diff --git a/src/renderer/App.js b/src/renderer/App.js
index 7d98ff1aa3859..b480b92d04a11 100644
--- a/src/renderer/App.js
+++ b/src/renderer/App.js
@@ -9,6 +9,8 @@ import FtPrompt from './components/ft-prompt/ft-prompt.vue'
import FtButton from './components/ft-button/ft-button.vue'
import FtToast from './components/ft-toast/ft-toast.vue'
import FtProgressBar from './components/ft-progress-bar/ft-progress-bar.vue'
+import FtPlaylistAddVideoPrompt from './components/ft-playlist-add-video-prompt/ft-playlist-add-video-prompt.vue'
+import FtCreatePlaylistPrompt from './components/ft-create-playlist-prompt/ft-create-playlist-prompt.vue'
import { marked } from 'marked'
import { IpcChannels } from '../constants'
import packageDetails from '../../package.json'
@@ -28,7 +30,9 @@ export default defineComponent({
FtPrompt,
FtButton,
FtToast,
- FtProgressBar
+ FtProgressBar,
+ FtPlaylistAddVideoPrompt,
+ FtCreatePlaylistPrompt,
},
data: function () {
return {
@@ -63,6 +67,12 @@ export default defineComponent({
checkForBlogPosts: function () {
return this.$store.getters.getCheckForBlogPosts
},
+ showAddToPlaylistPrompt: function () {
+ return this.$store.getters.getShowAddToPlaylistPrompt
+ },
+ showCreatePlaylistPrompt: function () {
+ return this.$store.getters.getShowCreatePlaylistPrompt
+ },
windowTitle: function () {
const routeTitle = this.$route.meta.title
if (routeTitle !== 'Channel' && routeTitle !== 'Watch' && routeTitle !== 'Hashtag') {
diff --git a/src/renderer/App.vue b/src/renderer/App.vue
index b4d7faa4ef45d..2e7ae23b9340c 100644
--- a/src/renderer/App.vue
+++ b/src/renderer/App.vue
@@ -74,6 +74,12 @@
:option-values="externalLinkOpeningPromptValues"
@click="handleExternalLinkOpeningPromptAnswer"
/>
+
+
.
+*/
+
+/*
+* Credit goes to pavelvaravko for making this css.
+* https://codepen.io/pavelvaravko/pen/qjojOr
+*/
+
+/* select starting stylings ------------------------------*/
+.center {
+ text-align: center;
+}
+
+.playlistNameInput {
+ width: 80%;
+ max-width: 600px;
+}
diff --git a/src/renderer/components/ft-create-playlist-prompt/ft-create-playlist-prompt.js b/src/renderer/components/ft-create-playlist-prompt/ft-create-playlist-prompt.js
new file mode 100644
index 0000000000000..a35c622c0483c
--- /dev/null
+++ b/src/renderer/components/ft-create-playlist-prompt/ft-create-playlist-prompt.js
@@ -0,0 +1,93 @@
+import Vue from 'vue'
+import { mapActions } from 'vuex'
+import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
+import FtPrompt from '../ft-prompt/ft-prompt.vue'
+import FtButton from '../ft-button/ft-button.vue'
+import FtInput from '../ft-input/ft-input.vue'
+import FtPlaylistSelector from '../ft-playlist-selector/ft-playlist-selector.vue'
+
+export default Vue.extend({
+ name: 'FtCreatePlaylistPrompt',
+ components: {
+ FtFlexBox,
+ FtPrompt,
+ FtButton,
+ FtInput,
+ FtPlaylistSelector
+ },
+ data: function () {
+ return {
+ playlistName: '',
+ playlistAddVideoPromptValues: [
+ 'save',
+ 'cancel'
+ ],
+ selectedPlaylists: []
+ }
+ },
+ computed: {
+ allPlaylists: function () {
+ return this.$store.getters.getAllPlaylists
+ },
+ newPlaylistVideoObject: function () {
+ return this.$store.getters.getNewPlaylistVideoObject
+ },
+ videoImportLength: function () {
+ return this.newPlaylistVideoObject.videos.length
+ }
+ },
+ mounted: function () {
+ this.playlistName = this.newPlaylistVideoObject.title
+ },
+ methods: {
+ handleCreatePlaylistPrompt: function (option) {
+ this.hideCreatePlaylistPrompt()
+ },
+
+ createNewPlaylist: function () {
+ const videosObject = this.videoImportLength > 0 ? this.newPlaylistVideoObject.videos : []
+
+ const playlistObject = {
+ playlistName: this.playlistName,
+ protected: false,
+ removeOnWatched: false,
+ description: '',
+ videos: videosObject
+ }
+
+ const nameExists = this.allPlaylists.findIndex((playlist) => {
+ return playlist.playlistName.toLowerCase() === this.playlistName.toLowerCase()
+ })
+
+ if (this.playlistName === '') {
+ this.showToast({
+ message: 'Playlist name cannot be empty. Please input a name.'
+ })
+ } else if (nameExists !== -1) {
+ this.showToast({
+ message: 'There is already a playlist with this name. Please pick a different name.'
+ })
+ } else {
+ try {
+ this.addPlaylist(playlistObject)
+ this.showToast({
+ message: `Playlist ${this.playlistName} has been successfully created.`
+ })
+ } catch (e) {
+ this.showToast({
+ message: 'There was an issue with creating the playlist.'
+ })
+ console.error(e)
+ } finally {
+ this.hideCreatePlaylistPrompt()
+ }
+ }
+ },
+
+ ...mapActions([
+ 'showToast',
+ 'addPlaylist',
+ 'hideCreatePlaylistPrompt'
+ ])
+ }
+})
diff --git a/src/renderer/components/ft-create-playlist-prompt/ft-create-playlist-prompt.vue b/src/renderer/components/ft-create-playlist-prompt/ft-create-playlist-prompt.vue
new file mode 100644
index 0000000000000..7e859b6b8810e
--- /dev/null
+++ b/src/renderer/components/ft-create-playlist-prompt/ft-create-playlist-prompt.vue
@@ -0,0 +1,39 @@
+
+
+
+ New Playlist Name
+
+
+ playlistName = input"
+ @click="createNewPlaylist"
+ />
+
+
+ {{ videoImportLength }} video(s) will also be imported when created
+
+
+
+
+
+
+
+
+
+
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 7b0cd23873070..1f9c5a9645624 100644
--- a/src/renderer/components/ft-list-video/ft-list-video.js
+++ b/src/renderer/components/ft-list-video/ft-list-video.js
@@ -25,6 +25,10 @@ export default defineComponent({
type: String,
default: null
},
+ playlistType: {
+ type: String,
+ default: null
+ },
playlistIndex: {
type: Number,
default: null
@@ -101,6 +105,10 @@ export default defineComponent({
return this.$route.name === 'history'
},
+ inUserPlaylist: function () {
+ return this.$router.currentRoute.path.includes('playlist') && this.playlistType === 'user'
+ },
+
invidiousUrl: function () {
let videoUrl = `${this.currentInvidiousInstance}/watch?v=${this.id}`
// `playlistId` can be undefined
@@ -590,6 +598,26 @@ export default defineComponent({
this.removeVideo(payload)
},
+ removeVideoFromPlaylist: function () {
+ const payload = {
+ _id: this.playlistId,
+ videoId: this.id
+ }
+
+ try {
+ this.removeVideo(payload)
+ this.$emit('refresh-playlist')
+ this.showToast({
+ message: 'Video has been removed'
+ })
+ } catch (e) {
+ this.showToast({
+ message: 'There was a problem with removing this video'
+ })
+ console.error(e)
+ }
+ },
+
togglePlaylistPrompt: function () {
const videoData = {
videoId: this.id,
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 281d7da04204c..7352e77febd3b 100644
--- a/src/renderer/components/ft-list-video/ft-list-video.vue
+++ b/src/renderer/components/ft-list-video/ft-list-video.vue
@@ -63,6 +63,33 @@
:size="appearance === `watchPlaylistItem` ? 14 : 18"
@click="togglePlaylistPrompt"
/>
+
+
+
{
+ playlist.title = playlist.playlistName
+ playlist.type = 'playlist'
+ playlist.thumbnail = ''
+ playlist.channelName = ''
+ playlist.channelId = ''
+ playlist.playlistId = ''
+ playlist.videoCount = playlist.videos.length
+ return playlist
+ }).sort((a, b) => {
+ // Sort by favorites, watch later, then alphabetically
+ if (a._id === 'favorites') {
+ return -1
+ } else if (b._id === 'favorites') {
+ return 1
+ } else if (a._id === 'watchLater') {
+ return -1
+ } else if (b._id === 'watchLater') {
+ return 1
+ }
+
+ return a.title.localeCompare(b.title, this.locale)
+ })
},
selectedPlaylistsCount: function () {
return this.selectedPlaylists.length
@@ -47,7 +70,6 @@ export default Vue.extend({
},
methods: {
handleAddToPlaylistPrompt: function (option) {
- console.log(option)
this.hideAddToPlaylistPrompt()
},
@@ -77,12 +99,24 @@ export default Vue.extend({
addedPlaylists++
}
})
+
+ this.showToast({
+ message: `Video has been added to ${addedPlaylists} playlist(s).`
+ })
this.handleAddToPlaylistPrompt(null)
},
+ createNewPlaylist: function () {
+ this.showCreatePlaylistPrompt({
+ title: '',
+ videos: []
+ })
+ },
+
...mapActions([
'addVideo',
- 'hideAddToPlaylistPrompt'
+ 'hideAddToPlaylistPrompt',
+ 'showCreatePlaylistPrompt',
])
}
})
diff --git a/src/renderer/components/ft-playlist-add-video-prompt/ft-playlist-add-video-prompt.vue b/src/renderer/components/ft-playlist-add-video-prompt/ft-playlist-add-video-prompt.vue
index 3cd2b8199977f..858b435852bf4 100644
--- a/src/renderer/components/ft-playlist-add-video-prompt/ft-playlist-add-video-prompt.vue
+++ b/src/renderer/components/ft-playlist-add-video-prompt/ft-playlist-add-video-prompt.vue
@@ -22,6 +22,10 @@
label="Save"
@click="addSelectedToPlaylists"
/>
+
playlist._id === this.id)
},
+ deletePlaylistPromptNames: function () {
+ return [
+ this.$t('Yes'),
+ this.$t('No')
+ ]
+ },
+
thumbnail: function () {
switch (this.thumbnailPreference) {
case 'start':
@@ -107,25 +130,15 @@ export default defineComponent({
mounted: function () {
this.newTitle = this.title
this.newDescription = this.description
-
- // Causes errors if not put inside of a check
- // if (
- // typeof this.data.viewCount !== 'undefined' &&
- // !isNaN(this.data.viewCount)
- // ) {
- // this.viewCount = this.hideViews ? null : formatNumber(this.data.viewCount)
- // }
- //
- // if (
- // typeof this.data.videoCount !== 'undefined' &&
- // !isNaN(this.data.videoCount)
- // ) {
- // this.videoCount = formatNumber(this.data.videoCount)
- // }
- //
- // this.lastUpdated = this.data.lastUpdated
},
methods: {
+ copyPlaylist: function () {
+ this.showCreatePlaylistPrompt({
+ title: this.title,
+ videos: this.videos
+ })
+ },
+
savePlaylistInfo: function () {
const playlist = {
playlistName: this.newTitle,
@@ -135,8 +148,19 @@ export default defineComponent({
videos: this.selectedPlaylist.videos,
_id: this.id,
}
- this.updatePlaylist(playlist)
- this.exitEditMode()
+ try {
+ this.updatePlaylist(playlist)
+ this.showToast({
+ message: 'Playlist has been updated.'
+ })
+ } catch (e) {
+ this.showToast({
+ message: 'There was an issue with updating this playlist.'
+ })
+ console.error(e)
+ } finally {
+ this.exitEditMode()
+ }
},
enterEditMode: function () {
@@ -149,6 +173,73 @@ export default defineComponent({
this.newTitle = this.title
},
- ...mapActions(['updatePlaylist']),
+ handleRemoveVideosOnWatchPromptAnswer: function (option) {
+ console.log(this.selectedPlaylist.videos)
+ if (option === 'yes') {
+ const videosToWatch = this.selectedPlaylist.videos.filter((video) => {
+ const watchedIndex = this.historyCache.findIndex((history) => {
+ return history.videoId === video.videoId
+ })
+
+ return watchedIndex === -1
+ })
+
+ const videosRemoved = this.selectedPlaylist.videos.length - videosToWatch.length
+
+ if (videosRemoved === 0) {
+ this.showToast({
+ message: 'There were no videos to remove.'
+ })
+ this.showRemoveVideosOnWatchPrompt = false
+ return
+ }
+
+ const playlist = {
+ playlistName: this.title,
+ protected: this.selectedPlaylist.protected,
+ removeOnWatched: this.selectedPlaylist.removeOnWatched,
+ description: this.description,
+ videos: videosToWatch,
+ _id: this.id
+ }
+ try {
+ this.updatePlaylist(playlist)
+ this.showToast({
+ message: `${videosRemoved} video(s) have been removed.`
+ })
+ } catch (e) {
+ this.showToast({
+ message: 'There was an issue with updating this playlist.'
+ })
+ console.error(e)
+ }
+ }
+ this.showRemoveVideosOnWatchPrompt = false
+ },
+
+ handleDeletePlaylistPromptAnswer: function (option) {
+ if (this.selectedPlaylist.protected) {
+ this.showToast({
+ message: 'This playlist is protected and cannot be removed.'
+ })
+ } else if (option === 'yes') {
+ this.removePlaylist(this.id)
+ this.$router.push(
+ {
+ path: '/userPlaylists'
+ }
+ )
+ this.showToast({
+ message: `${this.title} has been deleted.`
+ })
+ }
+ this.showDeletePlaylistPrompt = false
+ },
+
+ ...mapActions([
+ 'showCreatePlaylistPrompt',
+ 'updatePlaylist',
+ 'removePlaylist',
+ ]),
},
})
diff --git a/src/renderer/components/playlist-info/playlist-info.vue b/src/renderer/components/playlist-info/playlist-info.vue
index 6f9a5b455a3ab..db9403fb51627 100644
--- a/src/renderer/components/playlist-info/playlist-info.vue
+++ b/src/renderer/components/playlist-info/playlist-info.vue
@@ -103,16 +103,12 @@
-
-
-
-
-
-
-
-
-
-
+
@@ -140,6 +138,20 @@
:dropdown-position-y="description ? 'top' : 'bottom'"
share-target-type="Playlist"
/>
+
+
diff --git a/src/renderer/scss-partials/_ft-list-item.scss b/src/renderer/scss-partials/_ft-list-item.scss
index 03da664f69d71..633b2eac489d7 100644
--- a/src/renderer/scss-partials/_ft-list-item.scss
+++ b/src/renderer/scss-partials/_ft-list-item.scss
@@ -161,6 +161,28 @@ $watched-transition-duration: 0.5s;
opacity: $thumbnail-overlay-opacity;
}
+ .trashIcon {
+ position: absolute;
+ top: 75px;
+ right: 3px;
+ font-size: 17px;
+ opacity: $thumbnail-overlay-opacity;
+ }
+ .upArrowIcon {
+ position: absolute;
+ bottom: 40px;
+ left: 3px;
+ font-size: 17px;
+ opacity: $thumbnail-overlay-opacity;
+ }
+ .downArrowIcon {
+ position: absolute;
+ bottom: 3px;
+ left: 3px;
+ font-size: 17px;
+ opacity: $thumbnail-overlay-opacity;
+ }
+
.watchedProgressBar {
align-self: flex-end;
background-color: var(--primary-color);
diff --git a/src/renderer/store/modules/playlists.js b/src/renderer/store/modules/playlists.js
index d892ae568deeb..3aee9f97574e5 100644
--- a/src/renderer/store/modules/playlists.js
+++ b/src/renderer/store/modules/playlists.js
@@ -24,9 +24,9 @@ const state = {
const getters = {
getAllPlaylists: () => state.playlists,
- getFavorites: () => state.playlists[0],
+ getFavorites: () => state.playlists.find(playlist => playlist._id === 'favorites'),
getPlaylist: (playlistId) => state.playlists.find(playlist => playlist._id === playlistId),
- getWatchLater: () => state.playlists[1]
+ getWatchLater: () => state.playlists.find(playlist => playlist._id === 'watchLater')
}
const actions = {
diff --git a/src/renderer/store/modules/utils.js b/src/renderer/store/modules/utils.js
index 7fef82828ca4c..fedb580ecb314 100644
--- a/src/renderer/store/modules/utils.js
+++ b/src/renderer/store/modules/utils.js
@@ -29,8 +29,10 @@ const state = {
cachedPlaylist: null,
showProgressBar: false,
showAddToPlaylistPrompt: false,
+ showCreatePlaylistPrompt: false,
progressBarPercentage: 0,
playlistAddVideoObject: [],
+ newPlaylistVideoObject: [],
regionNames: [],
regionValues: [],
recentBlogPosts: [],
@@ -79,10 +81,18 @@ const getters = {
return state.showAddToPlaylistPrompt
},
+ getShowCreatePlaylistPrompt () {
+ return state.showCreatePlaylistPrompt
+ },
+
getPlaylistAddVideoObject () {
return state.playlistAddVideoObject
},
+ getNewPlaylistVideoObject () {
+ return state.newPlaylistVideoObject
+ },
+
getShowProgressBar () {
return state.showProgressBar
},
@@ -255,6 +265,15 @@ const actions = {
commit('setShowAddToPlaylistPrompt', false)
},
+ showCreatePlaylistPrompt ({ commit }, videoArray) {
+ commit('setShowCreatePlaylistPrompt', true)
+ commit('setNewPlaylistVideoObject', videoArray)
+ },
+
+ hideCreatePlaylistPrompt ({ commit }) {
+ commit('setShowCreatePlaylistPrompt', false)
+ },
+
updateShowProgressBar ({ commit }, value) {
commit('setShowProgressBar', value)
},
@@ -653,10 +672,18 @@ const mutations = {
state.showAddToPlaylistPrompt = payload
},
+ setShowCreatePlaylistPrompt (state, payload) {
+ state.showCreatePlaylistPrompt = payload
+ },
+
setPlaylistAddVideoObject (state, payload) {
state.playlistAddVideoObject = payload
},
+ setNewPlaylistVideoObject (state, payload) {
+ state.newPlaylistVideoObject = payload
+ },
+
setPopularCache (state, value) {
state.popularCache = value
},
diff --git a/src/renderer/views/Playlist/Playlist.css b/src/renderer/views/Playlist/Playlist.css
index 7b2414b74014a..a3e82f26d0fd8 100644
--- a/src/renderer/views/Playlist/Playlist.css
+++ b/src/renderer/views/Playlist/Playlist.css
@@ -57,6 +57,7 @@
box-sizing: border-box;
position: relative;
top: 0;
+ z-index: 1;
height: auto;
width: 100%;
}
diff --git a/src/renderer/views/Playlist/Playlist.js b/src/renderer/views/Playlist/Playlist.js
index f4d5312968b4b..b7e9133314677 100644
--- a/src/renderer/views/Playlist/Playlist.js
+++ b/src/renderer/views/Playlist/Playlist.js
@@ -7,7 +7,7 @@ import FtListVideoLazy from '../../components/ft-list-video-lazy/ft-list-video-l
import FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'
import FtButton from '../../components/ft-button/ft-button.vue'
import { getLocalPlaylist, parseLocalPlaylistVideo } from '../../helpers/api/local'
-import { extractNumberFromString } from '../../helpers/utils'
+import { extractNumberFromString, showToast } from '../../helpers/utils'
import { invidiousGetPlaylistInfo, youtubeImageUrlToInvidious } from '../../helpers/api/invidious'
export default defineComponent({
@@ -71,6 +71,13 @@ export default defineComponent({
selectedPlaylist: function () {
return this.userPlaylists.find(playlist => playlist._id === this.playlistId)
},
+ selectedVideos: function () {
+ if (typeof (this.selectedPlaylist) !== 'undefined') {
+ return this.selectedPlaylist.videos
+ } else {
+ return []
+ }
+ },
},
watch: {
$route () {
@@ -78,7 +85,18 @@ export default defineComponent({
this.getPlaylistInfo()
},
selectedPlaylist () {
- this.getPlaylistInfo()
+ if (this.isLoading) {
+ // Ignores first time load of page
+ return
+ }
+ this.refreshPage()
+ },
+ selectedVideos () {
+ if (this.isLoading) {
+ // Ignores first time load of page
+ return
+ }
+ this.refreshPage()
},
},
mounted: function () {
@@ -170,9 +188,9 @@ export default defineComponent({
infoSource: 'invidious'
}
- this.id = result.playlistId
- this.title = result.title
- this.description = result.description
+ this.playlistId = result.playlistId
+ this.playlistTitle = result.title
+ this.playlistDescription = result.description
this.firstVideoId = result.videos[0].videoId
this.viewCount = result.viewCount
this.videoCount = result.videoCount
@@ -256,8 +274,99 @@ export default defineComponent({
})
},
+ moveVideoUp: function (videoId) {
+ const playlistItems = [].concat(this.playlistItems)
+ const videoIndex = playlistItems.findIndex((video) => {
+ return video.videoId === videoId
+ })
+
+ if (videoIndex === 0) {
+ showToast({
+ message: 'This video cannot be moved up.'
+ })
+ return
+ }
+
+ const videoObject = playlistItems[videoIndex]
+
+ playlistItems.splice(videoIndex, 1)
+ playlistItems.splice(videoIndex - 1, 0, videoObject)
+
+ const playlist = {
+ playlistName: this.playlistTitle,
+ protected: this.selectedPlaylist.protected,
+ removeOnWatched: this.selectedPlaylist.removeOnWatched,
+ description: this.playlistDescription,
+ videos: playlistItems,
+ _id: this.playlistId
+ }
+ try {
+ this.updatePlaylist(playlist)
+ this.playlistItems = playlistItems
+ } catch (e) {
+ showToast({
+ message: 'There was an issue with updating this playlist.'
+ })
+ console.error(e)
+ }
+ },
+
+ moveVideoDown: function (videoId) {
+ const playlistItems = [].concat(this.playlistItems)
+ const videoIndex = playlistItems.findIndex((video) => {
+ return video.videoId === videoId
+ })
+
+ if (videoIndex + 1 === playlistItems.length || videoIndex + 1 > playlistItems.length) {
+ showToast({
+ message: 'This video cannot be moved down.'
+ })
+ return
+ }
+
+ const videoObject = playlistItems[videoIndex]
+
+ playlistItems.splice(videoIndex, 1)
+ playlistItems.splice(videoIndex + 1, 0, videoObject)
+
+ const playlist = {
+ playlistName: this.playlistTitle,
+ protected: this.selectedPlaylist.protected,
+ removeOnWatched: this.selectedPlaylist.removeOnWatched,
+ description: this.playlistDescription,
+ videos: playlistItems,
+ _id: this.playlistId
+ }
+ try {
+ this.updatePlaylist(playlist)
+ this.playlistItems = playlistItems
+ } catch (e) {
+ showToast({
+ message: 'There was an issue with updating this playlist.'
+ })
+ console.error(e)
+ }
+ },
+
+ refreshPage: function () {
+ this.getPlaylistInfo()
+ // The list of videos within a playlist do not refresh properly if a video
+ // is removed, so the timeout forces the view to refresh. This is kinda hacky
+ // and has to do with a quirk of Vue. I don't really like this solution but this
+ // was the only way I could get it to update properly
+ const yOffset = window.scrollY
+ this.isLoading = true
+ window.setTimeout(() => {
+ this.isLoading = false
+ window.setTimeout(() => {
+ window.scrollTo(0, yOffset)
+ }, 100)
+ }, 100)
+ },
+
...mapActions([
- 'updateSubscriptionDetails'
+ 'updateSubscriptionDetails',
+ 'updatePlaylist',
]),
...mapMutations([
diff --git a/src/renderer/views/Playlist/Playlist.vue b/src/renderer/views/Playlist/Playlist.vue
index db1abb3ae4aaf..cb8853ad5ff0c 100644
--- a/src/renderer/views/Playlist/Playlist.vue
+++ b/src/renderer/views/Playlist/Playlist.vue
@@ -16,6 +16,7 @@
:last-updated="lastUpdated"
:description="playlistDescription"
:video-count="videoCount"
+ :videos="playlistItems"
:view-count="viewCount"
:info-source="infoSource"
class="playlistInfo"
@@ -41,9 +42,12 @@
{
+ // Sort by favorites, watch later, then alphabetically
+ if (a._id === 'favorites') {
+ return -1
+ } else if (b._id === 'favorites') {
+ return 1
+ } else if (a._id === 'watchLater') {
+ return -1
+ } else if (b._id === 'watchLater') {
+ return 1
+ }
+
+ return a.title.localeCompare(b.title, this.locale)
})
},
@@ -126,5 +146,16 @@ export default defineComponent({
// this.activeData = filteredQuery.length < this.searchDataLimit ? filteredQuery : filteredQuery.slice(0, this.searchDataLimit)
// }
},
+
+ createNewPlaylist: function () {
+ this.showCreatePlaylistPrompt({
+ title: '',
+ videos: []
+ })
+ },
+
+ ...mapActions([
+ 'showCreatePlaylistPrompt'
+ ])
}
})
diff --git a/src/renderer/views/UserPlaylists/UserPlaylists.vue b/src/renderer/views/UserPlaylists/UserPlaylists.vue
index d2f8660a2491c..8cfbedf1a48a5 100644
--- a/src/renderer/views/UserPlaylists/UserPlaylists.vue
+++ b/src/renderer/views/UserPlaylists/UserPlaylists.vue
@@ -11,6 +11,13 @@
{{ $t("User Playlists.Your Playlists") }}
+