@@ -7,6 +7,7 @@ import PlaylistInfo from '../../components/playlist-info/playlist-info.vue'
77import FtListVideoNumbered from '../../components/ft-list-video-numbered/ft-list-video-numbered.vue'
88import FtFlexBox from '../../components/ft-flex-box/ft-flex-box.vue'
99import FtButton from '../../components/ft-button/ft-button.vue'
10+ import FtSelect from '../../components/ft-select/ft-select.vue'
1011import FtAutoLoadNextPageWrapper from '../../components/ft-auto-load-next-page-wrapper/ft-auto-load-next-page-wrapper.vue'
1112import {
1213 getLocalPlaylist ,
@@ -16,6 +17,16 @@ import {
1617import { extractNumberFromString , setPublishedTimestampsInvidious , showToast } from '../../helpers/utils'
1718import { invidiousGetPlaylistInfo , youtubeImageUrlToInvidious } from '../../helpers/api/invidious'
1819
20+ const SORT_BY_VALUES = {
21+ DateAddedNewest : 'date_added_descending' ,
22+ DateAddedOldest : 'date_added_ascending' ,
23+ AuthorAscending : 'author_ascending' ,
24+ AuthorDescending : 'author_descending' ,
25+ VideoTitleAscending : 'video_title_ascending' ,
26+ VideoTitleDescending : 'video_title_descending' ,
27+ Custom : 'custom' ,
28+ }
29+
1930export default defineComponent ( {
2031 name : 'Playlist' ,
2132 components : {
@@ -25,6 +36,7 @@ export default defineComponent({
2536 'ft-list-video-numbered' : FtListVideoNumbered ,
2637 'ft-flex-box' : FtFlexBox ,
2738 'ft-button' : FtButton ,
39+ 'ft-select' : FtSelect ,
2840 'ft-auto-load-next-page-wrapper' : FtAutoLoadNextPageWrapper ,
2941 } ,
3042 beforeRouteLeave ( to , from , next ) {
@@ -77,6 +89,12 @@ export default defineComponent({
7789 currentInvidiousInstance : function ( ) {
7890 return this . $store . getters . getCurrentInvidiousInstance
7991 } ,
92+ userPlaylistSortOrder : function ( ) {
93+ return this . $store . getters . getUserPlaylistSortOrder
94+ } ,
95+ sortOrder : function ( ) {
96+ return this . isUserPlaylistRequested ? this . userPlaylistSortOrder : SORT_BY_VALUES . Custom
97+ } ,
8098 currentLocale : function ( ) {
8199 return this . $i18n . locale . replace ( '_' , '-' )
82100 } ,
@@ -138,10 +156,10 @@ export default defineComponent({
138156 } ,
139157
140158 sometimesFilteredUserPlaylistItems ( ) {
141- if ( ! this . isUserPlaylistRequested ) { return this . playlistItems }
142- if ( this . processedVideoSearchQuery === '' ) { return this . playlistItems }
159+ if ( ! this . isUserPlaylistRequested ) { return this . sortedPlaylistItems }
160+ if ( this . processedVideoSearchQuery === '' ) { return this . sortedPlaylistItems }
143161
144- return this . playlistItems . filter ( ( v ) => {
162+ return this . sortedPlaylistItems . filter ( ( v ) => {
145163 if ( typeof ( v . title ) === 'string' && v . title . toLowerCase ( ) . includes ( this . processedVideoSearchQuery ) ) {
146164 return true
147165 } else if ( typeof ( v . author ) === 'string' && v . author . toLowerCase ( ) . includes ( this . processedVideoSearchQuery ) ) {
@@ -151,10 +169,41 @@ export default defineComponent({
151169 return false
152170 } )
153171 } ,
172+ sortByValues ( ) {
173+ return Object . values ( SORT_BY_VALUES )
174+ } ,
175+ isSortOrderCustom ( ) {
176+ return this . sortOrder === SORT_BY_VALUES . Custom
177+ } ,
178+ sortedPlaylistItems : function ( ) {
179+ if ( this . sortOrder === SORT_BY_VALUES . Custom ) {
180+ return this . playlistItems
181+ }
182+
183+ return this . playlistItems . toSorted ( ( a , b ) => {
184+ switch ( this . sortOrder ) {
185+ case SORT_BY_VALUES . DateAddedNewest :
186+ return b . timeAdded - a . timeAdded
187+ case SORT_BY_VALUES . DateAddedOldest :
188+ return a . timeAdded - b . timeAdded
189+ case SORT_BY_VALUES . VideoTitleAscending :
190+ return a . title . localeCompare ( b . title , this . currentLocale )
191+ case SORT_BY_VALUES . VideoTitleDescending :
192+ return b . title . localeCompare ( a . title , this . currentLocale )
193+ case SORT_BY_VALUES . AuthorAscending :
194+ return a . author . localeCompare ( b . author , this . currentLocale )
195+ case SORT_BY_VALUES . AuthorDescending :
196+ return b . author . localeCompare ( a . author , this . currentLocale )
197+ default :
198+ console . error ( `Unknown sortOrder: ${ this . sortOrder } ` )
199+ return 0
200+ }
201+ } )
202+ } ,
154203 visiblePlaylistItems : function ( ) {
155204 if ( ! this . isUserPlaylistRequested ) {
156205 // No filtering for non user playlists yet
157- return this . playlistItems
206+ return this . sortedPlaylistItems
158207 }
159208
160209 if ( this . userPlaylistVisibleLimit < this . sometimesFilteredUserPlaylistItems . length ) {
@@ -166,6 +215,32 @@ export default defineComponent({
166215 processedVideoSearchQuery ( ) {
167216 return this . videoSearchQuery . trim ( ) . toLowerCase ( )
168217 } ,
218+ sortBySelectNames ( ) {
219+ return this . sortByValues . map ( ( k ) => {
220+ switch ( k ) {
221+ case SORT_BY_VALUES . Custom :
222+ return this . $t ( 'Playlist.Sort By.Custom' )
223+ case SORT_BY_VALUES . DateAddedNewest :
224+ return this . $t ( 'Playlist.Sort By.DateAddedNewest' )
225+ case SORT_BY_VALUES . DateAddedOldest :
226+ return this . $t ( 'Playlist.Sort By.DateAddedOldest' )
227+ case SORT_BY_VALUES . VideoTitleAscending :
228+ return this . $t ( 'Playlist.Sort By.VideoTitleAscending' )
229+ case SORT_BY_VALUES . VideoTitleDescending :
230+ return this . $t ( 'Playlist.Sort By.VideoTitleDescending' )
231+ case SORT_BY_VALUES . AuthorAscending :
232+ return this . $t ( 'Playlist.Sort By.AuthorAscending' )
233+ case SORT_BY_VALUES . AuthorDescending :
234+ return this . $t ( 'Playlist.Sort By.AuthorDescending' )
235+ default :
236+ console . error ( `Unknown sort: ${ k } ` )
237+ return k
238+ }
239+ } )
240+ } ,
241+ sortBySelectValues ( ) {
242+ return this . sortByValues
243+ } ,
169244 } ,
170245 watch : {
171246 $route ( ) {
@@ -485,6 +560,7 @@ export default defineComponent({
485560 ...mapActions ( [
486561 'updateSubscriptionDetails' ,
487562 'updatePlaylist' ,
563+ 'updateUserPlaylistSortOrder' ,
488564 'removeVideo' ,
489565 ] ) ,
490566
0 commit comments