Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const DBActions = {
UPSERT_VIDEOS: 'db-action-playlists-upsert-videos-by-playlist-name',
DELETE_VIDEO_ID: 'db-action-playlists-delete-video-by-playlist-name',
DELETE_VIDEO_IDS: 'db-action-playlists-delete-video-ids',
DELETE_ALL_VIDEOS: 'db-action-playlists-delete-all-videos'
DELETE_ALL_VIDEOS: 'db-action-playlists-delete-all-videos',
}
}

Expand All @@ -66,7 +66,7 @@ const SyncEvents = {

PLAYLISTS: {
UPSERT_VIDEO: 'sync-playlists-upsert-video',
DELETE_VIDEO: 'sync-playlists-delete-video'
DELETE_VIDEO: 'sync-playlists-delete-video',
}
}

Expand Down
22 changes: 16 additions & 6 deletions src/datastores/handlers/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,22 @@ class Playlists {
return db.playlists.removeAsync({ _id, protected: { $ne: true } })
}

static deleteVideoIdByPlaylistId(_id, playlistItemId) {
return db.playlists.updateAsync(
{ _id },
{ $pull: { videos: { playlistItemId } } },
{ upsert: true }
)
static deleteVideoIdByPlaylistId({ _id, videoId, playlistItemId }) {
if (playlistItemId != null) {
return db.playlists.updateAsync(
{ _id },
{ $pull: { videos: { playlistItemId } } },
{ upsert: true }
)
} else if (videoId != null) {
return db.playlists.updateAsync(
{ _id },
{ $pull: { videos: { videoId } } },
{ upsert: true }
)
} else {
throw new Error(`Both videoId & playlistItemId are absent, _id: ${_id}`)
}
}

static deleteVideoIdsByPlaylistId(_id, videoIds) {
Expand Down
4 changes: 2 additions & 2 deletions src/datastores/handlers/electron.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,12 @@ class Playlists {
)
}

static deleteVideoIdByPlaylistId(_id, playlistItemId) {
static deleteVideoIdByPlaylistId({ _id, videoId, playlistItemId }) {
return ipcRenderer.invoke(
IpcChannels.DB_PLAYLISTS,
{
action: DBActions.PLAYLISTS.DELETE_VIDEO_ID,
data: { _id, playlistItemId }
data: { _id, videoId, playlistItemId }
}
)
}
Expand Down
4 changes: 2 additions & 2 deletions src/datastores/handlers/web.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ class Playlists {
return baseHandlers.playlists.delete(_id)
}

static deleteVideoIdByPlaylistId(_id, playlistItemId) {
return baseHandlers.playlists.deleteVideoIdByPlaylistId(_id, playlistItemId)
static deleteVideoIdByPlaylistId({ _id, videoId, playlistItemId }) {
return baseHandlers.playlists.deleteVideoIdByPlaylistId({ _id, videoId, playlistItemId })
}

static deleteVideoIdsByPlaylistId(_id, videoIds) {
Expand Down
15 changes: 14 additions & 1 deletion src/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -995,14 +995,27 @@ function runApp() {
return null

case DBActions.PLAYLISTS.DELETE_VIDEO_ID:
await baseHandlers.playlists.deleteVideoIdByPlaylistId(data._id, data.playlistItemId)
await baseHandlers.playlists.deleteVideoIdByPlaylistId({
_id: data._id,
videoId: data.videoId,
playlistItemId: data.playlistItemId,
})
syncOtherWindows(
IpcChannels.SYNC_PLAYLISTS,
event,
{ event: SyncEvents.PLAYLISTS.DELETE_VIDEO, data }
)
return null

case DBActions.PLAYLISTS.SET_QUICK_SAVE_TARGET_PLAYLIST:
Comment thread
absidue marked this conversation as resolved.
Outdated
await baseHandlers.playlists.setPlaylistAsQuickBookmarkTarget(data)
syncOtherWindows(
IpcChannels.SYNC_PLAYLISTS,
event,
{ event: SyncEvents.PLAYLISTS.SET_QUICK_SAVE_TARGET_PLAYLIST, data }
)
return null

case DBActions.PLAYLISTS.DELETE_VIDEO_IDS:
await baseHandlers.playlists.deleteVideoIdsByPlaylistId(data._id, data.videoIds)
// TODO: Syncing (implement only when it starts being used)
Expand Down
72 changes: 72 additions & 0 deletions src/renderer/components/ft-list-video/ft-list-video.js
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,29 @@ export default defineComponent({
return this.playlistIdTypePairFinal?.playlistItemId
},

quickBookmarkPlaylistId() {
return this.$store.getters.getQuickBookmarkTargetPlaylistId
},
quickBookmarkPlaylist() {
return this.$store.getters.getPlaylist(this.quickBookmarkPlaylistId)
},
isQuickBookmarkEnabled() {
return this.quickBookmarkPlaylist != null
},
isInQuickBookmarkPlaylist: function () {
if (!this.isQuickBookmarkEnabled) { return false }

return this.quickBookmarkPlaylist.videos.some((video) => {
return video.videoId === this.id
})
},
quickBookmarkIconText: function () {
return this.isInQuickBookmarkPlaylist ? this.$t('User Playlists.Remove from Favorites') : this.$t('User Playlists.Add to Favorites')
Comment thread
kommunarr marked this conversation as resolved.
Outdated
},
quickBookmarkIconTheme: function () {
return this.isInQuickBookmarkPlaylist ? 'base favorite' : 'base'
},

watchPageLinkTo() {
// For `router-link` attribute `to`
return {
Expand Down Expand Up @@ -729,12 +752,61 @@ export default defineComponent({
showToast(this.$t('Channel Unhidden', { channel: channelName }))
},

toggleQuickBookmarked() {
if (!this.isQuickBookmarkEnabled) {
// This should be prevented by UI
return
}

if (this.isInQuickBookmarkPlaylist) {
this.removeFromQuickBookmarkPlaylist()
} else {
this.addToQuickBookmarkPlaylist()
}
},
addToQuickBookmarkPlaylist() {
const videoData = {
videoId: this.id,
title: this.title,
author: this.channelName,
authorId: this.channelId,
description: this.description,
viewCount: this.viewCount,
lengthSeconds: this.data.lengthSeconds,
}

this.addVideos({
_id: this.quickBookmarkPlaylist._id,
videos: [videoData],
})
// Update playlist's `lastUpdatedAt`
this.updatePlaylist({ _id: this.quickBookmarkPlaylist._id })

// TODO: Maybe show playlist name
showToast(this.$t('Video.Video has been saved'))
},
removeFromQuickBookmarkPlaylist() {
this.removeVideo({
_id: this.quickBookmarkPlaylist._id,
// Remove all playlist items with same videoId
videoId: this.id,
})
// Update playlist's `lastUpdatedAt`
this.updatePlaylist({ _id: this.quickBookmarkPlaylist._id })

// TODO: Maybe show playlist name
showToast(this.$t('Video.Video has been removed from your saved list'))
},

...mapActions([
'openInExternalPlayer',
'updateHistory',
'removeFromHistory',
'updateChannelsHidden',
'showAddToPlaylistPromptForManyVideos',
'addVideos',
'updatePlaylist',
'removeVideo',
])
}
})
14 changes: 14 additions & 0 deletions src/renderer/components/ft-list-video/ft-list-video.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@
:size="appearance === `watchPlaylistItem` ? 14 : 18"
@click="togglePlaylistPrompt"
/>
<ft-icon-button
v-if="isQuickBookmarkEnabled"
:title="quickBookmarkIconText"
:icon="['fas', 'star']"
class="quickBookmarkVideoIcon"
:class="{
bookmarked: isInQuickBookmarkPlaylist,
alwaysVisible: alwaysShowAddToPlaylistButton,
}"
:theme="quickBookmarkIconTheme"
:padding="appearance === `watchPlaylistItem` ? 5 : 6"
:size="appearance === `watchPlaylistItem` ? 14 : 18"
@click="toggleQuickBookmarked"
/>
<ft-icon-button
v-if="inUserPlaylist && canMoveVideoUp"
:title="$t('User Playlists.Move Video Up')"
Expand Down
35 changes: 35 additions & 0 deletions src/renderer/components/playlist-info/playlist-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import FtIconButton from '../ft-icon-button/ft-icon-button.vue'
import FtInput from '../ft-input/ft-input.vue'
import FtPrompt from '../ft-prompt/ft-prompt.vue'
import {
copyToClipboard,
Comment thread
kommunarr marked this conversation as resolved.
Outdated
showToast,
} from '../../helpers/utils'

Expand Down Expand Up @@ -194,6 +195,23 @@ export default defineComponent({
// Cannot delete protected playlist
return !this.hideSharingActions
},

quickBookmarkPlaylistId() {
return this.$store.getters.getQuickBookmarkTargetPlaylistId
},
quickBookmarkPlaylist() {
return this.$store.getters.getPlaylist(this.quickBookmarkPlaylistId)
},
quickBookmarkEnabled() {
return this.quickBookmarkPlaylist != null
},
markedAsQuickBookmarkTarget() {
// Only user playlists can be target
if (this.selectedUserPlaylist == null) { return false }
if (this.quickBookmarkPlaylist == null) { return false }

return this.quickBookmarkPlaylist._id === this.selectedUserPlaylist._id
},
},
watch: {
showDeletePlaylistPrompt(shown) {
Expand Down Expand Up @@ -318,10 +336,27 @@ export default defineComponent({
this.showDeletePlaylistPrompt = false
},

enableQuickBookmarkForThisPlaylist() {
if (this.quickBookmarkEnabled) {
showToast(this.$t('User Playlists.SinglePlaylistView.Toast["Another playlist is already used for quick bookmark. Click here to use this playlist anyway"]'), 5000, () => {
Comment thread
kommunarr marked this conversation as resolved.
Outdated
this.updateQuickBookmarkTargetPlaylistId(this.id)
})
return
}

this.updateQuickBookmarkTargetPlaylistId(this.id)
showToast(this.$t('User Playlists.SinglePlaylistView.Toast.This playlist is now used for quick bookmark'))
},
disableQuickBookmark() {
this.updateQuickBookmarkTargetPlaylistId(null)
showToast(this.$t('User Playlists.SinglePlaylistView.Toast.Quick bookmark disabled'))
},

...mapActions([
'showAddToPlaylistPromptForManyVideos',
'updatePlaylist',
'removePlaylist',
'updateQuickBookmarkTargetPlaylistId',
]),
},
})
14 changes: 14 additions & 0 deletions src/renderer/components/playlist-info/playlist-info.vue
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,20 @@
theme="secondary"
@click="toggleCopyVideosPrompt"
/>
<ft-icon-button
v-if="!editMode && !markedAsQuickBookmarkTarget"
:title="$t('User Playlists.Enable Quick Bookmark With This Playlist')"
:icon="['fas', 'link']"
theme="secondary"
@click="enableQuickBookmarkForThisPlaylist"
/>
<ft-icon-button
v-if="!editMode && markedAsQuickBookmarkTarget"
:title="$t('User Playlists.Disable Quick Bookmark')"
:icon="['fas', 'link-slash']"
theme="secondary"
@click="disableQuickBookmark"
/>
<ft-icon-button
v-if="!editMode && infoSource === 'user' && videoCount > 0"
:title="$t('User Playlists.Remove Watched Videos')"
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/components/privacy-settings/privacy-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export default defineComponent({
if (option !== 'yes') { return }

this.removeAllPlaylists()
this.updateQuickBookmarkTargetPlaylistId('favorites')
showToast(this.$t('Settings.Privacy Settings.All playlists have been removed'))
},

Expand All @@ -137,6 +138,7 @@ export default defineComponent({
'updateAllSubscriptionsList',
'updateProfileSubscriptions',
'removeAllPlaylists',
'updateQuickBookmarkTargetPlaylistId',
])
}
})
Loading