diff --git a/configuration/homeScreen-configuration.js b/configuration/homeScreen-configuration.js index f97a65b..df8baf3 100644 --- a/configuration/homeScreen-configuration.js +++ b/configuration/homeScreen-configuration.js @@ -167,7 +167,7 @@ 'itemsLayout', 'useGaplessCards', 'sectionCssClass', 'hideName' ]; const RESTORE_ADVANCED_KEYS = [ - 'ttl', 'sortBy', 'sortOrder', 'sortOrderDirection', + 'ttl', 'sortBy', 'sortOrder', 'minimumItems', 'itemLimit', 'flattenSeries', 'limitBeforeSort', 'hideWatched' ]; const TTL_UNIT_OPTIONS = [ @@ -1444,6 +1444,63 @@ window.KefinTweaksConfig = ${JSON.stringify(configToBackup, null, 2)};`; return true; // flag always newly stamped → needs save } + // TEMPORARY: one-time overwrite of saved Kefin discovery sort fields from the new + // sortBy + sortOrder defaults. Remove in a future release once existing installs + // have picked up the patch (see discoverySortOrdersPatched). + // TODO(remove): patchDiscoverySortOrdersOnce + call site + discoverySortPatch log field + function patchDiscoverySortOrdersOnce(config) { + if (!window.KefinTweaksConfig) window.KefinTweaksConfig = {}; + if (window.KefinTweaksConfig.discoverySortOrdersPatched === true) return false; + if (!Array.isArray(window.KefinHomeConfig2?.DISCOVERY_SECTION_GROUPS)) return false; + + const canonicalMap = buildCanonicalSectionMapForGroups('DISCOVERY_SECTION_GROUPS'); + const isDirection = (value) => value === 'Ascending' || value === 'Descending'; + const topRatedQueryResetIds = new Set(['spotlightGenre', 'spotlightGenreSeries', 'spotlightNetwork']); + + const applySortPair = (target, canonical, fieldKey, directionKey) => { + if (!target || !canonical) return; + if (canonical[fieldKey]) target[fieldKey] = canonical[fieldKey]; + else delete target[fieldKey]; + + if (isDirection(canonical[directionKey])) target[directionKey] = canonical[directionKey]; + else delete target[directionKey]; + }; + + for (const group of config.DISCOVERY_SECTION_GROUPS || []) { + for (const section of group.sections || []) { + if (!section?.id) continue; + const canonical = canonicalMap.get(section.id); + if (!canonical) continue; + + applySortPair(section, canonical, 'sortBy', 'sortOrder'); + delete section.sortOrderDirection; + + const savedQueries = section.queries || []; + const canonicalQueries = canonical.queries || []; + const count = Math.min(savedQueries.length, canonicalQueries.length); + const replaceQueryOptions = topRatedQueryResetIds.has(section.id); + for (let i = 0; i < count; i++) { + const savedQuery = savedQueries[i]; + const canonicalQuery = canonicalQueries[i]; + if (!savedQuery || !canonicalQuery) continue; + if (replaceQueryOptions) { + savedQuery.queryOptions = JSON.parse(JSON.stringify(canonicalQuery.queryOptions || {})); + continue; + } + const canonicalOpts = canonicalQuery.queryOptions || {}; + if (!savedQuery.queryOptions) { + if (!canonicalOpts.SortBy && !isDirection(canonicalOpts.SortOrder)) continue; + savedQuery.queryOptions = {}; + } + applySortPair(savedQuery.queryOptions, canonicalOpts, 'SortBy', 'SortOrder'); + } + } + } + + window.KefinTweaksConfig.discoverySortOrdersPatched = true; + return true; // flag always newly stamped → needs save + } + async function ensureKefinTweaksDefaultSections() { try { if (!window.ApiClient || !window.ApiClient._loggedIn) { @@ -1477,8 +1534,10 @@ window.KefinTweaksConfig = ${JSON.stringify(configToBackup, null, 2)};`; const seasonalThemeChanges = syncSeasonalThemesFromDefaults(config); // TEMPORARY / TODO(remove): one-time liveTv-on-now Limit patch const liveTvLimitPatch = patchLiveTvOnNowLimitOnce(config); + // TEMPORARY / TODO(remove): one-time discovery sortBy/sortOrder overwrite + const discoverySortPatch = patchDiscoverySortOrdersOnce(config); - if (libraryChanges || addedDefaults || prunedOrphans || defaultSyncChanges || seasonalThemeChanges || liveTvLimitPatch) { + if (libraryChanges || addedDefaults || prunedOrphans || defaultSyncChanges || seasonalThemeChanges || liveTvLimitPatch || discoverySortPatch) { await saveConfig(config); LOG('KefinTweaks default home sections synced on startup', { libraryChanges, @@ -1486,7 +1545,8 @@ window.KefinTweaksConfig = ${JSON.stringify(configToBackup, null, 2)};`; prunedOrphans, defaultSyncChanges, seasonalThemeChanges, - liveTvLimitPatch + liveTvLimitPatch, + discoverySortPatch }); } } catch (error) { @@ -1919,6 +1979,11 @@ window.KefinTweaksConfig = ${JSON.stringify(configToBackup, null, 2)};`; ...(savedQuery.queryOptions || {}), ...currentQuery.queryOptions }; + ['SortBy', 'SortOrder'].forEach((key) => { + if (!Object.prototype.hasOwnProperty.call(currentQuery.queryOptions, key)) { + delete merged.queryOptions[key]; + } + }); } else if (savedQuery.queryOptions) { merged.queryOptions = JSON.parse(JSON.stringify(savedQuery.queryOptions)); } @@ -1992,6 +2057,12 @@ window.KefinTweaksConfig = ${JSON.stringify(configToBackup, null, 2)};`; merged[key] = currentSection[key]; } }); + + ['sortBy', 'sortOrder'].forEach((key) => { + if (!Object.prototype.hasOwnProperty.call(currentSection, key)) { + delete merged[key]; + } + }); // Ensure id is preserved from currentSection if (currentSection.id) { diff --git a/configuration/homeScreen-migration.js b/configuration/homeScreen-migration.js index 1a990ff..0a99698 100644 --- a/configuration/homeScreen-migration.js +++ b/configuration/homeScreen-migration.js @@ -628,8 +628,25 @@ found.section.isPlayed = legacySectionConfig.isPlayed; } if (legacySectionConfig.minimumItems !== undefined) found.section.minimumItems = legacySectionConfig.minimumItems; - if (legacySectionConfig.sortOrder !== undefined) found.section.sortOrder = legacySectionConfig.sortOrder; - if (legacySectionConfig.sortOrderDirection !== undefined) found.section.sortOrderDirection = legacySectionConfig.sortOrderDirection; + if (legacySectionConfig.sortOrder !== undefined) { + const legacySort = String(legacySectionConfig.sortOrder).trim(); + if (legacySort === 'Ascending' || legacySort === 'Descending') { + found.section.sortOrder = legacySort; + } else if (legacySort) { + found.section.sortBy = legacySort; + const existingOrder = found.section.sortOrder == null ? '' : String(found.section.sortOrder).trim(); + if (existingOrder !== 'Ascending' && existingOrder !== 'Descending') { + delete found.section.sortOrder; + } + } + } + if (legacySectionConfig.sortOrderDirection !== undefined) { + const legacyDirection = String(legacySectionConfig.sortOrderDirection).trim(); + if (legacyDirection === 'Ascending' || legacyDirection === 'Descending') { + found.section.sortOrder = legacyDirection; + } + } + delete found.section.sortOrderDirection; const isRecentlyWatchedPerson = RECENTLY_WATCHED_PERSON_IDS.has(sectionKey); if (legacySectionConfig.name !== undefined) { diff --git a/configuration/homeScreenAdvancedEditor.js b/configuration/homeScreenAdvancedEditor.js index a943133..f46b635 100644 --- a/configuration/homeScreenAdvancedEditor.js +++ b/configuration/homeScreenAdvancedEditor.js @@ -452,11 +452,26 @@ .replace(/([A-Z])([A-Z][a-z])/g, '$1 $2'); } + const SORT_BY_NONE = 'None'; + function toSortBySelectOptions(sortOrders) { - return (sortOrders || []).map(value => ({ - value, - label: humanizeSortOrderLabel(value) - })); + return [ + { value: SORT_BY_NONE, label: 'None' }, + ...(sortOrders || []).map(value => ({ + value, + label: humanizeSortOrderLabel(value) + })) + ]; + } + + function sortBySelectValue(stored) { + const value = stored == null ? '' : String(stored).trim(); + return value || SORT_BY_NONE; + } + + function isSortByNone(value) { + const by = value == null ? '' : String(value).trim(); + return !by || by === SORT_BY_NONE; } function getSectionSortOrderDirectionOptions(directions) { @@ -484,15 +499,63 @@ return allowed.includes(profile); } + const SECTION_SORT_DIRECTIONS = new Set(['Ascending', 'Descending']); + + function isSectionSortDirection(value) { + return SECTION_SORT_DIRECTIONS.has(String(value || '').trim()); + } + + /** + * Legacy sortOrder stored the field (Random, CommunityRating, …) and + * sortOrderDirection stored Ascending/Descending. Current model is + * sortBy = field, sortOrder = direction only. + */ + function normalizeSectionSortFields(section) { + if (!section || typeof section !== 'object') return section; + const order = section.sortOrder == null ? '' : String(section.sortOrder).trim(); + const legacyDirection = section.sortOrderDirection == null ? '' : String(section.sortOrderDirection).trim(); + + if (order && !isSectionSortDirection(order)) { + if (!section.sortBy) section.sortBy = order; + delete section.sortOrder; + } + if (isSectionSortDirection(legacyDirection)) { + section.sortOrder = legacyDirection; + } + delete section.sortOrderDirection; + return section; + } + function applySectionLevelSort(section, sortBy, sortOrder) { const by = sortBy == null ? '' : String(sortBy).trim(); const order = sortOrder == null ? '' : String(sortOrder).trim(); + delete section.sortOrderDirection; - if (!by || by === 'Default') delete section.sortBy; - else section.sortBy = by; + if (isSortByNone(by)) { + delete section.sortBy; + delete section.sortOrder; + return; + } - if (!order || order === 'Default') delete section.sortOrder; - else section.sortOrder = order; + section.sortBy = by; + if (isSectionSortDirection(order)) section.sortOrder = order; + else delete section.sortOrder; + } + + function applyCollectedQuerySort(queryOptions, sortBy, sortOrder) { + if (!queryOptions) return; + const by = sortBy == null ? '' : String(sortBy).trim(); + const order = sortOrder == null ? '' : String(sortOrder).trim(); + + if (isSortByNone(by)) { + delete queryOptions.SortBy; + delete queryOptions.SortOrder; + return; + } + + queryOptions.SortBy = by; + if (isSectionSortDirection(order)) queryOptions.SortOrder = order; + else delete queryOptions.SortOrder; } function resolvePremiereAgeFields(section) { @@ -513,19 +576,14 @@ } } - const sortByEl = dialog.querySelector('#hsae-advanced-sortBy'); - if (isProfileFieldActive(root, sortByEl)) { - const sortVal = sortByEl?.value; - delete section.sortBy; - if (sortVal && sortVal !== 'Default') section.sortOrder = sortVal; - else delete section.sortOrder; - } + normalizeSectionSortFields(section); + const sortByEl = dialog.querySelector('#hsae-advanced-sortBy'); const sortDirEl = dialog.querySelector('#hsae-advanced-sortOrder'); - if (isProfileFieldActive(root, sortDirEl)) { - const dirVal = sortDirEl?.value; - if (dirVal && dirVal !== 'Default') section.sortOrderDirection = dirVal; - else delete section.sortOrderDirection; + if (isProfileFieldActive(root, sortByEl)) { + applySectionLevelSort(section, sortByEl?.value, sortDirEl?.value); + } else { + delete section.sortOrderDirection; } } @@ -545,10 +603,12 @@ const sortByEl = dialog.querySelector('#hsae-advanced-sortBy'); const sortOrderEl = dialog.querySelector('#hsae-advanced-sortOrder'); + normalizeSectionSortFields(section); if (isProfileFieldActive(root, sortByEl) && !isDiscoverySection(section)) { if (section.useRandomQuery) { delete section.sortBy; delete section.sortOrder; + delete section.sortOrderDirection; } else { applySectionLevelSort(section, sortByEl?.value, sortOrderEl?.value); } @@ -991,9 +1051,13 @@ const renderMode = section.renderMode || (section.spotlight ? 'Spotlight' : 'Normal'); const ttlMatch = matchTtlPreset(section.ttl); const groupSelection = resolveGroupSelection(section, context); - const isDiscovery = isDiscoverySection(section); - const sectionSortBy = section.sortBy || (isDiscovery ? section.sortOrder : '') || ''; - const sectionSortOrder = isDiscovery ? (section.sortOrderDirection || '') : (section.sortOrder || ''); + const normalizedSort = normalizeSectionSortFields({ + sortBy: section.sortBy, + sortOrder: section.sortOrder, + sortOrderDirection: section.sortOrderDirection + }); + const sectionSortBy = normalizedSort.sortBy || ''; + const sectionSortOrder = isSectionSortDirection(normalizedSort.sortOrder) ? normalizedSort.sortOrder : ''; return { section, @@ -1540,7 +1604,7 @@
- ${buildSelect(`query-${index}-SortBy`, toSortBySelectOptions(SORT_ORDERS), queryOptions.SortBy || '', 'Sort By')} + ${buildSelect(`query-${index}-SortBy`, toSortBySelectOptions(SORT_ORDERS), sortBySelectValue(queryOptions.SortBy), 'Sort By')}
${buildSelect(`query-${index}-SortOrder`, SORT_ORDER_DIRECTIONS, queryOptions.SortOrder || '', 'Sort Order')} @@ -2310,7 +2374,7 @@
- ${buildSelect('hsae-advanced-sortBy', toSortBySelectOptions(SORT_ORDERS), state.sortBy || '', 'Sort By')} + ${buildSelect('hsae-advanced-sortBy', toSortBySelectOptions(SORT_ORDERS), sortBySelectValue(state.sortBy), 'Sort By')}
Items will be sorted in this order after they are returned from Jellyfin.
@@ -2442,12 +2506,11 @@ } } if (isProfileFieldActive(root, sortByEl)) { - const sortBy = sortByEl?.value; - const sortOrder = editor.querySelector(`#query-${queryIndex}-SortOrder`)?.value; - if (sortBy) query.queryOptions.SortBy = sortBy; - else delete query.queryOptions.SortBy; - if (sortOrder) query.queryOptions.SortOrder = sortOrder; - else delete query.queryOptions.SortOrder; + applyCollectedQuerySort( + query.queryOptions, + sortByEl?.value, + editor.querySelector(`#query-${queryIndex}-SortOrder`)?.value + ); } if (hideWatched) query.queryOptions.IsUnplayed = true; else if (query.queryOptions) delete query.queryOptions.IsUnplayed; @@ -2467,10 +2530,11 @@ if (staticItems.length) { query.queryOptions.Ids = staticItems.map(item => item.id); } - ['SortBy', 'SortOrder'].forEach(key => { - const value = editor.querySelector(`#query-${queryIndex}-${key}`)?.value; - if (value) query.queryOptions[key] = value; - }); + applyCollectedQuerySort( + query.queryOptions, + editor.querySelector(`#query-${queryIndex}-SortBy`)?.value, + editor.querySelector(`#query-${queryIndex}-SortOrder`)?.value + ); return query; } @@ -2479,10 +2543,11 @@ || CACHE_SOURCE_OPTIONS[0]?.value; if (dataSource) query.dataSource = dataSource; query.queryOptions = {}; - ['SortBy', 'SortOrder'].forEach(key => { - const value = editor.querySelector(`#query-${queryIndex}-${key}`)?.value; - if (value) query.queryOptions[key] = value; - }); + applyCollectedQuerySort( + query.queryOptions, + editor.querySelector(`#query-${queryIndex}-SortBy`)?.value, + editor.querySelector(`#query-${queryIndex}-SortOrder`)?.value + ); const limit = editor.querySelector(`#query-${queryIndex}-Limit`)?.value; if (limit !== '' && limit != null) { const limitN = parseInt(limit, 10); @@ -2550,7 +2615,12 @@ delete query.queryOptions.PlaylistIds; delete query.queryOptions._parentItemType; - ['SortBy', 'SortOrder', 'Filters', 'SearchTerm'].forEach(key => { + applyCollectedQuerySort( + query.queryOptions, + editor.querySelector(`#query-${queryIndex}-SortBy`)?.value, + editor.querySelector(`#query-${queryIndex}-SortOrder`)?.value + ); + ['Filters', 'SearchTerm'].forEach(key => { const value = editor.querySelector(`#query-${queryIndex}-${key}`)?.value; if (value) query.queryOptions[key] = value; }); @@ -3651,7 +3721,7 @@ 'name', 'caption', 'description', 'enabled', 'order', 'cardFormat', 'renderMode', 'ttl', 'queries', 'items', 'externalListUrls', 'spotlightConfig', 'hideName', 'userConfigurable', 'useRandomQuery', 'useMultiQueryPicker', 'multiQueryPickerLabel', 'useQueryNamesForSection', - 'sortBy', 'sortOrder', 'sortOrderDirection', 'itemLimit', 'minimumItems', 'flattenSeries', + 'sortBy', 'sortOrder', 'itemLimit', 'minimumItems', 'flattenSeries', 'limitBeforeSort', 'sectionCssClass', 'borderStyle', 'borderColor', 'cardTitleColor', 'itemsLayout', 'useGaplessCards', 'cardTitleVisibility', 'useParentCard', 'cardTitlePosition', 'cardTitleCapitalization', 'cardTitleFontFamily', 'cardTitleFontSize', 'startDate', 'endDate', @@ -3959,6 +4029,8 @@ function diffSectionAgainstDefault(current, canonical) { const diffs = []; if (!current || !canonical) return diffs; + current = normalizeSectionSortFields({ ...current }); + canonical = normalizeSectionSortFields({ ...canonical }); for (const key of HSAE_SECTION_DIFF_KEYS) { const hasCurrent = Object.prototype.hasOwnProperty.call(current, key); const hasCanonical = Object.prototype.hasOwnProperty.call(canonical, key); diff --git a/scripts/homeScreenConfig2.js b/scripts/homeScreenConfig2.js index 45b5386..01dda2d 100644 --- a/scripts/homeScreenConfig2.js +++ b/scripts/homeScreenConfig2.js @@ -1814,7 +1814,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -1881,7 +1881,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -1912,7 +1912,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -1943,7 +1943,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -1989,7 +1989,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2028,7 +2028,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2067,7 +2067,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2110,7 +2110,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ { @@ -2144,7 +2144,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2178,7 +2178,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2212,7 +2212,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2251,7 +2251,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2294,7 +2294,7 @@ Recursive: true, IncludeItemTypes: ["Series"], MinCommunityRating: 7.5, - Limit: 20, + Limit: 100, Fields: DISCOVERY_CONTENT_FIELDS, }, }, @@ -2328,7 +2328,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ { @@ -2363,7 +2363,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2435,7 +2435,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ { @@ -2468,7 +2468,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2502,7 +2502,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2536,7 +2536,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2563,7 +2563,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2599,7 +2599,7 @@ enabled: false, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Thumb", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2631,7 +2631,7 @@ enabled: false, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Thumb", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2663,7 +2663,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2708,7 +2708,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Poster", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2747,7 +2747,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Thumb", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2787,7 +2787,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Thumb", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ @@ -2834,7 +2834,7 @@ enabled: true, userConfigurable: true, itemLimit: 20, - sortOrder: "Random", + sortBy: "Random", cardFormat: "Thumb", ttl: CACHE_CONFIG.DISCOVERY_TTL, queries: [ diff --git a/scripts/sectionHelper.js b/scripts/sectionHelper.js index b196c1d..811db6b 100644 --- a/scripts/sectionHelper.js +++ b/scripts/sectionHelper.js @@ -8,6 +8,24 @@ const ERR = (...args) => console.error('[KefinTweaks SectionHelper]', ...args); const ApiHelper = window.apiHelper || window.ApiHelper; + + function isSortDirectionValue(value) { + const v = value == null ? '' : String(value).trim(); + return v === 'Ascending' || v === 'Descending'; + } + + /** Legacy sortOrder was the field; sortOrder is now Ascending/Descending only. */ + function normalizeInstanceSort(instanceConfig) { + const sortBy = instanceConfig?.sortBy == null ? '' : String(instanceConfig.sortBy).trim(); + const order = instanceConfig?.sortOrder == null ? '' : String(instanceConfig.sortOrder).trim(); + const legacyDirection = instanceConfig?.sortOrderDirection == null + ? '' + : String(instanceConfig.sortOrderDirection).trim(); + const out = { sortBy, sortOrder: isSortDirectionValue(order) ? order : '' }; + if (order && !isSortDirectionValue(order) && !out.sortBy) out.sortBy = order; + if (isSortDirectionValue(legacyDirection)) out.sortOrder = legacyDirection; + return out; + } const Config = () => window.KefinHomeConfig2 || window.KefinHomeScreen?.getConfig?.() || {}; const discoveryState = { @@ -1213,8 +1231,9 @@ }; if (!hasTemplateQueries) { - if (instanceConfig.sortOrder) queryOptions.SortBy = instanceConfig.sortOrder; - if (instanceConfig.sortOrderDirection) queryOptions.SortOrder = instanceConfig.sortOrderDirection; + const sort = normalizeInstanceSort(instanceConfig); + if (sort.sortBy) queryOptions.SortBy = sort.sortBy; + if (sort.sortOrder) queryOptions.SortOrder = sort.sortOrder; } else if (!queryOptions.IncludeItemTypes?.length) { queryOptions.IncludeItemTypes = contentTypes; }