diff --git a/src/renderer/App.js b/src/renderer/App.js
index 95c7aad0..2795d8c4 100644
--- a/src/renderer/App.js
+++ b/src/renderer/App.js
@@ -88,6 +88,7 @@ export default Vue.extend({
this.$store.dispatch('grabUserSettings')
this.$store.dispatch('grabHistory')
this.$store.dispatch('grabAllProfiles', this.$t('Profile.All Channels'))
+ this.$store.dispatch('grabAllPlaylists')
this.$store.commit('setUsingElectron', useElectron)
this.checkThemeSettings()
this.checkLocale()
diff --git a/src/renderer/components/ft-icon-button/ft-icon-button.sass b/src/renderer/components/ft-icon-button/ft-icon-button.sass
index 032d8a55..8099b01d 100644
--- a/src/renderer/components/ft-icon-button/ft-icon-button.sass
+++ b/src/renderer/components/ft-icon-button/ft-icon-button.sass
@@ -52,6 +52,9 @@
&:active
background-color: var(--accent-color-active)
+ &.favorite
+ color: var(--favorite-icon-color)
+
.iconDropdown
display: none
position: absolute
diff --git a/src/renderer/components/ft-list-video/ft-list-video.js b/src/renderer/components/ft-list-video/ft-list-video.js
index ecf8d5ac..50c4c2de 100644
--- a/src/renderer/components/ft-list-video/ft-list-video.js
+++ b/src/renderer/components/ft-list-video/ft-list-video.js
@@ -165,6 +165,22 @@ export default Vue.extend({
addWatchedStyle: function () {
return this.watched && !this.inHistory
+ },
+
+ favoritesPlaylist: function () {
+ return this.$store.getters.getFavorites
+ },
+
+ inFavoritesPlaylist: function () {
+ const index = this.favoritesPlaylist.videos.findIndex((video) => {
+ return video.videoId === this.id
+ })
+
+ return index !== -1
+ },
+
+ favoriteIconTheme: function () {
+ return this.inFavoritesPlaylist ? 'base favorite' : 'base'
}
},
mounted: function () {
@@ -173,10 +189,11 @@ export default Vue.extend({
},
methods: {
toggleSave: function () {
- console.log('TODO: ft-list-video method toggleSave')
- this.showToast({
- message: this.$t('Saving videos are currently not available. Please wait for a future update')
- })
+ if (this.inFavoritesPlaylist) {
+ this.removeFromPlaylist()
+ } else {
+ this.addToPlaylist()
+ }
},
handleOptionsClick: function (option) {
@@ -396,11 +413,54 @@ export default Vue.extend({
this.watched = false
},
+ addToPlaylist: function () {
+ const videoData = {
+ videoId: this.id,
+ title: this.title,
+ author: this.channelName,
+ authorId: this.channelId,
+ published: '',
+ description: this.description,
+ viewCount: this.viewCount,
+ lengthSeconds: this.data.lengthSeconds,
+ timeAdded: new Date().getTime(),
+ isLive: false,
+ paid: false,
+ type: 'video'
+ }
+
+ const payload = {
+ playlistName: 'Favorites',
+ videoData: videoData
+ }
+
+ this.addVideo(payload)
+
+ this.showToast({
+ message: this.$t('Video.Video has been saved')
+ })
+ },
+
+ removeFromPlaylist: function () {
+ const payload = {
+ playlistName: 'Favorites',
+ videoId: this.id
+ }
+
+ this.removeVideo(payload)
+
+ this.showToast({
+ message: this.$t('Video.Video has been removed from your saved list')
+ })
+ },
+
...mapActions([
'showToast',
'toLocalePublicationString',
'updateHistory',
- 'removeFromHistory'
+ 'removeFromHistory',
+ 'addVideo',
+ 'removeVideo'
])
}
})
diff --git a/src/renderer/components/ft-list-video/ft-list-video.vue b/src/renderer/components/ft-list-video/ft-list-video.vue
index abf66448..2a79d601 100644
--- a/src/renderer/components/ft-list-video/ft-list-video.vue
+++ b/src/renderer/components/ft-list-video/ft-list-video.vue
@@ -32,13 +32,13 @@
{
+ return video.videoId === this.id
+ })
+
+ return index !== -1
+ },
+
+ favoriteIconTheme: function () {
+ return this.inFavoritesPlaylist ? 'base favorite' : 'base'
+ },
+
downloadLinkNames: function () {
return this.downloadLinks.map((download) => {
return download.label
@@ -208,6 +228,14 @@ export default Vue.extend({
this.$router.push({ path: `/channel/${this.channelId}` })
},
+ toggleSave: function () {
+ if (this.inFavoritesPlaylist) {
+ this.removeFromPlaylist()
+ } else {
+ this.addToPlaylist()
+ }
+ },
+
handleSubscription: function () {
if (this.channelId === '') {
return
@@ -303,9 +331,48 @@ export default Vue.extend({
shell.openExternal(url)
},
+ addToPlaylist: function () {
+ const videoData = {
+ videoId: this.id,
+ title: this.title,
+ author: this.channelName,
+ authorId: this.channelId,
+ published: '',
+ description: this.description,
+ viewCount: this.viewCount,
+ lengthSeconds: this.lengthSeconds,
+ timeAdded: new Date().getTime(),
+ isLive: false,
+ paid: false,
+ type: 'video'
+ }
+
+ const payload = {
+ playlistName: 'Favorites',
+ videoData: videoData
+ }
+
+ this.addVideo(payload)
+
+ this.showToast({
+ message: this.$t('Video.Video has been marked as watched')
+ })
+ },
+
+ removeFromPlaylist: function () {
+ const payload = {
+ playlistName: 'Favorites',
+ videoId: this.id
+ }
+
+ this.removeVideo(payload)
+ },
+
...mapActions([
'showToast',
- 'updateProfile'
+ 'updateProfile',
+ 'addVideo',
+ 'removeVideo'
])
}
})
diff --git a/src/renderer/components/watch-video-info/watch-video-info.vue b/src/renderer/components/watch-video-info/watch-video-info.vue
index 05e7ec76..67c22a87 100644
--- a/src/renderer/components/watch-video-info/watch-video-info.vue
+++ b/src/renderer/components/watch-video-info/watch-video-info.vue
@@ -62,6 +62,14 @@
+
{
+ playlistDb.update({ playlistName: payload.playlistName }, { $push: { videos: payload.videoData } }, { upsert: true }, err => {
if (err) {
console.error(err)
} else {
@@ -81,12 +86,17 @@ const actions = {
}
})
},
- grabAllPlaylists({ commit }) {
- playlistDb.getAllData((err, payload) => {
+ grabAllPlaylists({ commit, dispatch }) {
+ playlistDb.find({}, (err, payload) => {
if (err) {
console.error(err)
} else {
- commit('setAllPlaylists', payload)
+ if (payload.length === 0) {
+ commit('setAllPlaylists', state.playlists)
+ dispatch('addPlaylists', payload)
+ } else {
+ commit('setAllPlaylists', payload)
+ }
}
})
},
@@ -99,12 +109,12 @@ const actions = {
}
})
},
- removeAllVideos ({ commit }, playlistId) {
- playlistDb.update({ _id: playlistId }, { $set: { videos: [] } }, { upsert: true }, err => {
+ removeAllVideos ({ commit }, playlistName) {
+ playlistDb.update({ playlistName: playlistName }, { $set: { videos: [] } }, { upsert: true }, err => {
if (err) {
console.error(err)
} else {
- commit('removeAllVideos', playlistId)
+ commit('removeAllVideos', playlistName)
}
})
},
@@ -127,7 +137,7 @@ const actions = {
})
},
removeVideo ({ commit }, payload) {
- playlistDb.update({ _id: payload.playlistId }, { $pull: { videos: payload.videoId } }, { upsert: true }, err => {
+ playlistDb.update({ playlistName: payload.playlistName }, { $pull: { videos: { videoId: payload.videoId } } }, { upsert: true }, (err, numRemoved) => {
if (err) {
console.error(err)
} else {
@@ -136,7 +146,7 @@ const actions = {
})
},
removeVideos ({ commit }, payload) {
- playlistDb.update({ _id: payload.playlistId }, { $pull: { videos: { $in: payload.videoIds } } }, { upsert: true }, err => {
+ playlistDb.update({ _id: payload.playlistName }, { $pull: { videos: { $in: payload.videoId } } }, { upsert: true }, err => {
if (err) {
console.error(err)
} else {
@@ -154,9 +164,9 @@ const mutations = {
state.playlists = state.playlists.concat(payload)
},
addVideo (state, payload) {
- const playlist = state.playlists.find(playlist => playlist._id === payload.playlistId)
+ const playlist = state.playlists.find(playlist => playlist.playlistName === payload.playlistName)
if (playlist) {
- playlist.videos.push(payload.videoId)
+ playlist.videos.push(payload.videoData)
}
},
addVideos (state, payload) {
@@ -168,22 +178,22 @@ const mutations = {
removeAllPlaylists (state) {
state.playlists = state.playlists.filter(playlist => playlist.protected !== true)
},
- removeAllVideos (state, playlistId) {
- const playlist = state.playlists.find(playlist => playlist._id === playlistId)
+ removeAllVideos (state, playlistName) {
+ const playlist = state.playlists.find(playlist => playlist.playlistName === playlistName)
if (playlist) {
playlist.videos = []
}
},
removeVideo (state, payload) {
- const playlist = state.playlists.find(playlist => playlist._id === payload.playlistId)
- if (playlist) {
- playlist.videos = playlist.videos.filter(video => video !== payload.videoId)
+ const playlist = state.playlists.findIndex(playlist => playlist.playlistName === payload.playlistName)
+ if (playlist !== -1) {
+ state.playlists[playlist].videos = state.playlists[playlist].videos.filter(video => video.videoId !== payload.videoId)
}
},
removeVideos (state, payload) {
- const playlist = state.playlists.find(playlist => playlist._id === payload.playlistId)
- if (playlist) {
- playlist.videos = playlist.videos.filter(video => payload.videoIds.indexOf(video) === -1)
+ const playlist = state.playlists.findIndex(playlist => playlist._id === payload.playlistId)
+ if (playlist !== -1) {
+ playlist.videos = playlist.videos.filter(video => payload.videoId.indexOf(video) === -1)
}
},
removePlaylist (state, playlistId) {
diff --git a/src/renderer/themes.css b/src/renderer/themes.css
index d2346125..787de982 100644
--- a/src/renderer/themes.css
+++ b/src/renderer/themes.css
@@ -8,6 +8,7 @@
--bg-color: #f1f1f1;
--link-color: var(--accent-color);
--link-visited-color: var(--accent-color-visited);
+ --favorite-icon-color: #FFD600;
--card-bg-color: #FFFFFF;
--secondary-card-bg-color: #eeeeee;
--scrollbar-color: #CCCCCC;
@@ -32,6 +33,7 @@
--bg-color: #212121;
--link-color: var(--accent-color);
--link-visited-color: var(--accent-color-visited);
+ --favorite-icon-color: #FFEA00;
--card-bg-color: #303030;
--secondary-card-bg-color: rgba(0, 0, 0, 0.75);
--scrollbar-color: #414141;
@@ -55,6 +57,7 @@
--bg-color: #000000;
--link-color: var(--accent-color);
--link-visited-color: var(--accent-color-visited);
+ --favorite-icon-color: #FFEA00;
--card-bg-color: #000000;
--secondary-card-bg-color: rgba(0, 0, 0, 0.75);
--scrollbar-color: #515151;
diff --git a/src/renderer/views/UserPlaylists/UserPlaylists.js b/src/renderer/views/UserPlaylists/UserPlaylists.js
index a216cfe4..8e6068cc 100644
--- a/src/renderer/views/UserPlaylists/UserPlaylists.js
+++ b/src/renderer/views/UserPlaylists/UserPlaylists.js
@@ -1,6 +1,8 @@
import Vue from 'vue'
import FtCard from '../../components/ft-card/ft-card.vue'
import FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'
+import FtTooltip from '../../components/ft-tooltip/ft-tooltip.vue'
+import FtLoader from '../../components/ft-loader/ft-loader.vue'
import FtElementList from '../../components/ft-element-list/ft-element-list.vue'
export default Vue.extend({
@@ -8,8 +10,48 @@ export default Vue.extend({
components: {
'ft-card': FtCard,
'ft-flex-box': FtFlexBox,
+ 'ft-tooltip': FtTooltip,
+ 'ft-loader': FtLoader,
'ft-element-list': FtElementList
},
+ data: function () {
+ return {
+ isLoading: false,
+ dataLimit: 100
+ }
+ },
+ computed: {
+ favoritesPlaylist: function () {
+ return this.$store.getters.getFavorites
+ },
+
+ activeData: function () {
+ if (this.favoritesPlaylist.videos.length < this.dataLimit) {
+ return this.favoritesPlaylist.videos
+ } else {
+ return this.favoritesPlaylist.videos.slice(0, this.dataLimit)
+ }
+ }
+ },
+ watch: {
+ activeData() {
+ this.isLoading = true
+ setTimeout(() => {
+ this.isLoading = false
+ }, 100)
+ }
+ },
mounted: function () {
+ const limit = sessionStorage.getItem('favoritesLimit')
+
+ if (limit !== null) {
+ this.dataLimit = limit
+ }
+ },
+ methods: {
+ increaseLimit: function () {
+ this.dataLimit += 100
+ sessionStorage.setItem('favoritesLimit', this.dataLimit)
+ }
}
})
diff --git a/src/renderer/views/UserPlaylists/UserPlaylists.vue b/src/renderer/views/UserPlaylists/UserPlaylists.vue
index 77fe35b1..6cae1139 100644
--- a/src/renderer/views/UserPlaylists/UserPlaylists.vue
+++ b/src/renderer/views/UserPlaylists/UserPlaylists.vue
@@ -1,12 +1,42 @@
-
- {{ $t("User Playlists.Your Playlists") }}
-
+
+
+
+ {{ $t("User Playlists.Your Playlists") }}
+
+
+
- {{ $t("This part of the app is not ready yet. Come back later when progress has been made.") }}
+ {{ $t("User Playlists['Your saved videos are empty. Click on the save button on the corner of a video to have it listed here']") }}
+
+
+
+
diff --git a/src/renderer/views/Watch/Watch.vue b/src/renderer/views/Watch/Watch.vue
index b2247a34..8202edde 100644
--- a/src/renderer/views/Watch/Watch.vue
+++ b/src/renderer/views/Watch/Watch.vue
@@ -81,6 +81,7 @@
:download-links="downloadLinks"
:watching-playlist="watchingPlaylist"
:theatre-possible="theatrePossible"
+ :length-seconds="videoLengthSeconds"
class="watchVideo"
:class="{ theatreWatchVideo: useTheatreMode }"
@theatre-mode="toggleTheatreMode"
diff --git a/static/locales/en-US.yaml b/static/locales/en-US.yaml
index ce61e623..14a916d3 100644
--- a/static/locales/en-US.yaml
+++ b/static/locales/en-US.yaml
@@ -86,6 +86,8 @@ Most Popular: Most Popular
Playlists: Playlists
User Playlists:
Your Playlists: Your Playlists
+ Playlist Message: This page is not reflective of fully working playlists. It only lists videos that you have saved or favorited. When the work has finished, all videos currently here will be migrated to a 'Favorites' playlist.
+ Your saved videos are empty. Click on the save button on the corner of a video to have it listed here: Your saved videos are empty. Click on the save button on the corner of a video to have it listed here
History:
# On History Page
History: History
@@ -368,6 +370,9 @@ Video:
Remove From History: Remove From History
Video has been marked as watched: Video has been marked as watched
Video has been removed from your history: Video has been removed from your history
+ Save Video: Save Video
+ Video has been saved: Video has been saved
+ Video has been removed from your saved list: Video has been removed from your saved list
Open in YouTube: Open in YouTube
Copy YouTube Link: Copy YouTube Link
Open YouTube Embedded Player: Open YouTube Embedded Player