mirror of
https://github.com/ranaldsgift/KefinTweaks.git
synced 2026-11-05 15:52:47 +01:00
Fix multi-query previews, and ensure multi query merging respects section level sortby/sortorder
This commit is contained in:
@@ -6089,49 +6089,29 @@ window.KefinTweaksConfig = ${JSON.stringify(configToBackup, null, 2)};`;
|
||||
throw new Error('Section has no queries to preview');
|
||||
}
|
||||
|
||||
// Match home-screen selection: picker / random load one query; otherwise merge all
|
||||
const resolveQueries = window.cardBuilder.resolveQueriesToLoad;
|
||||
const queriesToLoad = typeof resolveQueries === 'function'
|
||||
? resolveQueries(previewSection, { initialize: true })
|
||||
: queries;
|
||||
if (typeof window.cardBuilder.refreshSectionQueries !== 'function') {
|
||||
throw new Error('Required dependencies not available for preview');
|
||||
}
|
||||
|
||||
const useSpotlightFields = options.useSpotlightFields === true
|
||||
|| previewSection.renderMode === 'Spotlight';
|
||||
const previewCopy = {
|
||||
...previewSection,
|
||||
queries: queries.map(withPreviewQueryOptions),
|
||||
renderMode: useSpotlightFields ? 'Spotlight' : previewSection.renderMode
|
||||
};
|
||||
|
||||
let allItems = [];
|
||||
for (const query of queriesToLoad) {
|
||||
const previewQuery = withPreviewQueryOptions(query);
|
||||
let queryUrl = null;
|
||||
|
||||
if (previewQuery.dataSource) {
|
||||
queryUrl = null;
|
||||
} else {
|
||||
queryUrl = window.apiHelper.buildQueryFromSection(previewQuery, userId, serverUrl, useSpotlightFields, { sectionType: previewSection.type });
|
||||
}
|
||||
|
||||
try {
|
||||
let items = [];
|
||||
if (previewQuery.dataSource) {
|
||||
const response = await window.apiHelper.fetchFromDataSource(previewQuery.dataSource, previewQuery.queryOptions, false);
|
||||
items = response.Items || response || [];
|
||||
} else if (queryUrl && typeof queryUrl === 'string') {
|
||||
const result = await apiHelper.getQuery(queryUrl, { useCache: false });
|
||||
items = result.Items || result || [];
|
||||
}
|
||||
allItems = allItems.concat(items);
|
||||
} catch (error) {
|
||||
console.error('[Preview] Error fetching query:', error);
|
||||
throw new Error(`Error fetching query: ${error.message}`);
|
||||
}
|
||||
let items;
|
||||
try {
|
||||
items = await window.cardBuilder.refreshSectionQueries(previewCopy);
|
||||
} catch (error) {
|
||||
console.error('[Preview] Error fetching query:', error);
|
||||
throw new Error(`Error fetching query: ${error.message}`);
|
||||
}
|
||||
|
||||
if (allItems.length === 0) {
|
||||
return { items: [], limit: 0, section: previewSection };
|
||||
}
|
||||
if (!Array.isArray(items)) items = [];
|
||||
|
||||
allItems = window.cardBuilder.postProcessItems(previewSection, allItems);
|
||||
|
||||
return { items: allItems, limit: 0, section: previewSection };
|
||||
return { items, limit: items.length, section: previewSection };
|
||||
}
|
||||
|
||||
const EDITOR_PREVIEW_SECTION_ID = 'hsae-editor-preview';
|
||||
|
||||
+29
-43
@@ -1264,58 +1264,44 @@
|
||||
* @returns {Object} - Merged result object with config, result.data, result.dataPromise, result.isStalePromise
|
||||
*/
|
||||
mergeMultiQueryResults: function(results, sectionConfig) {
|
||||
// Combine all items from all queries
|
||||
const allItems = [];
|
||||
const itemsByQuery = [];
|
||||
|
||||
results.forEach(result => {
|
||||
if (result.data?.Items) {
|
||||
allItems.push(...result.data.Items);
|
||||
itemsByQuery.push(result.data.Items);
|
||||
}
|
||||
});
|
||||
|
||||
// Sort merged items if sortBy specified
|
||||
/* if (sectionConfig.sortBy) {
|
||||
allItems.sort((a, b) => {
|
||||
const aVal = a[sectionConfig.sortBy] || (a.UserData?.[sectionConfig.sortBy] ? new Date(a.UserData[sectionConfig.sortBy]).getTime() : 0);
|
||||
const bVal = b[sectionConfig.sortBy] || (b.UserData?.[sectionConfig.sortBy] ? new Date(b.UserData[sectionConfig.sortBy]).getTime() : 0);
|
||||
|
||||
// Handle DatePlayed specifically for merged Continue/NextUp
|
||||
if (sectionConfig.sortBy === 'DatePlayed') {
|
||||
const aDate = a.UserData?.LastPlayedDate ? new Date(a.UserData.LastPlayedDate).getTime() : 0;
|
||||
const bDate = b.UserData?.LastPlayedDate ? new Date(b.UserData.LastPlayedDate).getTime() : 0;
|
||||
const comparison = aDate > bDate ? 1 : aDate < bDate ? -1 : 0;
|
||||
return sectionConfig.sortOrder === 'Descending' ? -comparison : comparison;
|
||||
}
|
||||
|
||||
const comparison = aVal > bVal ? 1 : aVal < bVal ? -1 : 0;
|
||||
return sectionConfig.sortOrder === 'Descending' ? -comparison : comparison;
|
||||
});
|
||||
} */
|
||||
|
||||
const queryPayloadItems = (data) => {
|
||||
if (!data) return [];
|
||||
if (Array.isArray(data)) return data;
|
||||
if (Array.isArray(data.Items)) return data.Items;
|
||||
if (Array.isArray(data.data?.Items)) return data.data.Items;
|
||||
return [];
|
||||
};
|
||||
// Skip the getQuery stub `{ Items: [] }` (empty arrays are truthy). Keep one slot per query.
|
||||
const syncQueryItems = (result) => {
|
||||
if (!result) return [];
|
||||
if (Array.isArray(result.Items) && result.Items.length > 0) return result.Items;
|
||||
const items = result.data?.Items;
|
||||
if (Array.isArray(items) && items.length > 0) return items;
|
||||
return [];
|
||||
};
|
||||
const itemsByQuery = (results || []).map((result) => syncQueryItems(result));
|
||||
const processLists = (lists) => window.cardBuilder.postProcessItemsByQuery(sectionConfig, lists);
|
||||
|
||||
let dataPromise = null;
|
||||
const ensureData = function() {
|
||||
if (!dataPromise) {
|
||||
dataPromise = Promise.all(results.map((r) => (
|
||||
typeof r.ensureData === 'function' ? r.ensureData() : r.dataPromise
|
||||
))).then((allData) => {
|
||||
const itemsByFreshQuery = [];
|
||||
allData.forEach((data) => {
|
||||
if (data?.Items) {
|
||||
itemsByFreshQuery.push(data.Items);
|
||||
}
|
||||
});
|
||||
return window.cardBuilder.postProcessItemsByQuery(sectionConfig, itemsByFreshQuery);
|
||||
dataPromise = Promise.all((results || []).map((r) => {
|
||||
if (!r) return Promise.resolve([]);
|
||||
if (typeof r.ensureData === 'function') return r.ensureData();
|
||||
if (r.dataPromise) return r.dataPromise;
|
||||
return Promise.resolve(r.data != null ? r.data : r);
|
||||
})).then((allData) => {
|
||||
const itemsByFreshQuery = allData.map((data) => queryPayloadItems(data));
|
||||
return { Items: processLists(itemsByFreshQuery) };
|
||||
});
|
||||
}
|
||||
return dataPromise;
|
||||
};
|
||||
|
||||
const mergedResult = {
|
||||
data: { Items: window.cardBuilder.postProcessItemsByQuery(sectionConfig, itemsByQuery) },
|
||||
isStale: results.some((r) => r.isStale),
|
||||
isStalePromise: Promise.all(results.map(r => r.isStalePromise || Promise.resolve(false)))
|
||||
data: { Items: processLists(itemsByQuery) },
|
||||
isStale: (results || []).some((r) => r && r.isStale),
|
||||
isStalePromise: Promise.all((results || []).map(r => r?.isStalePromise || Promise.resolve(false)))
|
||||
.then(staleFlags => staleFlags.some(s => s)),
|
||||
ensureData
|
||||
};
|
||||
|
||||
+217
-75
@@ -962,26 +962,106 @@
|
||||
return sortedContinueWatching;
|
||||
}
|
||||
|
||||
function postProcessItemsByQuery(sectionConfig, queryResults) {
|
||||
let processed = [];
|
||||
for (let i = 0; i < queryResults.length; i++) {
|
||||
const queryConfig = sectionConfig.queries[i];
|
||||
const queryResult = queryResults[i];
|
||||
const items = queryResult?.Items || queryResult || [];
|
||||
processed.push(...postProcessItems(queryConfig, items));
|
||||
function itemsFromQueryPayload(queryResult) {
|
||||
if (!queryResult) return [];
|
||||
if (Array.isArray(queryResult)) return queryResult;
|
||||
if (Array.isArray(queryResult.Items)) return queryResult.Items;
|
||||
return [];
|
||||
}
|
||||
|
||||
function mergedSectionItemLimit(sectionConfig) {
|
||||
const itemLimit = Number(sectionConfig?.itemLimit);
|
||||
if (itemLimit > 0) return itemLimit;
|
||||
const total = (sectionConfig?.queries || []).reduce((acc, query) => {
|
||||
const limit = Number(query?.queryOptions?.Limit);
|
||||
return acc + (limit > 0 ? limit : 0);
|
||||
}, 0);
|
||||
return total > 0 ? total : 0;
|
||||
}
|
||||
|
||||
function applyMergedSectionRules(sectionConfig, items) {
|
||||
let processed = Array.isArray(items) ? items : [];
|
||||
|
||||
if (sectionConfig.flattenSeries === true) {
|
||||
processed = flattenSeriesEpisodes(processed);
|
||||
}
|
||||
|
||||
if (sectionConfig.type === 'series-episodes' && Array.isArray(processed)) {
|
||||
processed = [...processed].sort((a, b) => (a.IndexNumber || 0) - (b.IndexNumber || 0));
|
||||
}
|
||||
|
||||
if (sectionConfig.id === 'continueWatchingAndNextUp') {
|
||||
// Get the movies from the items, and the rest as the episodes, then use mergeNextUpAndContinueWatching to merge them
|
||||
const movies = processed.filter((item) => item.Type === 'Movie');
|
||||
const episodes = processed.filter((item) => item.Type !== 'Movie');
|
||||
processed = mergeNextUpAndContinueWatching(episodes, movies);
|
||||
}
|
||||
|
||||
return processed;
|
||||
if (sectionConfig.id === 'upcoming') {
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
processed = processed.filter((item) => {
|
||||
if (!item.PremiereDate || item.LocationType !== 'Virtual') return false;
|
||||
const premiereDate = new Date(item.PremiereDate);
|
||||
premiereDate.setHours(0, 0, 0, 0);
|
||||
return premiereDate >= today;
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
sectionConfig.id === 'recentlyReleased.movies' ||
|
||||
sectionConfig.id === 'upcoming' ||
|
||||
sectionConfig.id === 'recentlyReleased.episodes'
|
||||
) {
|
||||
processed.forEach((item) => {
|
||||
if (item.PremiereDate) {
|
||||
item.CustomFooterText = formatAirDate(item.PremiereDate);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const sortBy = sectionConfig.sortBy != null ? String(sectionConfig.sortBy).trim() : '';
|
||||
const limit = mergedSectionItemLimit(sectionConfig);
|
||||
if (sortBy) {
|
||||
if (sortBy.toLowerCase() === 'random' && limit > 0 && sectionConfig.limitBeforeSort === true) {
|
||||
processed = processed.slice(0, limit);
|
||||
}
|
||||
processed = sortItems(processed, sortBy, sectionConfig.sortOrder || 'Ascending');
|
||||
}
|
||||
|
||||
if (limit > 0) {
|
||||
processed = processed.slice(0, limit);
|
||||
}
|
||||
|
||||
return deduplicateItems(processed);
|
||||
}
|
||||
|
||||
function postProcessItems(sectionConfig, itemsData) {
|
||||
function postProcessItemsByQuery(sectionConfig, queryResults) {
|
||||
let processed = [];
|
||||
const queries = sectionConfig?.queries || [];
|
||||
const lists = Array.isArray(queryResults) ? queryResults : [];
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
const query = queries[i];
|
||||
const items = itemsFromQueryPayload(lists[i]);
|
||||
if (!query) {
|
||||
processed.push(...items);
|
||||
continue;
|
||||
}
|
||||
processed.push(...postProcessItems({ queries: [query] }, items, { scope: 'query' }));
|
||||
}
|
||||
|
||||
const sortAndLimitOptions = {
|
||||
sortBy: sectionConfig.sortBy,
|
||||
sortOrder: sectionConfig.sortOrder,
|
||||
limit: mergedSectionItemLimit(sectionConfig),
|
||||
limitBeforeSort: sectionConfig.limitBeforeSort,
|
||||
handleAllSortingOptions: true
|
||||
};
|
||||
|
||||
return postProcessItems(sectionConfig, processed, sortAndLimitOptions);
|
||||
}
|
||||
|
||||
function postProcessItems(sectionConfig, itemsData, options = {}) {
|
||||
const { sortBy, sortOrder, limit, limitBeforeSort, handleAllSortingOptions } = options;
|
||||
let processed = itemsData?.Items || itemsData || [];
|
||||
|
||||
//Check if imageTypes is used in the query to ensure only items with these image types are included
|
||||
@@ -1051,20 +1131,7 @@
|
||||
processed = [...processed].sort((a, b) => (a.IndexNumber || 0) - (b.IndexNumber || 0));
|
||||
}
|
||||
|
||||
/* if (sectionConfig.id === 'popularTVNetworks') {
|
||||
// Sort items randomly
|
||||
processed = shuffle(processed);
|
||||
} */
|
||||
|
||||
if (sectionConfig.id === 'continueWatchingAndNextUp') {
|
||||
// Get the movies from the items, and the rest as the episodes, then use mergeNextUpAndContinueWatching to merge them
|
||||
const movies = processed.filter((item) => item.Type === 'Movie');
|
||||
const episodes = processed.filter((item) => item.Type !== 'Movie');
|
||||
processed = mergeNextUpAndContinueWatching(episodes, movies);
|
||||
}
|
||||
|
||||
if (sectionConfig.id === 'upcoming') {
|
||||
// Remove items which aired before today
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
processed = processed.filter((item) => {
|
||||
@@ -1075,7 +1142,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
// Add Custom Secondary Text for Recently Released Movies
|
||||
if (
|
||||
sectionConfig.id === 'recentlyReleased.movies' ||
|
||||
sectionConfig.id === 'upcoming' ||
|
||||
@@ -1088,56 +1154,138 @@
|
||||
});
|
||||
}
|
||||
|
||||
// Sort items by UserData.PlayedPercentage if PlayedPercentage is set as the SortBy
|
||||
if (sectionConfig.queries?.[0]?.queryOptions?.SortBy === 'PlayedPercentage') {
|
||||
if (sectionConfig.id === 'continueWatchingAndNextUp') {
|
||||
const movies = processed.filter((item) => item.Type === 'Movie');
|
||||
const episodes = processed.filter((item) => item.Type !== 'Movie');
|
||||
processed = mergeNextUpAndContinueWatching(episodes, movies);
|
||||
} else {
|
||||
const sortAndLimitOptions = {
|
||||
sortBy: sortBy || sectionConfig.queries?.[0]?.queryOptions?.SortBy,
|
||||
sortOrder: sortOrder || sectionConfig.queries?.[0]?.queryOptions?.SortOrder,
|
||||
limit: limit || Number(sectionConfig.queries?.[0]?.queryOptions?.Limit || 0),
|
||||
handleAllSortingOptions: handleAllSortingOptions,
|
||||
limitBeforeSort: limitBeforeSort
|
||||
};
|
||||
|
||||
processed = sortAndLimitItems(processed, sortAndLimitOptions);
|
||||
}
|
||||
|
||||
// Deduplicate items based on ProviderIds. Look for match imdb, tmdb or tvdb ids
|
||||
processed = deduplicateItems(processed);
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
function childCountSortValue(item) {
|
||||
return (item?.ChildCount || 0)
|
||||
+ (item?.SeriesCount || 0)
|
||||
+ (item?.EpisodeCount || 0)
|
||||
+ (item?.AlbumCount || 0)
|
||||
+ (item?.ArtistCount || 0)
|
||||
+ (item?.ProgramCount || 0)
|
||||
+ (item?.MovieCount || 0)
|
||||
+ (item?.SongCount || 0);
|
||||
}
|
||||
|
||||
const SORT_FIELD_GETTERS = {
|
||||
Name: { get: (item) => item?.Name, type: 'string' },
|
||||
SortName: { get: (item) => item?.SortName || item?.Name, type: 'string' },
|
||||
DateCreated: { get: (item) => item?.DateCreated, type: 'date' },
|
||||
PremiereDate: { get: (item) => item?.PremiereDate, type: 'date' },
|
||||
StartDate: { get: (item) => item?.StartDate, type: 'date' },
|
||||
DateLastContentAdded: { get: (item) => item?.DateLastContentAdded, type: 'date' },
|
||||
DatePlayed: { get: (item) => item?.UserData?.LastPlayedDate, type: 'date' },
|
||||
SeriesDatePlayed: { get: (item) => item?.UserData?.LastPlayedDate, type: 'date' },
|
||||
CommunityRating: { get: (item) => item?.CommunityRating, type: 'number' },
|
||||
CriticRating: { get: (item) => item?.CriticRating, type: 'number' },
|
||||
ProductionYear: { get: (item) => item?.ProductionYear, type: 'number' },
|
||||
Runtime: { get: (item) => item?.RunTimeTicks, type: 'number' },
|
||||
PlayCount: { get: (item) => item?.UserData?.PlayCount, type: 'number' },
|
||||
PlayedPercentage: { get: (item) => item?.UserData?.PlayedPercentage, type: 'number' },
|
||||
ParentIndexNumber: { get: (item) => item?.ParentIndexNumber, type: 'number' },
|
||||
IndexNumber: { get: (item) => item?.IndexNumber, type: 'number' },
|
||||
SimilarityScore: { get: (item) => item?.SimilarityScore, type: 'number' },
|
||||
SearchScore: { get: (item) => item?.SearchScore, type: 'number' },
|
||||
ChildCount: { get: childCountSortValue, type: 'number' },
|
||||
IsPlayed: { get: (item) => item?.UserData?.Played === true, type: 'boolean' },
|
||||
IsUnplayed: { get: (item) => item?.UserData?.Played !== true, type: 'boolean' },
|
||||
IsFolder: { get: (item) => item?.IsFolder === true, type: 'boolean' }
|
||||
};
|
||||
|
||||
function isMissingSortValue(value, type) {
|
||||
if (value == null || value === '') return true;
|
||||
if (type === 'number' && !Number.isFinite(Number(value))) return true;
|
||||
if (type === 'date' && Number.isNaN(new Date(value).getTime())) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function compareSortValues(aVal, bVal, type, descending) {
|
||||
const aMissing = isMissingSortValue(aVal, type);
|
||||
const bMissing = isMissingSortValue(bVal, type);
|
||||
if (aMissing && bMissing) return 0;
|
||||
if (aMissing) return 1;
|
||||
if (bMissing) return -1;
|
||||
let cmp = 0;
|
||||
if (type === 'string') {
|
||||
cmp = String(aVal).localeCompare(String(bVal), undefined, { sensitivity: 'base' });
|
||||
} else if (type === 'boolean') {
|
||||
cmp = (aVal ? 1 : 0) - (bVal ? 1 : 0);
|
||||
} else if (type === 'date') {
|
||||
cmp = new Date(aVal).getTime() - new Date(bVal).getTime();
|
||||
} else {
|
||||
cmp = Number(aVal) - Number(bVal);
|
||||
}
|
||||
return descending ? -cmp : cmp;
|
||||
}
|
||||
|
||||
function sortByFieldGetter(items, sortBy, order) {
|
||||
const field = SORT_FIELD_GETTERS[sortBy];
|
||||
if (!field) return items;
|
||||
const descending = order === 'Descending';
|
||||
return [...items].sort((a, b) => compareSortValues(field.get(a), field.get(b), field.type, descending));
|
||||
}
|
||||
|
||||
function sortAndLimitItems(items, options = { handleAllSortingOptions: false }) {
|
||||
const { sortBy, sortOrder, limit, limitBeforeSort, handleAllSortingOptions } = options;
|
||||
const order = sortOrder || 'Ascending';
|
||||
let processed = items;
|
||||
|
||||
if (limit > 0 && limitBeforeSort === true) {
|
||||
processed = processed.slice(0, limit);
|
||||
}
|
||||
|
||||
if (handleAllSortingOptions === true) {
|
||||
const field = sortBy != null ? String(sortBy).trim() : '';
|
||||
if (!field || field === 'Default') {
|
||||
// Leave concatenated order.
|
||||
} else if (field === 'Random') {
|
||||
processed = shuffle(processed);
|
||||
} else if (field === 'PlayedPercentage') {
|
||||
processed = processed.filter((item) => item.UserData?.PlayedPercentage && item.UserData?.PlayedPercentage > 0);
|
||||
processed = sortByFieldGetter(processed, field, order);
|
||||
} else {
|
||||
processed = sortByFieldGetter(processed, field, order);
|
||||
}
|
||||
} else if (sortBy === 'PlayedPercentage') {
|
||||
processed = processed.sort((a, b) => {
|
||||
const playedPercentageA = a.UserData?.PlayedPercentage || 0;
|
||||
const playedPercentageB = b.UserData?.PlayedPercentage || 0;
|
||||
return playedPercentageB - playedPercentageA;
|
||||
if (order === 'Descending') {
|
||||
return playedPercentageB - playedPercentageA;
|
||||
}
|
||||
return playedPercentageA - playedPercentageB;
|
||||
});
|
||||
|
||||
// Remove any items which have no UserData.PlayedPercentage
|
||||
processed = processed.filter((item) => item.UserData?.PlayedPercentage && item.UserData?.PlayedPercentage > 0);
|
||||
}
|
||||
|
||||
// Check for SortBy ChildCount and use ChildCount to sort the items
|
||||
// ChildCount = ChildCount + SeriesCount + EpisodeCount + AlbumCount + ArtistCount + ProgramCount + MovieCount + SongCount
|
||||
if (sectionConfig.queries?.[0]?.queryOptions?.SortBy === 'ChildCount') {
|
||||
} else if (sortBy === 'ChildCount') {
|
||||
processed = processed.sort((a, b) => {
|
||||
const childCountA =
|
||||
(a.ChildCount || 0) +
|
||||
(a.SeriesCount || 0) +
|
||||
(a.EpisodeCount || 0) +
|
||||
(a.AlbumCount || 0) +
|
||||
(a.ArtistCount || 0) +
|
||||
(a.ProgramCount || 0) +
|
||||
(a.MovieCount || 0) +
|
||||
(a.SongCount || 0);
|
||||
const childCountB =
|
||||
(b.ChildCount || 0) +
|
||||
(b.SeriesCount || 0) +
|
||||
(b.EpisodeCount || 0) +
|
||||
(b.AlbumCount || 0) +
|
||||
(b.ArtistCount || 0) +
|
||||
(b.ProgramCount || 0) +
|
||||
(b.MovieCount || 0) +
|
||||
(b.SongCount || 0);
|
||||
|
||||
if (sectionConfig.queries?.[0]?.queryOptions?.SortOrder === 'Descending') {
|
||||
const childCountA = childCountSortValue(a);
|
||||
const childCountB = childCountSortValue(b);
|
||||
if (order === 'Descending') {
|
||||
return childCountB - childCountA;
|
||||
}
|
||||
return childCountA - childCountB;
|
||||
});
|
||||
}
|
||||
|
||||
// Sum of all query limits
|
||||
const totalLimit = sectionConfig.queries?.reduce((acc, query) => acc + (query.queryOptions?.Limit || 0), 0);
|
||||
const limit = sectionConfig.itemLimit || totalLimit || 0;
|
||||
|
||||
if (sectionConfig.queries?.[0]?.queryOptions?.SortBy === 'Random' || sectionConfig.sortBy === 'Random') {
|
||||
if (limit > 0 && sectionConfig.limitBeforeSort === true) {
|
||||
processed = processed.slice(0, limit);
|
||||
}
|
||||
} else if (sortBy === 'Random') {
|
||||
processed = shuffle(processed);
|
||||
}
|
||||
|
||||
@@ -1146,9 +1294,6 @@
|
||||
processed = processed.slice(0, limit);
|
||||
}
|
||||
|
||||
// Deduplicate items based on ProviderIds. Look for match imdb, tmdb or tvdb ids
|
||||
processed = deduplicateItems(processed);
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
@@ -1387,11 +1532,7 @@
|
||||
const allData = await Promise.all(
|
||||
results.map((r) => r._refreshPromise || Promise.resolve(r.data)),
|
||||
);
|
||||
const itemsByFreshQuery = [];
|
||||
allData.forEach((data) => {
|
||||
if (data?.Items) itemsByFreshQuery.push(data.Items);
|
||||
else if (Array.isArray(data)) itemsByFreshQuery.push(data);
|
||||
});
|
||||
const itemsByFreshQuery = allData.map((data) => itemsFromQueryPayload(data));
|
||||
return postProcessItemsByQuery(sectionConfig, itemsByFreshQuery);
|
||||
}
|
||||
|
||||
@@ -1506,9 +1647,10 @@
|
||||
let finalResult;
|
||||
if (results.length > 1) {
|
||||
finalResult = ApiHelper.mergeMultiQueryResults(results, sectionConfig);
|
||||
// Extract items from merged result
|
||||
const items = finalResult.result?.data?.Items || finalResult.result?.data || [];
|
||||
return items;
|
||||
const settled = typeof finalResult.result?.ensureData === 'function'
|
||||
? await finalResult.result.ensureData()
|
||||
: finalResult.result?.data;
|
||||
return settled?.Items || [];
|
||||
} else if (results.length === 1) {
|
||||
// Single query result
|
||||
const data = results[0].data || results[0];
|
||||
|
||||
@@ -400,6 +400,17 @@
|
||||
return sortItemsByConfiguredIds(cfg, postProcessedItems);
|
||||
};
|
||||
|
||||
const itemsFromMerged = (raw) => {
|
||||
if (Array.isArray(raw?.Items)) return raw.Items;
|
||||
if (Array.isArray(raw)) return raw;
|
||||
return [];
|
||||
};
|
||||
|
||||
const finishMerged = (items) => {
|
||||
const filtered = applyExcludeItemIdFilter(sectionConfig, items);
|
||||
return sortItemsByConfiguredIds(sectionConfig, filtered);
|
||||
};
|
||||
|
||||
let mappedDataPromise = null;
|
||||
const result = {
|
||||
data: { Items: [] },
|
||||
@@ -463,19 +474,19 @@
|
||||
result.refreshPromise = Promise.all(
|
||||
results.map((r) => r._refreshPromise || Promise.resolve(r.data))
|
||||
).then((allData) => {
|
||||
const itemsByFreshQuery = [];
|
||||
allData.forEach((data) => {
|
||||
if (data?.Items) itemsByFreshQuery.push(data.Items);
|
||||
else if (Array.isArray(data)) itemsByFreshQuery.push(data);
|
||||
const itemsByFreshQuery = allData.map((data) => {
|
||||
if (Array.isArray(data?.Items)) return data.Items;
|
||||
if (Array.isArray(data)) return data;
|
||||
return [];
|
||||
});
|
||||
const mergedFresh = window.cardBuilder?.postProcessItemsByQuery
|
||||
? window.cardBuilder.postProcessItemsByQuery(sectionConfig, itemsByFreshQuery)
|
||||
: itemsByFreshQuery.flat();
|
||||
return postProcess(sectionConfig, mergedFresh);
|
||||
return finishMerged(mergedFresh);
|
||||
});
|
||||
}
|
||||
|
||||
return postProcess(sectionConfig, raw);
|
||||
return finishMerged(itemsFromMerged(raw));
|
||||
}
|
||||
|
||||
const queryResult = results[0];
|
||||
|
||||
Reference in New Issue
Block a user