From d18061242593d74bbe02a4c979ac4d5700f331b7 Mon Sep 17 00:00:00 2001 From: GLEBR1K <28905234+GLEBR1K@users.noreply.github.com> Date: Sun, 29 Dec 2024 00:34:48 +0000 Subject: [PATCH] [Feature] Playlist: Sort videos by published date (#6280) * include `published` info for playlisted videos * playlist: sort videos by published date * playlist: fix published date formatting for upcoming videos * playlist: add `premiereDate` to the metadata --- .../components/ft-list-video/ft-list-video.js | 6 ++++++ .../components/watch-video-info/watch-video-info.js | 8 ++++++++ src/renderer/helpers/playlists.js | 11 +++++++++++ src/renderer/helpers/utils.js | 2 ++ src/renderer/views/Playlist/Playlist.js | 4 ++++ src/renderer/views/Watch/Watch.js | 4 ++++ src/renderer/views/Watch/Watch.vue | 1 + static/locales/en-US.yaml | 2 ++ 8 files changed, 38 insertions(+) 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 9a3213e9a5018..3bcfd3689bc3d 100644 --- a/src/renderer/components/ft-list-video/ft-list-video.js +++ b/src/renderer/components/ft-list-video/ft-list-video.js @@ -775,6 +775,9 @@ export default defineComponent({ description: this.description, viewCount: this.viewCount, lengthSeconds: this.data.lengthSeconds, + published: this.published, + premiereDate: this.data.premiereDate, + premiereTimestamp: this.data.premiereTimestamp, } this.showAddToPlaylistPromptForManyVideos({ videos: [videoData] }) @@ -824,6 +827,9 @@ export default defineComponent({ author: this.channelName, authorId: this.channelId, lengthSeconds: this.data.lengthSeconds, + published: this.published, + premiereDate: this.data.premiereDate, + premiereTimestamp: this.data.premiereTimestamp, } this.addVideo({ diff --git a/src/renderer/components/watch-video-info/watch-video-info.js b/src/renderer/components/watch-video-info/watch-video-info.js index 1076ef9be94dd..71cdf1346d26a 100644 --- a/src/renderer/components/watch-video-info/watch-video-info.js +++ b/src/renderer/components/watch-video-info/watch-video-info.js @@ -39,6 +39,10 @@ export default defineComponent({ type: Number, required: true }, + premiereDate: { + type: Date, + default: undefined + }, viewCount: { type: Number, required: true @@ -348,6 +352,8 @@ export default defineComponent({ description: this.description, viewCount: this.viewCount, lengthSeconds: this.lengthSeconds, + published: this.published, + premiereDate: this.premiereDate, } this.showAddToPlaylistPromptForManyVideos({ videos: [videoData] }) @@ -372,6 +378,8 @@ export default defineComponent({ author: this.channelName, authorId: this.channelId, lengthSeconds: this.lengthSeconds, + published: this.published, + premiereDate: this.premiereDate, } this.addVideo({ diff --git a/src/renderer/helpers/playlists.js b/src/renderer/helpers/playlists.js index 6d8e2ed565bd4..ac81d9d37347b 100644 --- a/src/renderer/helpers/playlists.js +++ b/src/renderer/helpers/playlists.js @@ -1,6 +1,8 @@ export const SORT_BY_VALUES = { DateAddedNewest: 'date_added_descending', DateAddedOldest: 'date_added_ascending', + PublishedNewest: 'published_descending', + PublishedOldest: 'published_ascending', AuthorAscending: 'author_ascending', AuthorDescending: 'author_descending', VideoTitleAscending: 'video_title_ascending', @@ -48,12 +50,21 @@ export function videoDurationWithFallback(video) { return 0 } +function publishedWithFallback(video) { + const published = video.published + return typeof published === 'number' && !isNaN(published) && published !== 0 ? published : 0 +} + function compareTwoPlaylistItems(a, b, sortOrder, collator) { switch (sortOrder) { case SORT_BY_VALUES.DateAddedNewest: return b.timeAdded - a.timeAdded case SORT_BY_VALUES.DateAddedOldest: return a.timeAdded - b.timeAdded + case SORT_BY_VALUES.PublishedNewest: + return publishedWithFallback(b) - publishedWithFallback(a) + case SORT_BY_VALUES.PublishedOldest: + return publishedWithFallback(a) - publishedWithFallback(b) case SORT_BY_VALUES.VideoTitleAscending: return collator.compare(a.title, b.title) case SORT_BY_VALUES.VideoTitleDescending: diff --git a/src/renderer/helpers/utils.js b/src/renderer/helpers/utils.js index 4086c3d083977..212f53fd3f5ed 100644 --- a/src/renderer/helpers/utils.js +++ b/src/renderer/helpers/utils.js @@ -30,6 +30,7 @@ export function getIconForSortPreference(sortPreference) { case 'latest_created_first': case 'latest_played_first': case 'date_added_descending': + case 'published_descending': case 'last': case 'newest': case 'popular': @@ -40,6 +41,7 @@ export function getIconForSortPreference(sortPreference) { case 'earliest_created_first': case 'earliest_played_first': case 'date_added_ascending': + case 'published_ascending': case 'oldest': default: // quantity ascending diff --git a/src/renderer/views/Playlist/Playlist.js b/src/renderer/views/Playlist/Playlist.js index de97d22d1724e..e671f5363e1da 100644 --- a/src/renderer/views/Playlist/Playlist.js +++ b/src/renderer/views/Playlist/Playlist.js @@ -215,6 +215,10 @@ export default defineComponent({ return this.$t('Playlist.Sort By.DateAddedNewest') case SORT_BY_VALUES.DateAddedOldest: return this.$t('Playlist.Sort By.DateAddedOldest') + case SORT_BY_VALUES.PublishedNewest: + return this.$t('Playlist.Sort By.PublishedNewest') + case SORT_BY_VALUES.PublishedOldest: + return this.$t('Playlist.Sort By.PublishedOldest') case SORT_BY_VALUES.VideoTitleAscending: return this.$t('Playlist.Sort By.VideoTitleAscending') case SORT_BY_VALUES.VideoTitleDescending: diff --git a/src/renderer/views/Watch/Watch.js b/src/renderer/views/Watch/Watch.js index edda7ef359576..6b6252c1eeb71 100644 --- a/src/renderer/views/Watch/Watch.js +++ b/src/renderer/views/Watch/Watch.js @@ -101,6 +101,7 @@ export default defineComponent({ channelId: '', channelSubscriptionCountText: '', videoPublished: 0, + premiereDate: undefined, videoStoryboardSrc: '', /** @type {string|null} */ manifestSrc: null, @@ -629,9 +630,12 @@ export default defineComponent({ // TODO a I18n entry for time format might be needed here this.upcomingTimeLeft = new Intl.RelativeTimeFormat(this.currentLocale).format(upcomingTimeLeft, timeUnit) } + + this.premiereDate = upcomingTimestamp } else { this.upcomingTimestamp = null this.upcomingTimeLeft = null + this.premiereDate = undefined } } else { this.videoLengthSeconds = result.basic_info.duration diff --git a/src/renderer/views/Watch/Watch.vue b/src/renderer/views/Watch/Watch.vue index d2c792227a8bb..80e9e63a5a545 100644 --- a/src/renderer/views/Watch/Watch.vue +++ b/src/renderer/views/Watch/Watch.vue @@ -124,6 +124,7 @@ :channel-name="channelName" :channel-thumbnail="channelThumbnail" :published="videoPublished" + :premiere-date="premiereDate" :subscription-count-text="channelSubscriptionCountText" :like-count="videoLikeCount" :dislike-count="videoDislikeCount" diff --git a/static/locales/en-US.yaml b/static/locales/en-US.yaml index f0758bed23eb9..b3aaa45826c91 100644 --- a/static/locales/en-US.yaml +++ b/static/locales/en-US.yaml @@ -936,6 +936,8 @@ Playlist: Sort By: Sort By DateAddedNewest: Latest added first DateAddedOldest: Earliest added first + PublishedNewest: Latest published first + PublishedOldest: Earliest published first AuthorAscending: Author (A-Z) AuthorDescending: Author (Z-A) VideoTitleAscending: Title (A-Z)