diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 41fb667ae..d9dd41ecc 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) - [tehciolo](https://github.com/tehciolo) - [scampower3](https://github.com/scampower3) diff --git a/src/components/itemContextMenu.js b/src/components/itemContextMenu.js index 0416ce471..bf03b6903 100644 --- a/src/components/itemContextMenu.js +++ b/src/components/itemContextMenu.js @@ -9,6 +9,7 @@ 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'; export function getCommands(options) { const item = options.item; @@ -589,9 +590,16 @@ function play(item, resume, queue, queueNext) { serverId: item.ServerId }); } else { + const sortParentId = 'items-' + (item.IsFolder ? item.Id : item.ParentId) + '-Folder'; + const sortValues = userSettings.getSortValuesLegacy(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 53b70ea44..25499101f 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,7 +146,7 @@ function createStreamInfoFromUrlItem(item) { } function mergePlaybackQueries(obj1, obj2) { - const query = Object.assign(obj1, obj2); + const query = merge({}, obj1, obj2); const filters = query.Filters ? query.Filters.split(',') : []; if (filters.indexOf('IsNotFolder') === -1) { @@ -1798,15 +1799,15 @@ 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: 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 @@ -1814,7 +1815,7 @@ class PlaybackManager { SortBy: options.shuffle ? 'Random' : 'SortName', MediaTypes: 'Photo,Video', Limit: UNLIMITED_ITEMS - }).then(function (result) { + }, queryOptions)).then(function (result) { const playbackItems = result.Items; let index = playbackItems.map(function (i) { @@ -1830,7 +1831,7 @@ 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 @@ -1839,15 +1840,15 @@ class PlaybackManager { // 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: options.shuffle ? 'Random' : 'SortName', MediaTypes: 'Audio' - }); + }, queryOptions)); } else if (firstItem.Type === 'Series' || firstItem.Type === 'Season') { const apiClient = ServerConnections.getApiClient(firstItem.ServerId); diff --git a/src/components/shortcuts.js b/src/components/shortcuts.js index 7dc840e8b..58a7bffb0 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; @@ -177,6 +178,10 @@ function executeAction(card, target, action) { const item = getItemInfoFromCard(card); + const itemsContainer = dom.parentWithClass(card, 'itemsContainer'); + + const sortParentId = 'items-' + (item.IsFolder ? item.Id : itemsContainer?.getAttribute('data-parentid')) + '-Folder'; + const serverId = item.ServerId; const type = item.Type; @@ -200,12 +205,17 @@ 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 + serverId: serverId, + 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 0378a1025..5370bdcd6 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 { @@ -960,10 +965,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.getSortValuesLegacy(basekey, this.getDefaultSortBy()); } getDefaultSortBy() { diff --git a/src/scripts/settings/userSettings.js b/src/scripts/settings/userSettings.js index 9dc065621..2c40109fe 100644 --- a/src/scripts/settings/userSettings.js +++ b/src/scripts/settings/userSettings.js @@ -622,6 +622,21 @@ export class UserSettings { getFilter(key) { return this.get(key, true); } + + /** + * Gets the current sort values (Legacy - Non-JSON) + * (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) { + return { + sortBy: this.getFilter(key + '-sortby') || defaultSortBy, + sortOrder: this.getFilter(key + '-sortorder') === 'Descending' ? 'Descending' : 'Ascending' + }; + } } export const currentSettings = new UserSettings; @@ -672,3 +687,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 getSortValuesLegacy = currentSettings.getSortValuesLegacy.bind(currentSettings);