mirror of
https://github.com/ranaldsgift/KefinTweaks.git
synced 2026-11-05 15:52:47 +01:00
Store Person images in person cache and move client cache args to "dataSourceOptions" instead of queryOptions
This commit is contained in:
+31
-4
@@ -1069,7 +1069,11 @@
|
||||
}
|
||||
|
||||
if (query.dataSource) {
|
||||
return { dataSource: query.dataSource, options: queryOptions };
|
||||
return {
|
||||
dataSource: query.dataSource,
|
||||
options: queryOptions,
|
||||
dataSourceOptions: query.dataSourceOptions || {}
|
||||
};
|
||||
}
|
||||
|
||||
return this.buildStandardQuery(queryOptions, userId, serverUrl, buildContext);
|
||||
@@ -1141,15 +1145,38 @@
|
||||
return `${serverUrl}${path}?${params.toString()}`;
|
||||
},
|
||||
|
||||
/**
|
||||
* Resolve args for a cache dataSource method.
|
||||
* Prefers explicit dataSourceOptions; falls back to legacy ItemType/MinCount in queryOptions.
|
||||
*/
|
||||
resolveDataSourceMethodArgs: function(dataSourceOptions, queryOptions) {
|
||||
if (dataSourceOptions && typeof dataSourceOptions === 'object') {
|
||||
const keys = Object.keys(dataSourceOptions);
|
||||
if (keys.length) return { ...dataSourceOptions };
|
||||
}
|
||||
const qo = queryOptions || {};
|
||||
const out = {};
|
||||
if (qo.ItemType != null && qo.ItemType !== '') out.ItemType = qo.ItemType;
|
||||
else if (qo.itemType != null && qo.itemType !== '') out.ItemType = qo.itemType;
|
||||
if (qo.MinCount != null && qo.MinCount !== '') out.MinCount = qo.MinCount;
|
||||
else if (qo.minCount != null && qo.minCount !== '') out.MinCount = qo.minCount;
|
||||
else if (qo.minimumSeries != null && qo.minimumSeries !== '') out.minimumSeries = qo.minimumSeries;
|
||||
return out;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch from data source (cache-based)
|
||||
* @param {string} dataSource - Data source in format "CacheName.methodName"
|
||||
* @param {Object} options - Query options (sorting, limits, etc.)
|
||||
* @param {Object} queryOptions - Post-processing options (SortBy, SortOrder, Limit, etc.)
|
||||
* @param {boolean} [useCache=true]
|
||||
* @param {Object} [dataSourceOptions] - Args passed to the cache method (e.g. ItemType, MinCount)
|
||||
* @returns {Object} - Object with data, dataPromise, and isStalePromise
|
||||
*/
|
||||
fetchFromDataSource: async function(dataSource, options, useCache = true) {
|
||||
fetchFromDataSource: async function(dataSource, queryOptions, useCache = true, dataSourceOptions) {
|
||||
const [cacheName, methodName] = dataSource.split('.');
|
||||
const cache = window[cacheName];
|
||||
const options = queryOptions || {};
|
||||
const methodArgs = this.resolveDataSourceMethodArgs(dataSourceOptions, options);
|
||||
|
||||
if (!cache || !cache[methodName]) {
|
||||
WARN(`Data source not available: ${dataSource}`);
|
||||
@@ -1161,7 +1188,7 @@
|
||||
}
|
||||
|
||||
try {
|
||||
let dataPromise = Promise.resolve(cache[methodName](options));
|
||||
let dataPromise = Promise.resolve(cache[methodName](methodArgs));
|
||||
dataPromise = dataPromise.then(data => {
|
||||
if (!Array.isArray(data)) {
|
||||
data = [];
|
||||
|
||||
+12
-2
@@ -1138,7 +1138,12 @@
|
||||
let queryResult;
|
||||
|
||||
if (query.dataSource) {
|
||||
queryResult = await ApiHelper.fetchFromDataSource(query.dataSource, query.queryOptions || {});
|
||||
queryResult = await ApiHelper.fetchFromDataSource(
|
||||
query.dataSource,
|
||||
query.queryOptions || {},
|
||||
true,
|
||||
query.dataSourceOptions
|
||||
);
|
||||
} else {
|
||||
const queryUrl = ApiHelper.buildQueryFromSection(
|
||||
query,
|
||||
@@ -1234,7 +1239,12 @@
|
||||
|
||||
if (query.dataSource) {
|
||||
// Handle cache-based data sources
|
||||
queryResult = await ApiHelper.fetchFromDataSource(query.dataSource, query.queryOptions || {}, false);
|
||||
queryResult = await ApiHelper.fetchFromDataSource(
|
||||
query.dataSource,
|
||||
query.queryOptions || {},
|
||||
false,
|
||||
query.dataSourceOptions
|
||||
);
|
||||
} else {
|
||||
// Build and execute query
|
||||
const queryUrl = ApiHelper.buildQueryFromSection(query, userId, serverUrl, sectionConfig.renderMode === 'Spotlight', { sectionType: sectionConfig.type });
|
||||
|
||||
@@ -1365,7 +1365,8 @@
|
||||
discoveryItemType: 'Movie',
|
||||
discoverySourceQuery: {
|
||||
dataSource: 'PeopleCache.getTopDirectors',
|
||||
queryOptions: { ItemType: 'Movie', Limit: 100 }
|
||||
dataSourceOptions: { ItemType: 'Movie' },
|
||||
queryOptions: { Limit: 100 }
|
||||
},
|
||||
name: 'Directed by {Person}',
|
||||
enabled: true,
|
||||
@@ -1392,7 +1393,8 @@
|
||||
discoveryItemType: 'Movie',
|
||||
discoverySourceQuery: {
|
||||
dataSource: 'PeopleCache.getTopWriters',
|
||||
queryOptions: { ItemType: 'Movie', Limit: 100 }
|
||||
dataSourceOptions: { ItemType: 'Movie' },
|
||||
queryOptions: { Limit: 100 }
|
||||
},
|
||||
name: 'Written by {Person}',
|
||||
enabled: true,
|
||||
@@ -1419,7 +1421,8 @@
|
||||
discoveryItemType: 'Movie',
|
||||
discoverySourceQuery: {
|
||||
dataSource: 'PeopleCache.getTopActors',
|
||||
queryOptions: { ItemType: 'Movie', Limit: 100 }
|
||||
dataSourceOptions: { ItemType: 'Movie' },
|
||||
queryOptions: { Limit: 100 }
|
||||
},
|
||||
name: 'Starring {Person}',
|
||||
enabled: true,
|
||||
@@ -1970,7 +1973,8 @@
|
||||
discoveryItemType: 'Series',
|
||||
discoverySourceQuery: {
|
||||
dataSource: 'PeopleCache.getTopDirectors',
|
||||
queryOptions: { ItemType: 'Series', Limit: 100 }
|
||||
dataSourceOptions: { ItemType: 'Series' },
|
||||
queryOptions: { Limit: 100 }
|
||||
},
|
||||
name: 'Directed by {Person}',
|
||||
enabled: false,
|
||||
@@ -1998,7 +2002,8 @@
|
||||
discoveryItemType: 'Series',
|
||||
discoverySourceQuery: {
|
||||
dataSource: 'PeopleCache.getTopWriters',
|
||||
queryOptions: { ItemType: 'Series', Limit: 100 }
|
||||
dataSourceOptions: { ItemType: 'Series' },
|
||||
queryOptions: { Limit: 100 }
|
||||
},
|
||||
name: 'Written by {Person}',
|
||||
enabled: false,
|
||||
@@ -2026,7 +2031,8 @@
|
||||
discoveryItemType: 'Series',
|
||||
discoverySourceQuery: {
|
||||
dataSource: 'PeopleCache.getTopActors',
|
||||
queryOptions: { ItemType: 'Series', Limit: 100 }
|
||||
dataSourceOptions: { ItemType: 'Series' },
|
||||
queryOptions: { Limit: 100 }
|
||||
},
|
||||
name: 'Starring {Person}',
|
||||
enabled: true,
|
||||
|
||||
@@ -5,12 +5,17 @@
|
||||
|
||||
function stripPerson(person) {
|
||||
if (!person) return null;
|
||||
return {
|
||||
const out = {
|
||||
Name: person.Name,
|
||||
Id: person.Id,
|
||||
Role: person.Role,
|
||||
Type: person.Type
|
||||
};
|
||||
if (person.PrimaryImageTag) out.PrimaryImageTag = person.PrimaryImageTag;
|
||||
if (person.ImageBlurHashes?.Primary) {
|
||||
out.ImageBlurHashes = { Primary: person.ImageBlurHashes.Primary };
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function stripChapter(chapter) {
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
const WARN = (...args) => console.warn('[KefinTweaks Movies Cache]', ...args);
|
||||
const ERR = (...args) => console.error('[KefinTweaks Movies Cache]', ...args);
|
||||
|
||||
const CACHE_NAME = 'movies_library';
|
||||
const PARTIAL_CACHE_NAME = 'movies_library_partial';
|
||||
const CACHE_NAME = 'movies_library_v2';
|
||||
const PARTIAL_CACHE_NAME = 'movies_library_partial_v2';
|
||||
const LAST_FETCH_KEY_PREFIX = 'kefinTweaks_lastDateFetchedMovieCache_';
|
||||
const IMDB_TOP_250_CACHE_TTL = 24 * 60 * 60 * 1000;
|
||||
const MOVIE_FIELDS = [
|
||||
'ProviderIds', 'People', 'Studios', 'Taglines', 'Genres', 'Overview', 'PrimaryImageAspectRatio',
|
||||
'DateCreated', 'DateLastMediaAdded'
|
||||
'ImageBlurHashes', 'DateCreated', 'DateLastMediaAdded'
|
||||
].join(',');
|
||||
|
||||
let movies = null;
|
||||
@@ -116,7 +116,7 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* Full crawl with partial resume. Commits to movies_library only when complete.
|
||||
* Full crawl with partial resume. Commits to movies_library_v2 only when complete.
|
||||
*/
|
||||
async function fetchAndCacheMovies() {
|
||||
const cache = window.IndexedDBCache;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
const WARN = (...args) => console.warn('[KefinTweaks PeopleCache]', ...args);
|
||||
const ERR = (...args) => console.error('[KefinTweaks PeopleCache]', ...args);
|
||||
|
||||
const CACHE_NAME = 'library_top_people_v3';
|
||||
const CACHE_NAME = 'library_top_people_v4';
|
||||
const DEFAULT_MIN = 10;
|
||||
const DEFAULT_PER_TYPE_MAX = 100;
|
||||
const EPISODE_CHUNK_SIZE = 500;
|
||||
@@ -337,7 +337,7 @@
|
||||
const params = new URLSearchParams({
|
||||
IncludeItemTypes: 'Episode',
|
||||
Recursive: 'true',
|
||||
Fields: 'People',
|
||||
Fields: 'People,ImageBlurHashes',
|
||||
ExcludeLocationTypes: 'Virtual',
|
||||
EnableTotalRecordCount: 'false',
|
||||
SortBy: 'DateCreated',
|
||||
@@ -906,7 +906,12 @@
|
||||
if (personType === 'Director') list = filterRoleList('Director', itemType);
|
||||
else if (personType === 'Writer') list = filterRoleList('Writer', itemType);
|
||||
else list = filterRoleList('Actor', itemType);
|
||||
return list.slice(0, limit).map((p) => ({ Id: p.Id, Name: p.Name, Type: 'Person' }));
|
||||
return list.slice(0, limit).map((p) => {
|
||||
const out = { Id: p.Id, Name: p.Name, Type: 'Person' };
|
||||
if (p.PrimaryImageTag) out.PrimaryImageTag = p.PrimaryImageTag;
|
||||
if (p.ImageBlurHashes) out.ImageBlurHashes = p.ImageBlurHashes;
|
||||
return out;
|
||||
});
|
||||
}
|
||||
|
||||
async function waitForLoginReady(maxWaitMs = 60000) {
|
||||
|
||||
@@ -273,7 +273,12 @@
|
||||
let queryResult;
|
||||
|
||||
if (query.dataSource) {
|
||||
queryResult = await ApiHelper.fetchFromDataSource(query.dataSource, query.queryOptions || {});
|
||||
queryResult = await ApiHelper.fetchFromDataSource(
|
||||
query.dataSource,
|
||||
query.queryOptions || {},
|
||||
true,
|
||||
query.dataSourceOptions
|
||||
);
|
||||
} else {
|
||||
const queryUrl = ApiHelper.buildQueryFromSection(query, userId, serverUrl, sectionConfig.renderMode === 'Spotlight', { sectionType: sectionConfig.type });
|
||||
|
||||
@@ -575,7 +580,8 @@
|
||||
: 'getTopActors';
|
||||
return {
|
||||
dataSource: `PeopleCache.${method}`,
|
||||
queryOptions: { ItemType: itemType, Limit: 100 }
|
||||
dataSourceOptions: { ItemType: itemType },
|
||||
queryOptions: { Limit: 100 }
|
||||
};
|
||||
}
|
||||
if (discoveryType === 'Similar' || discoveryType === 'Watchlist') {
|
||||
@@ -676,7 +682,12 @@
|
||||
const built = ApiHelper.buildQueryFromSection(sourceQuery, userId, serverUrl, false);
|
||||
|
||||
if (typeof built === 'object' && built.dataSource) {
|
||||
const result = await ApiHelper.fetchFromDataSource(built.dataSource, built.options || {}, false);
|
||||
const result = await ApiHelper.fetchFromDataSource(
|
||||
built.dataSource,
|
||||
built.options || {},
|
||||
false,
|
||||
built.dataSourceOptions
|
||||
);
|
||||
return unwrapQueryItems(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
const WARN = (...args) => console.warn('[KefinTweaks Series Cache]', ...args);
|
||||
const ERR = (...args) => console.error('[KefinTweaks Series Cache]', ...args);
|
||||
|
||||
const CACHE_NAME = 'series_library';
|
||||
const PARTIAL_CACHE_NAME = 'series_library_partial';
|
||||
const CACHE_NAME = 'series_library_v2';
|
||||
const PARTIAL_CACHE_NAME = 'series_library_partial_v2';
|
||||
const LAST_FETCH_KEY_PREFIX = 'kefinTweaks_lastDateFetchedSeriesCache_';
|
||||
const SERIES_FIELDS = [
|
||||
'ProviderIds', 'People', 'Studios', 'Taglines', 'Genres', 'Overview',
|
||||
'PrimaryImageAspectRatio', 'ChildCount', 'RecursiveItemCount'
|
||||
'PrimaryImageAspectRatio', 'ImageBlurHashes', 'ChildCount', 'RecursiveItemCount'
|
||||
].join(',');
|
||||
|
||||
let series = null;
|
||||
|
||||
+19
-9
@@ -83,22 +83,32 @@
|
||||
|
||||
/**
|
||||
* Gets popular TV networks (studios) filtered by minimum series count
|
||||
* @param {number} minimumSeries - Minimum number of series required (default: 0, returns all)
|
||||
* @param {number|{ MinCount?: number, minCount?: number, minimumSeries?: number }} minOrOptions
|
||||
* Minimum series count, or queryOptions bag from fetchFromDataSource
|
||||
* @returns {Promise<Array>} - Array of studios meeting the minimum threshold
|
||||
*/
|
||||
async function getPopularTVNetworks(minimumSeries) {
|
||||
if (!minimumSeries) {
|
||||
minimumSeries = window.KefinTweaksConfig?.HOME_SETTINGS?.minimumSeriesForPopularTVNetworks ?? window.KefinHomeConfig2?.HOME_SETTINGS?.minimumSeriesForPopularTVNetworks;
|
||||
async function getPopularTVNetworks(minOrOptions) {
|
||||
let minimumSeries;
|
||||
if (minOrOptions && typeof minOrOptions === 'object') {
|
||||
minimumSeries = minOrOptions.MinCount ?? minOrOptions.minCount ?? minOrOptions.minimumSeries;
|
||||
} else {
|
||||
minimumSeries = minOrOptions;
|
||||
}
|
||||
|
||||
if (minimumSeries == null || minimumSeries === '') {
|
||||
minimumSeries = window.KefinTweaksConfig?.HOME_SETTINGS?.minimumSeriesForPopularTVNetworks
|
||||
?? window.KefinHomeConfig2?.HOME_SETTINGS?.minimumSeriesForPopularTVNetworks;
|
||||
}
|
||||
|
||||
const studios = await getSeriesStudios();
|
||||
|
||||
if (minimumSeries > 0) {
|
||||
return studios.filter(studio =>
|
||||
(studio.SeriesCount || studio.ChildCount || 0) >= minimumSeries
|
||||
const threshold = Number(minimumSeries);
|
||||
|
||||
if (Number.isFinite(threshold) && threshold > 0) {
|
||||
return studios.filter(studio =>
|
||||
(studio.SeriesCount || studio.ChildCount || 0) >= threshold
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return studios;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user