From 6cfcf36c3cdc1663179806810bb10826ba634657 Mon Sep 17 00:00:00 2001 From: MrK Date: Sun, 17 Sep 2023 23:27:44 +0100 Subject: [PATCH 01/14] Fixing bug #5584 by sending the proper Sort params to the API --- src/components/playback/playbackmanager.js | 16 ++++++++++++++-- src/components/shortcuts.js | 18 ++++++++++++++++-- src/controllers/list.js | 4 +++- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 05117fd08d9..c1ba163335e 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1806,12 +1806,18 @@ class PlaybackManager { MediaTypes: 'Audio' }); } else if (firstItem.MediaType === 'Photo') { + const sortOptions = options.sortOptions || {}; + let sortByValue = options.shuffle ? 'Random' : sortOptions.sortBy; + if (sortByValue == null) { + sortByValue = 'SortName'; + } promise = getItemsForPlayback(serverId, { ParentId: firstItem.ParentId, Filters: 'IsNotFolder', // Setting this to true may cause some incorrect sorting Recursive: false, - SortBy: options.shuffle ? 'Random' : 'SortName', + SortBy: sortByValue, + SortOrder: sortOptions.sortOrder, MediaTypes: 'Photo,Video', Limit: UNLIMITED_ITEMS }).then(function (result) { @@ -1849,11 +1855,17 @@ class PlaybackManager { MediaTypes: 'Audio' }); } else if (firstItem.IsFolder && firstItem.CollectionType === 'homevideos') { + const sortOptions = options.sortOptions || {}; + let sortByValue = options.shuffle ? 'Random' : sortOptions.sortBy; + if (sortByValue == null) { + sortByValue = 'SortName'; + } promise = getItemsForPlayback(serverId, mergePlaybackQueries({ ParentId: firstItem.Id, Filters: 'IsNotFolder', Recursive: true, - SortBy: options.shuffle ? 'Random' : 'SortName', + SortBy: sortByValue, + SortOrder: sortOptions.sortOrder, // Only include Photos because we do not handle mixed queues currently MediaTypes: 'Photo', Limit: UNLIMITED_ITEMS diff --git a/src/components/shortcuts.js b/src/components/shortcuts.js index 7dc840e8b61..10174d886d8 100644 --- a/src/components/shortcuts.js +++ b/src/components/shortcuts.js @@ -11,6 +11,7 @@ import dom from '../scripts/dom'; import recordingHelper from './recordingcreator/recordinghelper'; import ServerConnections from './ServerConnections'; import toast from './toast/toast'; +import * as userSettings from '../scripts/settings/userSettings'; function playAllFromHere(card, serverId, queue) { const parent = card.parentNode; @@ -165,6 +166,14 @@ function showPlayMenu(card, target) { }); } +function getSortValues(parentId) { + const basekey = 'items-' + parentId + '-Folder'; + return { + sortBy: userSettings.getFilter(basekey + '-sortby'), + sortOrder: userSettings.getFilter(basekey + '-sortorder') === 'Descending' ? 'Descending' : 'Ascending' + }; +} + function executeAction(card, target, action) { target = target || card; @@ -175,6 +184,10 @@ function executeAction(card, target, action) { id = card.getAttribute('data-id'); } + const itemsContainer = dom.parentWithClass(card, 'itemsContainer'); + + const parentId = itemsContainer.getAttribute('data-parentid'); + const item = getItemInfoFromCard(card); const serverId = item.ServerId; @@ -200,12 +213,13 @@ function executeAction(card, target, action) { }); } else if (action === 'play' || action === 'resume') { const startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0', 10); - + if (playbackManager.canPlay(item)) { playbackManager.play({ ids: [playableItemId], startPositionTicks: startPositionTicks, - serverId: serverId + serverId: serverId, + sortOptions: getSortValues(parentId) }); } else { console.warn('Unable to play item', item); diff --git a/src/controllers/list.js b/src/controllers/list.js index 0378a1025cb..fc2366a3e99 100644 --- a/src/controllers/list.js +++ b/src/controllers/list.js @@ -722,11 +722,13 @@ class ItemsView { function play() { const currentItem = self.currentItem; + const values = self.getSortValues(); if (currentItem && !self.hasFilters) { playbackManager.play({ items: [currentItem], - autoplay: true + autoplay: true, + sortOptions: values }); } else { getItems(self, self.params, currentItem, null, 0, 300).then(function (result) { From 344a6bfad6b7b88749f93cc236dc7bd2b7c4065f Mon Sep 17 00:00:00 2001 From: MrK Date: Sun, 17 Sep 2023 23:33:58 +0100 Subject: [PATCH 02/14] Updated CONTRIBUTORS.md --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index eccfd4cf279..835b7db646f 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -132,3 +132,4 @@ - [jomp16](https://github.com/jomp16) - [Leon de Klerk](https://github.com/leondeklerk) - [CrispyBaguette](https://github.com/CrispyBaguette) + - [v0idMrK](https://github.com/v0idMrK) From ecba6dccb95e5859c0eb934d2df3ff49da909dca Mon Sep 17 00:00:00 2001 From: MrK Date: Mon, 18 Sep 2023 13:00:22 +0100 Subject: [PATCH 03/14] Removing bad trailing space --- src/components/shortcuts.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/shortcuts.js b/src/components/shortcuts.js index 10174d886d8..22366c5c708 100644 --- a/src/components/shortcuts.js +++ b/src/components/shortcuts.js @@ -213,7 +213,6 @@ function executeAction(card, target, action) { }); } else if (action === 'play' || action === 'resume') { const startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0', 10); - if (playbackManager.canPlay(item)) { playbackManager.play({ ids: [playableItemId], From f922742d862e0111e785efd0fb8002098be8de0a Mon Sep 17 00:00:00 2001 From: MrK Date: Mon, 18 Sep 2023 19:36:21 +0100 Subject: [PATCH 04/14] Contributors file updated correctly Adds shortcuts.js function to get sort order Added sort order technique to most types of media on playbackmanager.js --- CONTRIBUTORS.md | 2 +- src/components/playback/playbackmanager.js | 42 +++++++++++++--------- src/components/shortcuts.js | 1 + 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 835b7db646f..3cb25b462e2 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -66,6 +66,7 @@ - [Fishbigger](https://github.com/fishbigger) - [sleepycatcoding](https://github.com/sleepycatcoding) - [TheMelmacian](https://github.com/TheMelmacian) + - [v0idMrK](https://github.com/v0idMrK) # Emby Contributors @@ -132,4 +133,3 @@ - [jomp16](https://github.com/jomp16) - [Leon de Klerk](https://github.com/leondeklerk) - [CrispyBaguette](https://github.com/CrispyBaguette) - - [v0idMrK](https://github.com/v0idMrK) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index c1ba163335e..60173e8ed2d 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1773,6 +1773,18 @@ class PlaybackManager { }); } + function getSortOptions(options) { + const sortOptions = options.sortOptions || {}; + let sortByValue = options.shuffle ? 'Random' : sortOptions.sortBy; + if (sortByValue == null) { + sortByValue = 'SortName'; + } + return { + sortBy: sortByValue, + sortOrder: sortOptions.sortOrder + }; + } + function translateItemsForPlayback(items, options) { if (items.length > 1 && options && options.ids) { // Use the original request id array for sorting the result in the proper order @@ -1788,6 +1800,8 @@ class PlaybackManager { const queryOptions = options.queryOptions || {}; + const sortOptions = getSortOptions(options); + if (firstItem.Type === 'Program') { promise = getItemsForPlayback(serverId, { Ids: firstItem.ChannelId @@ -1802,21 +1816,17 @@ class PlaybackManager { ArtistIds: firstItem.Id, Filters: 'IsNotFolder', Recursive: true, - SortBy: options.shuffle ? 'Random' : 'SortName', + SortBy: sortOptions.sortBy, + SortOrder: sortOptions.sortOrder, MediaTypes: 'Audio' }); } else if (firstItem.MediaType === 'Photo') { - const sortOptions = options.sortOptions || {}; - let sortByValue = options.shuffle ? 'Random' : sortOptions.sortBy; - if (sortByValue == null) { - sortByValue = 'SortName'; - } promise = getItemsForPlayback(serverId, { ParentId: firstItem.ParentId, Filters: 'IsNotFolder', // Setting this to true may cause some incorrect sorting Recursive: false, - SortBy: sortByValue, + SortBy: sortOptions.sortBy, SortOrder: sortOptions.sortOrder, MediaTypes: 'Photo,Video', Limit: UNLIMITED_ITEMS @@ -1841,7 +1851,8 @@ class PlaybackManager { Filters: 'IsNotFolder', // Setting this to true may cause some incorrect sorting Recursive: false, - SortBy: options.shuffle ? 'Random' : 'SortName', + SortBy: sortOptions.sortBy, + SortOrder: sortOptions.sortOrder, // Only include Photos because we do not handle mixed queues currently MediaTypes: 'Photo', Limit: UNLIMITED_ITEMS @@ -1851,20 +1862,16 @@ class PlaybackManager { GenreIds: firstItem.Id, Filters: 'IsNotFolder', Recursive: true, - SortBy: options.shuffle ? 'Random' : 'SortName', + SortBy: sortOptions.sortBy, + SortOrder: sortOptions.sortOrder, MediaTypes: 'Audio' }); } else if (firstItem.IsFolder && firstItem.CollectionType === 'homevideos') { - const sortOptions = options.sortOptions || {}; - let sortByValue = options.shuffle ? 'Random' : sortOptions.sortBy; - if (sortByValue == null) { - sortByValue = 'SortName'; - } promise = getItemsForPlayback(serverId, mergePlaybackQueries({ ParentId: firstItem.Id, Filters: 'IsNotFolder', Recursive: true, - SortBy: sortByValue, + SortBy: sortOptions.sortBy, SortOrder: sortOptions.sortOrder, // Only include Photos because we do not handle mixed queues currently MediaTypes: 'Photo', @@ -1872,10 +1879,12 @@ class PlaybackManager { }, queryOptions)); } else if (firstItem.IsFolder) { let sortBy = null; + let sortOrder = null; if (options.shuffle) { sortBy = 'Random'; } else if (firstItem.Type !== 'BoxSet') { - sortBy = 'SortName'; + sortBy = sortOptions.sortBy; + sortOrder = sortOptions.sortOrder; } promise = getItemsForPlayback(serverId, mergePlaybackQueries({ ParentId: firstItem.Id, @@ -1883,6 +1892,7 @@ class PlaybackManager { Recursive: true, // These are pre-sorted SortBy: sortBy, + SortOrder: sortOrder, MediaTypes: 'Audio,Video' }, queryOptions)); } else if (firstItem.Type === 'Episode' && items.length === 1 && getPlayer(firstItem, options).supportsProgress !== false) { diff --git a/src/components/shortcuts.js b/src/components/shortcuts.js index 22366c5c708..d4de04dbf0b 100644 --- a/src/components/shortcuts.js +++ b/src/components/shortcuts.js @@ -213,6 +213,7 @@ function executeAction(card, target, action) { }); } else if (action === 'play' || action === 'resume') { const startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0', 10); + if (playbackManager.canPlay(item)) { playbackManager.play({ ids: [playableItemId], From 580ad5f1a8dfde72be012c062b3405c766eb8ca9 Mon Sep 17 00:00:00 2001 From: MrK Date: Tue, 19 Sep 2023 22:29:54 +0100 Subject: [PATCH 05/14] Added getSortOptions to userSettings.js and cleaned up the shortcuts.js and list.js to use the above method --- src/components/shortcuts.js | 16 ++++------------ src/controllers/list.js | 5 +---- src/scripts/settings/userSettings.js | 13 +++++++++++++ 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/components/shortcuts.js b/src/components/shortcuts.js index d4de04dbf0b..70bf264fc3c 100644 --- a/src/components/shortcuts.js +++ b/src/components/shortcuts.js @@ -166,14 +166,6 @@ function showPlayMenu(card, target) { }); } -function getSortValues(parentId) { - const basekey = 'items-' + parentId + '-Folder'; - return { - sortBy: userSettings.getFilter(basekey + '-sortby'), - sortOrder: userSettings.getFilter(basekey + '-sortorder') === 'Descending' ? 'Descending' : 'Ascending' - }; -} - function executeAction(card, target, action) { target = target || card; @@ -184,11 +176,11 @@ function executeAction(card, target, action) { id = card.getAttribute('data-id'); } - const itemsContainer = dom.parentWithClass(card, 'itemsContainer'); + const item = getItemInfoFromCard(card); - const parentId = itemsContainer.getAttribute('data-parentid'); + const itemsContainer = dom.parentWithClass(card, 'itemsContainer'); - const item = getItemInfoFromCard(card); + const sortParentId = 'items-' + (item.IsFolder ? item.Id : itemsContainer.getAttribute('data-parentid')) + '-Folder'; const serverId = item.ServerId; const type = item.Type; @@ -219,7 +211,7 @@ function executeAction(card, target, action) { ids: [playableItemId], startPositionTicks: startPositionTicks, serverId: serverId, - sortOptions: getSortValues(parentId) + sortOptions: userSettings.getSortValues(sortParentId) }); } else { console.warn('Unable to play item', item); diff --git a/src/controllers/list.js b/src/controllers/list.js index fc2366a3e99..ded9d921eda 100644 --- a/src/controllers/list.js +++ b/src/controllers/list.js @@ -962,10 +962,7 @@ class ItemsView { getSortValues() { const basekey = this.getSettingsKey(); - return { - sortBy: userSettings.getFilter(basekey + '-sortby') || this.getDefaultSortBy(), - sortOrder: userSettings.getFilter(basekey + '-sortorder') === 'Descending' ? 'Descending' : 'Ascending' - }; + return userSettings.getSortValues(basekey); } getDefaultSortBy() { diff --git a/src/scripts/settings/userSettings.js b/src/scripts/settings/userSettings.js index 691b07cb4d1..26fc2100e5b 100644 --- a/src/scripts/settings/userSettings.js +++ b/src/scripts/settings/userSettings.js @@ -622,6 +622,18 @@ export class UserSettings { getFilter(key) { return this.get(key, true); } + + /** + * Gets the current sort values + * @param {string} key - Filter key. + * @return {Object} sortOptions object + */ + getSortValues(key) { + return { + sortBy: this.getFilter(key + '-sortby'), + sortOrder: this.getFilter(key + '-sortorder') === 'Descending' ? 'Descending' : 'Ascending' + }; + } } export const currentSettings = new UserSettings; @@ -672,3 +684,4 @@ export const customCss = currentSettings.customCss.bind(currentSettings); export const disableCustomCss = currentSettings.disableCustomCss.bind(currentSettings); export const getSavedView = currentSettings.getSavedView.bind(currentSettings); export const saveViewSetting = currentSettings.saveViewSetting.bind(currentSettings); +export const getSortValues = currentSettings.getSortValues.bind(currentSettings); From ee791f9d0d2b7c0bc96e6109415c1032d92f2a24 Mon Sep 17 00:00:00 2001 From: MrK Date: Wed, 20 Sep 2023 17:44:55 +0100 Subject: [PATCH 06/14] Changed from using sortOptions to using already implemented queryOptions Null verification for parentid on shortcuts.js itemContextMenu is now obeying to sorting --- src/components/itemContextMenu.js | 30 +++++++++++- src/components/playback/playbackmanager.js | 55 +++++++--------------- src/components/shortcuts.js | 4 +- src/controllers/list.js | 4 +- src/scripts/settings/userSettings.js | 20 ++++++-- 5 files changed, 68 insertions(+), 45 deletions(-) diff --git a/src/components/itemContextMenu.js b/src/components/itemContextMenu.js index 0ec982f15aa..fe01437b9d8 100644 --- a/src/components/itemContextMenu.js +++ b/src/components/itemContextMenu.js @@ -9,6 +9,8 @@ import itemHelper from './itemHelper'; import { playbackManager } from './playback/playbackmanager'; import ServerConnections from './ServerConnections'; import toast from './toast/toast'; +import * as userSettings from '../scripts/settings/userSettings'; +import libraryMenu from '../scripts/libraryMenu'; export function getCommands(options) { const item = options.item; @@ -567,6 +569,29 @@ function deleteSeriesTimer(apiClient, item, resolve, command) { }); } +function getSettingsKey(item) { + if (item.IsFolder) { + return 'Folder'; + } + const itemType = item.MediaType; + switch (itemType) { + case 'Movie': + case 'BoxSet': + case 'Video': + return 'movies'; + case 'Audio': + return 'songs'; + case 'MusicAlbum': + return 'musicalbums'; + case 'MusicArtist': + return 'musicartists'; + case 'MusicGenre': + return 'genres'; + case 'MusicPlaylist': + return 'musicplaylists'; + } +} + function play(item, resume, queue, queueNext) { let method = 'play'; if (queue) { @@ -589,9 +614,12 @@ function play(item, resume, queue, queueNext) { serverId: item.ServerId }); } else { + const sortParentId = item.IsFolder ? ('items-' + item.Id) : libraryMenu.getTopParentId() + '-' + getSettingsKey(item); + const sortValues = userSettings.getSortValues(sortParentId); playbackManager[method]({ items: [item], - startPositionTicks: startPosition + startPositionTicks: startPosition, + queryOptions: sortValues }); } } diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 60173e8ed2d..1981fdc57e2 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -145,7 +145,10 @@ function createStreamInfoFromUrlItem(item) { } function mergePlaybackQueries(obj1, obj2) { - const query = Object.assign(obj1, obj2); + const query = obj1; + for (const key in obj2) { + if (obj2[key] !== undefined) query[key] = obj2[key]; + } const filters = query.Filters ? query.Filters.split(',') : []; if (filters.indexOf('IsNotFolder') === -1) { @@ -1773,18 +1776,6 @@ class PlaybackManager { }); } - function getSortOptions(options) { - const sortOptions = options.sortOptions || {}; - let sortByValue = options.shuffle ? 'Random' : sortOptions.sortBy; - if (sortByValue == null) { - sortByValue = 'SortName'; - } - return { - sortBy: sortByValue, - sortOrder: sortOptions.sortOrder - }; - } - function translateItemsForPlayback(items, options) { if (items.length > 1 && options && options.ids) { // Use the original request id array for sorting the result in the proper order @@ -1800,8 +1791,6 @@ class PlaybackManager { const queryOptions = options.queryOptions || {}; - const sortOptions = getSortOptions(options); - if (firstItem.Type === 'Program') { promise = getItemsForPlayback(serverId, { Ids: firstItem.ChannelId @@ -1812,25 +1801,23 @@ class PlaybackManager { SortBy: options.shuffle ? 'Random' : null }); } else if (firstItem.Type === 'MusicArtist') { - promise = getItemsForPlayback(serverId, { + promise = getItemsForPlayback(serverId, mergePlaybackQueries({ ArtistIds: firstItem.Id, Filters: 'IsNotFolder', Recursive: true, - SortBy: sortOptions.sortBy, - SortOrder: sortOptions.sortOrder, + SortBy: options.shuffle ? 'Random' : 'SortName', MediaTypes: 'Audio' - }); + }, queryOptions)); } else if (firstItem.MediaType === 'Photo') { - promise = getItemsForPlayback(serverId, { + promise = getItemsForPlayback(serverId, mergePlaybackQueries({ ParentId: firstItem.ParentId, Filters: 'IsNotFolder', // Setting this to true may cause some incorrect sorting Recursive: false, - SortBy: sortOptions.sortBy, - SortOrder: sortOptions.sortOrder, MediaTypes: 'Photo,Video', + sortBy: options.shuffle ? 'Random' : 'SortName', Limit: UNLIMITED_ITEMS - }).then(function (result) { + }, queryOptions)).then(function (result) { const playbackItems = result.Items; let index = playbackItems.map(function (i) { @@ -1846,45 +1833,40 @@ class PlaybackManager { return Promise.resolve(result); }); } else if (firstItem.Type === 'PhotoAlbum') { - promise = getItemsForPlayback(serverId, { + promise = getItemsForPlayback(serverId, mergePlaybackQueries({ ParentId: firstItem.Id, Filters: 'IsNotFolder', // Setting this to true may cause some incorrect sorting Recursive: false, - SortBy: sortOptions.sortBy, - SortOrder: sortOptions.sortOrder, + SortBy: options.shuffle ? 'Random' : 'SortName', // Only include Photos because we do not handle mixed queues currently MediaTypes: 'Photo', Limit: UNLIMITED_ITEMS - }); + }, queryOptions)); } else if (firstItem.Type === 'MusicGenre') { - promise = getItemsForPlayback(serverId, { + promise = getItemsForPlayback(serverId, mergePlaybackQueries({ GenreIds: firstItem.Id, Filters: 'IsNotFolder', Recursive: true, - SortBy: sortOptions.sortBy, - SortOrder: sortOptions.sortOrder, + SortBy: options.shuffle ? 'Random' : 'SortName', MediaTypes: 'Audio' - }); + })); } else if (firstItem.IsFolder && firstItem.CollectionType === 'homevideos') { promise = getItemsForPlayback(serverId, mergePlaybackQueries({ ParentId: firstItem.Id, Filters: 'IsNotFolder', Recursive: true, - SortBy: sortOptions.sortBy, - SortOrder: sortOptions.sortOrder, + SortBy: options.shuffle ? 'Random' : 'SortName', // Only include Photos because we do not handle mixed queues currently MediaTypes: 'Photo', Limit: UNLIMITED_ITEMS }, queryOptions)); } else if (firstItem.IsFolder) { let sortBy = null; - let sortOrder = null; if (options.shuffle) { sortBy = 'Random'; } else if (firstItem.Type !== 'BoxSet') { - sortBy = sortOptions.sortBy; - sortOrder = sortOptions.sortOrder; + sortBy = 'SortName'; } promise = getItemsForPlayback(serverId, mergePlaybackQueries({ ParentId: firstItem.Id, @@ -1892,7 +1874,6 @@ class PlaybackManager { Recursive: true, // These are pre-sorted SortBy: sortBy, - SortOrder: sortOrder, MediaTypes: 'Audio,Video' }, queryOptions)); } else if (firstItem.Type === 'Episode' && items.length === 1 && getPlayer(firstItem, options).supportsProgress !== false) { diff --git a/src/components/shortcuts.js b/src/components/shortcuts.js index 70bf264fc3c..0fca127afa5 100644 --- a/src/components/shortcuts.js +++ b/src/components/shortcuts.js @@ -180,7 +180,7 @@ function executeAction(card, target, action) { const itemsContainer = dom.parentWithClass(card, 'itemsContainer'); - const sortParentId = 'items-' + (item.IsFolder ? item.Id : itemsContainer.getAttribute('data-parentid')) + '-Folder'; + const sortParentId = 'items-' + (item.IsFolder ? item.Id : itemsContainer?.getAttribute('data-parentid')) + '-Folder'; const serverId = item.ServerId; const type = item.Type; @@ -211,7 +211,7 @@ function executeAction(card, target, action) { ids: [playableItemId], startPositionTicks: startPositionTicks, serverId: serverId, - sortOptions: userSettings.getSortValues(sortParentId) + queryOptions: userSettings.getSortValuesLegacy(sortParentId, 'SortName') }); } else { console.warn('Unable to play item', item); diff --git a/src/controllers/list.js b/src/controllers/list.js index ded9d921eda..31f3d5000e9 100644 --- a/src/controllers/list.js +++ b/src/controllers/list.js @@ -728,7 +728,7 @@ class ItemsView { playbackManager.play({ items: [currentItem], autoplay: true, - sortOptions: values + queryOptions: values }); } else { getItems(self, self.params, currentItem, null, 0, 300).then(function (result) { @@ -962,7 +962,7 @@ class ItemsView { getSortValues() { const basekey = this.getSettingsKey(); - return userSettings.getSortValues(basekey); + return userSettings.getSortValuesLegacy(basekey, this.getDefaultSortBy()); } getDefaultSortBy() { diff --git a/src/scripts/settings/userSettings.js b/src/scripts/settings/userSettings.js index 26fc2100e5b..339da9687c9 100644 --- a/src/scripts/settings/userSettings.js +++ b/src/scripts/settings/userSettings.js @@ -624,16 +624,29 @@ export class UserSettings { } /** - * Gets the current sort values + * Gets the current sort values (Legacy - Non-JSON) + * (old views such as list.js [Photos] will + * use this one) * @param {string} key - Filter key. * @return {Object} sortOptions object */ - getSortValues(key) { + getSortValuesLegacy(key, defaultSortBy) { return { - sortBy: this.getFilter(key + '-sortby'), + sortBy: this.getFilter(key + '-sortby') || defaultSortBy, sortOrder: this.getFilter(key + '-sortorder') === 'Descending' ? 'Descending' : 'Ascending' }; } + + /** + * Gets the current sort values (JSON) + * (new views such as MoviesView will use + * this one) + * @param {string} key - Filter key. + * @return {Object} sortOptions object + */ + getSortValues(key) { + return this.loadQuerySettings(key, {}); + } } export const currentSettings = new UserSettings; @@ -684,4 +697,5 @@ export const customCss = currentSettings.customCss.bind(currentSettings); export const disableCustomCss = currentSettings.disableCustomCss.bind(currentSettings); export const getSavedView = currentSettings.getSavedView.bind(currentSettings); export const saveViewSetting = currentSettings.saveViewSetting.bind(currentSettings); +export const getSortValuesLegacy = currentSettings.getSortValuesLegacy.bind(currentSettings); export const getSortValues = currentSettings.getSortValues.bind(currentSettings); From 4488a586a45e60f2ec75357cd234d7f83d76ad7d Mon Sep 17 00:00:00 2001 From: MrK Date: Wed, 20 Sep 2023 22:50:01 +0100 Subject: [PATCH 07/14] Removed unneeded calls to getSortValues on playbackManager calls that only play 1 item --- src/components/itemContextMenu.js | 28 +--------------------------- src/controllers/list.js | 4 +--- 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/src/components/itemContextMenu.js b/src/components/itemContextMenu.js index fe01437b9d8..db742eda569 100644 --- a/src/components/itemContextMenu.js +++ b/src/components/itemContextMenu.js @@ -569,29 +569,6 @@ function deleteSeriesTimer(apiClient, item, resolve, command) { }); } -function getSettingsKey(item) { - if (item.IsFolder) { - return 'Folder'; - } - const itemType = item.MediaType; - switch (itemType) { - case 'Movie': - case 'BoxSet': - case 'Video': - return 'movies'; - case 'Audio': - return 'songs'; - case 'MusicAlbum': - return 'musicalbums'; - case 'MusicArtist': - return 'musicartists'; - case 'MusicGenre': - return 'genres'; - case 'MusicPlaylist': - return 'musicplaylists'; - } -} - function play(item, resume, queue, queueNext) { let method = 'play'; if (queue) { @@ -614,12 +591,9 @@ function play(item, resume, queue, queueNext) { serverId: item.ServerId }); } else { - const sortParentId = item.IsFolder ? ('items-' + item.Id) : libraryMenu.getTopParentId() + '-' + getSettingsKey(item); - const sortValues = userSettings.getSortValues(sortParentId); playbackManager[method]({ items: [item], - startPositionTicks: startPosition, - queryOptions: sortValues + startPositionTicks: startPosition }); } } diff --git a/src/controllers/list.js b/src/controllers/list.js index 31f3d5000e9..1ab0bd33837 100644 --- a/src/controllers/list.js +++ b/src/controllers/list.js @@ -722,13 +722,11 @@ class ItemsView { function play() { const currentItem = self.currentItem; - const values = self.getSortValues(); if (currentItem && !self.hasFilters) { playbackManager.play({ items: [currentItem], - autoplay: true, - queryOptions: values + autoplay: true }); } else { getItems(self, self.params, currentItem, null, 0, 300).then(function (result) { From af61ae047c79d1df8889812ebd5dbf8f23314d6a Mon Sep 17 00:00:00 2001 From: MrK Date: Wed, 20 Sep 2023 22:55:16 +0100 Subject: [PATCH 08/14] Added queryOptions to MusicGenre call on playbackmanager UserSettings added param to function comment --- src/components/playback/playbackmanager.js | 2 +- src/scripts/settings/userSettings.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 1981fdc57e2..0ff00b232d3 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1850,7 +1850,7 @@ class PlaybackManager { Recursive: true, SortBy: options.shuffle ? 'Random' : 'SortName', MediaTypes: 'Audio' - })); + }, queryOptions)); } else if (firstItem.IsFolder && firstItem.CollectionType === 'homevideos') { promise = getItemsForPlayback(serverId, mergePlaybackQueries({ ParentId: firstItem.Id, diff --git a/src/scripts/settings/userSettings.js b/src/scripts/settings/userSettings.js index 339da9687c9..fe301463fcf 100644 --- a/src/scripts/settings/userSettings.js +++ b/src/scripts/settings/userSettings.js @@ -628,6 +628,7 @@ export class UserSettings { * (old views such as list.js [Photos] will * use this one) * @param {string} key - Filter key. + * @param {string} defaultSortBy - Default SortBy value. * @return {Object} sortOptions object */ getSortValuesLegacy(key, defaultSortBy) { From ef8d92309bc8770e4a0a7e1dc2b6269d45f95c82 Mon Sep 17 00:00:00 2001 From: MrK Date: Wed, 20 Sep 2023 23:10:09 +0100 Subject: [PATCH 09/14] Code cleanup Restoring "Play All" functionality --- src/components/shortcuts.js | 7 +++++-- src/controllers/list.js | 5 +++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/components/shortcuts.js b/src/components/shortcuts.js index 0fca127afa5..bcbf42a36c0 100644 --- a/src/components/shortcuts.js +++ b/src/components/shortcuts.js @@ -205,13 +205,16 @@ function executeAction(card, target, action) { }); } else if (action === 'play' || action === 'resume') { const startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0', 10); - + const sortValues = userSettings.getSortValuesLegacy(sortParentId, 'SortName'); if (playbackManager.canPlay(item)) { playbackManager.play({ ids: [playableItemId], startPositionTicks: startPositionTicks, serverId: serverId, - queryOptions: userSettings.getSortValuesLegacy(sortParentId, 'SortName') + queryOptions: { + SortBy: sortValues.sortBy, + SortOrder: sortValues.sortOrder + } }); } else { console.warn('Unable to play item', item); diff --git a/src/controllers/list.js b/src/controllers/list.js index 1ab0bd33837..5370bdcd6f1 100644 --- a/src/controllers/list.js +++ b/src/controllers/list.js @@ -724,8 +724,13 @@ class ItemsView { const currentItem = self.currentItem; if (currentItem && !self.hasFilters) { + const values = self.getSortValues(); playbackManager.play({ items: [currentItem], + queryOptions: { + SortBy: values.sortBy, + SortOrder: values.sortOrder + }, autoplay: true }); } else { From c935ba9a2058aec7eac1d234e27b6fb9dcbde082 Mon Sep 17 00:00:00 2001 From: MrK Date: Thu, 21 Sep 2023 00:14:07 +0100 Subject: [PATCH 10/14] Removed unused imports --- src/components/itemContextMenu.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/itemContextMenu.js b/src/components/itemContextMenu.js index db742eda569..0ec982f15aa 100644 --- a/src/components/itemContextMenu.js +++ b/src/components/itemContextMenu.js @@ -9,8 +9,6 @@ import itemHelper from './itemHelper'; import { playbackManager } from './playback/playbackmanager'; import ServerConnections from './ServerConnections'; import toast from './toast/toast'; -import * as userSettings from '../scripts/settings/userSettings'; -import libraryMenu from '../scripts/libraryMenu'; export function getCommands(options) { const item = options.item; From 5d20523616eebb814b3b1361cceee27eee33a083 Mon Sep 17 00:00:00 2001 From: MrK Date: Sat, 23 Sep 2023 22:50:57 +0100 Subject: [PATCH 11/14] Reverting itemContextMenu changes to support folder/playlist ordering with the "Play" action Code cleanup --- src/components/itemContextMenu.js | 34 +++++++++++++++++++++- src/components/playback/playbackmanager.js | 2 +- src/components/shortcuts.js | 1 + 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/components/itemContextMenu.js b/src/components/itemContextMenu.js index 0ec982f15aa..ee5518e110f 100644 --- a/src/components/itemContextMenu.js +++ b/src/components/itemContextMenu.js @@ -9,6 +9,8 @@ import itemHelper from './itemHelper'; import { playbackManager } from './playback/playbackmanager'; import ServerConnections from './ServerConnections'; import toast from './toast/toast'; +import * as userSettings from '../scripts/settings/userSettings'; +import libraryMenu from '../scripts/libraryMenu'; export function getCommands(options) { const item = options.item; @@ -567,6 +569,29 @@ function deleteSeriesTimer(apiClient, item, resolve, command) { }); } +function getSettingsKey(item) { + if (item.IsFolder) { + return 'Folder'; + } + const itemType = item.MediaType; + switch (itemType) { + case 'Movie': + case 'BoxSet': + case 'Video': + return 'movies'; + case 'Audio': + return 'songs'; + case 'MusicAlbum': + return 'musicalbums'; + case 'MusicArtist': + return 'musicartists'; + case 'MusicGenre': + return 'genres'; + case 'MusicPlaylist': + return 'musicplaylists'; + } +} + function play(item, resume, queue, queueNext) { let method = 'play'; if (queue) { @@ -589,9 +614,16 @@ function play(item, resume, queue, queueNext) { serverId: item.ServerId }); } else { + const sortParentId = item.IsFolder ? ('items-' + item.Id) : libraryMenu.getTopParentId() + '-' + getSettingsKey(item); + const sortValues = userSettings.getSortValues(sortParentId); + playbackManager[method]({ items: [item], - startPositionTicks: startPosition + startPositionTicks: startPosition, + queryOptions: { + SortBy: sortValues.sortBy, + SortOrder: sortValues.sortOrder + } }); } } diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 0ff00b232d3..e263a72848d 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1815,7 +1815,7 @@ class PlaybackManager { // Setting this to true may cause some incorrect sorting Recursive: false, MediaTypes: 'Photo,Video', - sortBy: options.shuffle ? 'Random' : 'SortName', + SortBy: options.shuffle ? 'Random' : 'SortName', Limit: UNLIMITED_ITEMS }, queryOptions)).then(function (result) { const playbackItems = result.Items; diff --git a/src/components/shortcuts.js b/src/components/shortcuts.js index bcbf42a36c0..58a7bffb053 100644 --- a/src/components/shortcuts.js +++ b/src/components/shortcuts.js @@ -206,6 +206,7 @@ function executeAction(card, target, action) { } else if (action === 'play' || action === 'resume') { const startPositionTicks = parseInt(card.getAttribute('data-positionticks') || '0', 10); const sortValues = userSettings.getSortValuesLegacy(sortParentId, 'SortName'); + if (playbackManager.canPlay(item)) { playbackManager.play({ ids: [playableItemId], From d62a36a708869ca859d5e146edebb1bff1e1c78e Mon Sep 17 00:00:00 2001 From: MrK Date: Mon, 2 Oct 2023 23:25:57 +0100 Subject: [PATCH 12/14] itemContextMenu only supports folders and using parentId instead for lists Revert line change on playbackmanager.js --- src/components/itemContextMenu.js | 28 ++-------------------- src/components/playback/playbackmanager.js | 2 +- 2 files changed, 3 insertions(+), 27 deletions(-) diff --git a/src/components/itemContextMenu.js b/src/components/itemContextMenu.js index ee5518e110f..89ef6b3d288 100644 --- a/src/components/itemContextMenu.js +++ b/src/components/itemContextMenu.js @@ -10,7 +10,6 @@ import { playbackManager } from './playback/playbackmanager'; import ServerConnections from './ServerConnections'; import toast from './toast/toast'; import * as userSettings from '../scripts/settings/userSettings'; -import libraryMenu from '../scripts/libraryMenu'; export function getCommands(options) { const item = options.item; @@ -569,29 +568,6 @@ function deleteSeriesTimer(apiClient, item, resolve, command) { }); } -function getSettingsKey(item) { - if (item.IsFolder) { - return 'Folder'; - } - const itemType = item.MediaType; - switch (itemType) { - case 'Movie': - case 'BoxSet': - case 'Video': - return 'movies'; - case 'Audio': - return 'songs'; - case 'MusicAlbum': - return 'musicalbums'; - case 'MusicArtist': - return 'musicartists'; - case 'MusicGenre': - return 'genres'; - case 'MusicPlaylist': - return 'musicplaylists'; - } -} - function play(item, resume, queue, queueNext) { let method = 'play'; if (queue) { @@ -614,8 +590,8 @@ function play(item, resume, queue, queueNext) { serverId: item.ServerId }); } else { - const sortParentId = item.IsFolder ? ('items-' + item.Id) : libraryMenu.getTopParentId() + '-' + getSettingsKey(item); - const sortValues = userSettings.getSortValues(sortParentId); + const sortParentId = 'items-' + (item.IsFolder ? item.Id : item.ParentId) + '-Folder'; + const sortValues = userSettings.getSortValuesLegacy(sortParentId); playbackManager[method]({ items: [item], diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index e263a72848d..a546933ea56 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1814,8 +1814,8 @@ class PlaybackManager { Filters: 'IsNotFolder', // Setting this to true may cause some incorrect sorting Recursive: false, - MediaTypes: 'Photo,Video', SortBy: options.shuffle ? 'Random' : 'SortName', + MediaTypes: 'Photo,Video', Limit: UNLIMITED_ITEMS }, queryOptions)).then(function (result) { const playbackItems = result.Items; From ad5bcb6c8d3f9fa073a6178e6c3602d52eb834d2 Mon Sep 17 00:00:00 2001 From: MrK Date: Thu, 5 Oct 2023 22:49:35 +0100 Subject: [PATCH 13/14] Removed unused method --- src/scripts/settings/userSettings.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/scripts/settings/userSettings.js b/src/scripts/settings/userSettings.js index fe301463fcf..f95f508e74c 100644 --- a/src/scripts/settings/userSettings.js +++ b/src/scripts/settings/userSettings.js @@ -637,17 +637,6 @@ export class UserSettings { sortOrder: this.getFilter(key + '-sortorder') === 'Descending' ? 'Descending' : 'Ascending' }; } - - /** - * Gets the current sort values (JSON) - * (new views such as MoviesView will use - * this one) - * @param {string} key - Filter key. - * @return {Object} sortOptions object - */ - getSortValues(key) { - return this.loadQuerySettings(key, {}); - } } export const currentSettings = new UserSettings; @@ -699,4 +688,3 @@ export const disableCustomCss = currentSettings.disableCustomCss.bind(currentSet export const getSavedView = currentSettings.getSavedView.bind(currentSettings); export const saveViewSetting = currentSettings.saveViewSetting.bind(currentSettings); export const getSortValuesLegacy = currentSettings.getSortValuesLegacy.bind(currentSettings); -export const getSortValues = currentSettings.getSortValues.bind(currentSettings); From b33d927c08081090c106dbdcdc6c3b23613c8e1a Mon Sep 17 00:00:00 2001 From: MrK Date: Mon, 16 Oct 2023 21:01:23 +0100 Subject: [PATCH 14/14] Using lodash implementation to merge playback queries --- src/components/playback/playbackmanager.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index a546933ea56..806db30e3f9 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -15,6 +15,7 @@ import { PluginType } from '../../types/plugin.ts'; import { includesAny } from '../../utils/container.ts'; import { getItems } from '../../utils/jellyfin-apiclient/getItems.ts'; import { getItemBackdropImageUrl } from '../../utils/jellyfin-apiclient/backdropImage'; +import merge from 'lodash-es/merge'; const UNLIMITED_ITEMS = -1; @@ -145,10 +146,7 @@ function createStreamInfoFromUrlItem(item) { } function mergePlaybackQueries(obj1, obj2) { - const query = obj1; - for (const key in obj2) { - if (obj2[key] !== undefined) query[key] = obj2[key]; - } + const query = merge({}, obj1, obj2); const filters = query.Filters ? query.Filters.split(',') : []; if (filters.indexOf('IsNotFolder') === -1) {