mirror of
https://github.com/ranaldsgift/KefinTweaks.git
synced 2026-11-05 15:52:47 +01:00
Add and update data caches: Movies, People, Studios
This commit is contained in:
@@ -87,6 +87,43 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Get cached data entry (payload + metadata) if valid
|
||||
async getCacheEntry(cacheName, userId = null) {
|
||||
const key = this.getCacheKey(cacheName, userId);
|
||||
|
||||
try {
|
||||
const db = await this.openDB();
|
||||
const transaction = db.transaction([STORE_NAME], 'readonly');
|
||||
const store = transaction.objectStore(STORE_NAME);
|
||||
const request = store.get(key);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
request.onsuccess = () => {
|
||||
const data = request.result;
|
||||
if (!data) {
|
||||
resolve(null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Return full entry including timestamp and ttl
|
||||
resolve({
|
||||
payload: data.payload,
|
||||
timestamp: data.timestamp,
|
||||
ttl: data.ttl || this.ttl
|
||||
});
|
||||
};
|
||||
|
||||
request.onerror = () => {
|
||||
WARN('Error getting cache entry:', request.error);
|
||||
resolve(null);
|
||||
};
|
||||
});
|
||||
} catch (error) {
|
||||
ERR('Error in getCacheEntry:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Get cached data if valid
|
||||
async get(cacheName, userId = null) {
|
||||
if (!(await this.isCacheValid(cacheName, userId))) {
|
||||
@@ -220,8 +257,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
let _instance = null;
|
||||
|
||||
function getIndexedDBCache() {
|
||||
if (!_instance) {
|
||||
_instance = new IndexedDBCache();
|
||||
LOG('IndexedDBCache instance created');
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
// Create global instance
|
||||
window.IndexedDBCache = IndexedDBCache;
|
||||
window.IndexedDBCache = getIndexedDBCache();
|
||||
|
||||
LOG('IndexedDBCache manager loaded');
|
||||
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
// KefinTweaks Studios Cache Manager
|
||||
// Handles fetching, processing, and caching of Popular TV Networks
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const LOG = (...args) => console.log('[KefinTweaks Movies Cache]', ...args);
|
||||
const WARN = (...args) => console.warn('[KefinTweaks Movies Cache]', ...args);
|
||||
const ERR = (...args) => console.error('[KefinTweaks Movies Cache]', ...args);
|
||||
|
||||
// 1 week
|
||||
const CACHE_TTL = 7 * 24 * 60 * 60 * 1000;
|
||||
const IMDB_TOP_250_CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours for ID list
|
||||
|
||||
// State
|
||||
let movies = null;
|
||||
let imdbTop250Movies = null;
|
||||
let isInitializing = false;
|
||||
|
||||
async function fetchAndCacheMovies() {
|
||||
// IndexedDBCache
|
||||
const cacheName = 'movies_library';
|
||||
const cache = window.IndexedDBCache;
|
||||
|
||||
// Check cache first
|
||||
const cached = await cache.get(cacheName);
|
||||
if (cached) {
|
||||
LOG('Using cached Movies');
|
||||
return cached;
|
||||
}
|
||||
|
||||
try {
|
||||
LOG('Fetching Movies...');
|
||||
|
||||
const allMoviesQuery = `${ApiClient.serverAddress()}/Items?IncludeItemTypes=Movie&Recursive=true&Fields=ProviderIds`;
|
||||
|
||||
const movieResult = await apiHelper.getQuery(allMoviesQuery);
|
||||
|
||||
// Resolve the data (cached or fresh)
|
||||
let allMovies = [];
|
||||
if (movieResult && movieResult.Items) {
|
||||
allMovies = movieResult.Items;
|
||||
}
|
||||
|
||||
LOG(`Fetched ${allMovies.length} Movies`);
|
||||
|
||||
// Cache the results
|
||||
const userId = ApiClient.getCurrentUserId();
|
||||
await cache.set(cacheName, allMovies, userId, CACHE_TTL);
|
||||
|
||||
return allMovies;
|
||||
} catch (err) {
|
||||
ERR('Error fetching Movies:', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the cache
|
||||
*/
|
||||
async function initialize() {
|
||||
if (isInitializing) return;
|
||||
|
||||
if (movies) return;
|
||||
|
||||
isInitializing = true;
|
||||
try {
|
||||
movies = await fetchAndCacheMovies();
|
||||
} finally {
|
||||
isInitializing = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches IMDb Top 250 movies using client-side filtering
|
||||
* @returns {Promise<Array>} - List of matched Movie items
|
||||
*/
|
||||
async function fetchImdbTop250Data() {
|
||||
const CACHE_KEY_IDS = 'kefinTweaks_imdbTop250_ids';
|
||||
|
||||
let imdbIds = null;
|
||||
|
||||
// 1. Get IDs (Local Cache or Fetch GitHub)
|
||||
try {
|
||||
const cachedIds = localStorage.getItem(CACHE_KEY_IDS);
|
||||
if (cachedIds) {
|
||||
const parsed = JSON.parse(cachedIds);
|
||||
if (Date.now() - parsed.timestamp < IMDB_TOP_250_CACHE_TTL) {
|
||||
imdbIds = parsed.ids;
|
||||
}
|
||||
}
|
||||
} catch (e) { WARN('Error reading IMDb Top 250 cache:', e); }
|
||||
|
||||
if (!imdbIds) {
|
||||
LOG('Fetching IMDb Top 250 list from GitHub...');
|
||||
try {
|
||||
const response = await fetch('https://raw.githubusercontent.com/theapache64/top250/master/top250_min.json');
|
||||
if (!response.ok) throw new Error('Failed to fetch Top 250 JSON');
|
||||
const data = await response.json();
|
||||
|
||||
// Extract IDs
|
||||
imdbIds = data.map(entry => {
|
||||
// entry.imdb_url e.g. "http://www.imdb.com/title/tt0111161/"
|
||||
const match = entry.imdb_url && entry.imdb_url.match(/\/title\/(tt\d+)/);
|
||||
return match ? match[1] : null;
|
||||
}).filter(Boolean);
|
||||
|
||||
// Cache
|
||||
localStorage.setItem(CACHE_KEY_IDS, JSON.stringify({
|
||||
timestamp: Date.now(),
|
||||
ids: imdbIds
|
||||
}));
|
||||
} catch (err) {
|
||||
ERR('Failed to fetch IMDb Top 250 list:', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
if (!imdbIds || imdbIds.length === 0) return [];
|
||||
|
||||
return imdbIds;
|
||||
}
|
||||
|
||||
async function getImdbTop250Movies() {
|
||||
const cacheName = 'imdbTop250Movies';
|
||||
const cache = window.IndexedDBCache;
|
||||
const cached = await cache.get(cacheName);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
if (!imdbTop250Movies) {
|
||||
const imdbIds = await fetchImdbTop250Data();
|
||||
const allMovies = await getMovies();
|
||||
|
||||
// 3. Client-side Match
|
||||
const matchedMovies = [];
|
||||
const idsSet = new Set(imdbIds); // Faster lookup
|
||||
|
||||
for (const movie of allMovies) {
|
||||
if (movie.ProviderIds && movie.ProviderIds.Imdb && idsSet.has(movie.ProviderIds.Imdb)) {
|
||||
matchedMovies.push(movie);
|
||||
}
|
||||
}
|
||||
imdbTop250Movies = matchedMovies;
|
||||
}
|
||||
const userId = ApiClient.getCurrentUserId();
|
||||
await cache.set(cacheName, imdbTop250Movies, userId, IMDB_TOP_250_CACHE_TTL);
|
||||
return imdbTop250Movies || [];
|
||||
}
|
||||
|
||||
async function getMovies() {
|
||||
if (!movies) {
|
||||
movies = await fetchAndCacheMovies();
|
||||
}
|
||||
return movies || [];
|
||||
}
|
||||
|
||||
// Expose API
|
||||
window.MoviesCache = {
|
||||
init: initialize,
|
||||
getMovies: getMovies,
|
||||
getImdbTop250Movies: getImdbTop250Movies,
|
||||
// Also expose the fetcher if we need to force refresh
|
||||
refresh: async () => {
|
||||
const cache = window.IndexedDBCache;
|
||||
cache.delete('movies_library');
|
||||
movies = await fetchAndCacheMovies();
|
||||
return movies;
|
||||
}
|
||||
};
|
||||
|
||||
LOG('Module loaded');
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,321 @@
|
||||
// KefinTweaks People Cache Manager
|
||||
// Handles fetching, processing, and caching of top actors, directors, and writers
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const LOG = (...args) => console.log('[KefinTweaks PeopleCache]', ...args);
|
||||
const WARN = (...args) => console.warn('[KefinTweaks PeopleCache]', ...args);
|
||||
const ERR = (...args) => console.error('[KefinTweaks PeopleCache]', ...args);
|
||||
|
||||
// Configuration
|
||||
const MIN_PEOPLE_APPEARANCES = 2; // Minimum number of items a person must appear in to be tracked
|
||||
|
||||
// State
|
||||
let moviesTopPeople = null;
|
||||
let isInitializing = false;
|
||||
let isComplete = false;
|
||||
|
||||
/**
|
||||
* Extracts necessary item data for caching (similar to watchlist format)
|
||||
*/
|
||||
function extractItemDataForCache(item) {
|
||||
return {
|
||||
Id: item.Id,
|
||||
Type: item.Type,
|
||||
Name: item.Name,
|
||||
SeriesId: item.SeriesId,
|
||||
SeriesName: item.SeriesName,
|
||||
IndexNumber: item.IndexNumber,
|
||||
ParentIndexNumber: item.ParentIndexNumber,
|
||||
PremiereDate: item.PremiereDate,
|
||||
ProductionYear: item.ProductionYear,
|
||||
UserData: {
|
||||
Played: item.UserData?.Played || false,
|
||||
IsFavorite: item.UserData?.IsFavorite || false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes people data from movies array and returns RAW data (all people, unfiltered)
|
||||
*/
|
||||
function processPeopleDataRaw(movies, existingPeopleMap = null) {
|
||||
try {
|
||||
const peopleMap = existingPeopleMap ? new Map(existingPeopleMap) : new Map();
|
||||
|
||||
movies.forEach(movie => {
|
||||
// Extract item data for caching
|
||||
const itemData = extractItemDataForCache(movie);
|
||||
|
||||
if (movie.People) {
|
||||
movie.People.forEach(person => {
|
||||
const key = person.Id;
|
||||
if (!peopleMap.has(key)) {
|
||||
peopleMap.set(key, {
|
||||
id: person.Id,
|
||||
name: person.Name,
|
||||
directorCount: 0,
|
||||
writerCount: 0,
|
||||
actorCount: 0,
|
||||
directorItems: [],
|
||||
writerItems: [],
|
||||
actorItems: []
|
||||
});
|
||||
}
|
||||
|
||||
const personData = peopleMap.get(key);
|
||||
if (person.Type === 'Director') {
|
||||
personData.directorCount++;
|
||||
if (!personData.directorItems.some(item => item.Id === movie.Id)) {
|
||||
personData.directorItems.push(itemData);
|
||||
}
|
||||
} else if (person.Type === 'Writer') {
|
||||
personData.writerCount++;
|
||||
if (!personData.writerItems.some(item => item.Id === movie.Id)) {
|
||||
personData.writerItems.push(itemData);
|
||||
}
|
||||
} else if (person.Type === 'Actor') {
|
||||
personData.actorCount++;
|
||||
if (!personData.actorItems.some(item => item.Id === movie.Id)) {
|
||||
personData.actorItems.push(itemData);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return peopleMap;
|
||||
} catch (err) {
|
||||
ERR('Failed to process people data:', err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters and sorts raw people data
|
||||
*/
|
||||
function filterPeopleData(peopleMap) {
|
||||
try {
|
||||
if (!peopleMap) return null;
|
||||
|
||||
const allPeople = Array.from(peopleMap.values());
|
||||
|
||||
// Get threshold from config or default
|
||||
const minAppearances = (window.KefinTweaksConfig &&
|
||||
window.KefinTweaksConfig.homeScreen &&
|
||||
window.KefinTweaksConfig.homeScreen.discovery &&
|
||||
window.KefinTweaksConfig.homeScreen.discovery.minPeopleAppearances)
|
||||
|| MIN_PEOPLE_APPEARANCES;
|
||||
|
||||
const topDirectors = allPeople
|
||||
.filter(person => person.directorCount >= minAppearances)
|
||||
.sort((a, b) => b.directorCount - a.directorCount)
|
||||
.slice(0, 100)
|
||||
.map(person => ({
|
||||
id: person.id,
|
||||
name: person.name,
|
||||
count: person.directorCount,
|
||||
items: person.directorItems || []
|
||||
}));
|
||||
|
||||
const topWriters = allPeople
|
||||
.filter(person => person.writerCount >= minAppearances)
|
||||
.sort((a, b) => b.writerCount - a.writerCount)
|
||||
.slice(0, 100)
|
||||
.map(person => ({
|
||||
id: person.id,
|
||||
name: person.name,
|
||||
count: person.writerCount,
|
||||
items: person.writerItems || []
|
||||
}));
|
||||
|
||||
const topActors = allPeople
|
||||
.filter(person => person.actorCount >= minAppearances)
|
||||
.sort((a, b) => b.actorCount - a.actorCount)
|
||||
.slice(0, 100)
|
||||
.map(person => ({
|
||||
id: person.id,
|
||||
name: person.name,
|
||||
count: person.actorCount,
|
||||
items: person.actorItems || []
|
||||
}));
|
||||
|
||||
return {
|
||||
actors: topActors,
|
||||
directors: topDirectors,
|
||||
writers: topWriters
|
||||
};
|
||||
} catch (err) {
|
||||
ERR('Failed to filter people data:', err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches and processes top people data from all movies using pagination
|
||||
*/
|
||||
async function fetchTopPeople() {
|
||||
const apiClient = window.ApiClient;
|
||||
const serverUrl = apiClient.serverAddress();
|
||||
const token = apiClient.accessToken();
|
||||
const userId = apiClient.getCurrentUserId();
|
||||
const indexedDBCache = window.IndexedDBCache;
|
||||
|
||||
try {
|
||||
LOG('Starting paginated fetch of movies for people data processing...');
|
||||
|
||||
let startIndex = 0;
|
||||
const limit = 500;
|
||||
let hasMoreData = true;
|
||||
let peopleMap = null;
|
||||
|
||||
// Load existing raw people data if available (for resuming)
|
||||
const existingRawData = await indexedDBCache.get('movies_top_people_raw', userId);
|
||||
if (existingRawData && !existingRawData.isComplete) {
|
||||
const moviesProcessed = existingRawData.moviesProcessedCount;
|
||||
if (moviesProcessed > 0) {
|
||||
startIndex = moviesProcessed;
|
||||
peopleMap = new Map(existingRawData.peopleData || []);
|
||||
LOG(`Resuming from existing data: ${moviesProcessed} movies already processed`);
|
||||
}
|
||||
}
|
||||
|
||||
while (hasMoreData) {
|
||||
const url = `${serverUrl}/Items?userId=${userId}&IncludeItemTypes=Movie&Recursive=true&Fields=People,UserData&Limit=${limit}&StartIndex=${startIndex}`;
|
||||
|
||||
LOG(`Fetching movies ${startIndex} to ${startIndex + limit - 1}...`);
|
||||
|
||||
const response = await fetch(url, {
|
||||
headers: { 'Authorization': `MediaBrowser Token="${token}"` }
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
|
||||
const data = await response.json();
|
||||
const movies = data.Items || [];
|
||||
|
||||
if (movies.length === 0) {
|
||||
hasMoreData = false;
|
||||
} else {
|
||||
peopleMap = processPeopleDataRaw(movies, peopleMap);
|
||||
startIndex += movies.length;
|
||||
|
||||
// Update global state with partial results for immediate use
|
||||
const filteredData = filterPeopleData(peopleMap);
|
||||
if (filteredData) {
|
||||
moviesTopPeople = filteredData;
|
||||
}
|
||||
|
||||
// Checkpoint raw data
|
||||
const rawDataToCache = {
|
||||
isComplete: movies.length < limit,
|
||||
moviesProcessedCount: startIndex,
|
||||
peopleData: Array.from(peopleMap.entries())
|
||||
};
|
||||
await indexedDBCache.set('movies_top_people_raw', rawDataToCache, userId, 7 * 24 * 60 * 60 * 1000);
|
||||
|
||||
if (movies.length < limit) {
|
||||
hasMoreData = false;
|
||||
isComplete = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const finalPeopleData = filterPeopleData(peopleMap);
|
||||
if (finalPeopleData) {
|
||||
finalPeopleData.isComplete = true;
|
||||
moviesTopPeople = finalPeopleData;
|
||||
|
||||
await indexedDBCache.set('movies_top_people', finalPeopleData, userId, 7 * 24 * 60 * 60 * 1000);
|
||||
await indexedDBCache.clear('movies_top_people_raw', userId);
|
||||
|
||||
LOG('People cache complete and saved');
|
||||
}
|
||||
|
||||
return finalPeopleData;
|
||||
|
||||
} catch (err) {
|
||||
ERR('Failed to fetch top people data:', err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the people cache in the background
|
||||
*/
|
||||
async function initialize() {
|
||||
if (isInitializing) return;
|
||||
|
||||
if (moviesTopPeople !== null && isComplete) {
|
||||
return;
|
||||
}
|
||||
|
||||
const indexedDBCache = window.IndexedDBCache;
|
||||
const userId = window.ApiClient.getCurrentUserId();
|
||||
|
||||
// Check for valid complete filtered data
|
||||
const validComplete = await indexedDBCache.isCacheValid('movies_top_people', userId);
|
||||
if (validComplete) {
|
||||
const cachedData = await indexedDBCache.get('movies_top_people', userId);
|
||||
if (cachedData && cachedData.isComplete) {
|
||||
moviesTopPeople = cachedData;
|
||||
isComplete = true;
|
||||
LOG('Loaded complete top people data from IndexedDB');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize background fetch
|
||||
isInitializing = true;
|
||||
try {
|
||||
await fetchTopPeople();
|
||||
} finally {
|
||||
isInitializing = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function getTopPeople() {
|
||||
if (!moviesTopPeople) {
|
||||
await initialize();
|
||||
}
|
||||
return moviesTopPeople;
|
||||
}
|
||||
|
||||
async function getTopActors() {
|
||||
if (!moviesTopPeople) {
|
||||
await initialize();
|
||||
}
|
||||
return moviesTopPeople.actors;
|
||||
}
|
||||
|
||||
async function getTopDirectors() {
|
||||
if (!moviesTopPeople) {
|
||||
await initialize();
|
||||
}
|
||||
return moviesTopPeople.directors;
|
||||
}
|
||||
|
||||
async function getTopWriters() {
|
||||
if (!moviesTopPeople) {
|
||||
await initialize();
|
||||
}
|
||||
return moviesTopPeople.writers;
|
||||
}
|
||||
|
||||
function isCacheComplete() {
|
||||
return isComplete;
|
||||
}
|
||||
|
||||
// Expose API
|
||||
window.PeopleCache = {
|
||||
init: initialize,
|
||||
getTopPeople: getTopPeople,
|
||||
getTopActors: getTopActors,
|
||||
getTopDirectors: getTopDirectors,
|
||||
getTopWriters: getTopWriters,
|
||||
isComplete: isCacheComplete
|
||||
};
|
||||
|
||||
LOG('Module loaded');
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,114 @@
|
||||
// KefinTweaks Studios Cache Manager
|
||||
// Handles fetching, processing, and caching of Series Studios
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const LOG = (...args) => console.log('[KefinTweaks StudiosCache]', ...args);
|
||||
const WARN = (...args) => console.warn('[KefinTweaks StudiosCache]', ...args);
|
||||
const ERR = (...args) => console.error('[KefinTweaks StudiosCache]', ...args);
|
||||
|
||||
// State
|
||||
let _seriesStudios = null;
|
||||
|
||||
/**
|
||||
* Fetches and caches Series Studios using apiHelper.getQuery
|
||||
* Uses progressive loading: returns immediate cached data if available,
|
||||
* then updates in-memory cache when fresh data arrives
|
||||
*/
|
||||
async function fetchAndCacheSeriesStudios() {
|
||||
if (!window.apiHelper) {
|
||||
ERR('apiHelper is not available');
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const apiClient = window.ApiClient;
|
||||
if (!apiClient) {
|
||||
ERR('ApiClient is not available');
|
||||
return [];
|
||||
}
|
||||
|
||||
const serverUrl = apiClient.serverAddress();
|
||||
const url = `${serverUrl}/Studios?IncludeItemTypes=Series`;
|
||||
|
||||
LOG('Fetching Series Studios...');
|
||||
const result = await window.apiHelper.getQuery(url, { useCache: true });
|
||||
|
||||
// Extract immediate data (may be null/empty if uncached)
|
||||
const immediateData = result.data;
|
||||
const studios = immediateData?.Items || immediateData || [];
|
||||
|
||||
// When dataPromise resolves, update in-memory cache
|
||||
result.dataPromise.then(freshData => {
|
||||
const freshStudios = freshData?.Items || freshData || [];
|
||||
_seriesStudios = freshStudios;
|
||||
LOG(`Updated in-memory cache with ${freshStudios.length} Series Studios`);
|
||||
}).catch(err => {
|
||||
WARN('Error updating in-memory cache from dataPromise:', err);
|
||||
});
|
||||
|
||||
return studios;
|
||||
} catch (err) {
|
||||
ERR('Error fetching Series Studios:', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all Series Studios, using in-memory cache if available
|
||||
* Otherwise fetches and caches the data
|
||||
*/
|
||||
async function getSeriesStudios() {
|
||||
if (_seriesStudios !== null) {
|
||||
return _seriesStudios;
|
||||
}
|
||||
|
||||
// Fetch and cache, which will return immediate data and update cache when promise resolves
|
||||
const studios = await fetchAndCacheSeriesStudios();
|
||||
|
||||
// Update in-memory cache with immediate data (even if empty) to avoid repeated calls
|
||||
if (_seriesStudios === null) {
|
||||
_seriesStudios = studios;
|
||||
}
|
||||
|
||||
return studios;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the cache
|
||||
*/
|
||||
async function initialize() {
|
||||
await getSeriesStudios();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets popular TV networks (studios) filtered by minimum series count
|
||||
* @param {number} minimumSeries - Minimum number of series required (default: 0, returns all)
|
||||
* @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;
|
||||
}
|
||||
|
||||
const studios = await getSeriesStudios();
|
||||
|
||||
if (minimumSeries > 0) {
|
||||
return studios.filter(studio =>
|
||||
(studio.SeriesCount || studio.ChildCount || 0) >= minimumSeries
|
||||
);
|
||||
}
|
||||
|
||||
return studios;
|
||||
}
|
||||
|
||||
// Expose API
|
||||
window.StudiosCache = {
|
||||
init: initialize,
|
||||
getPopularTVNetworks: getPopularTVNetworks,
|
||||
getSeriesStudios: getSeriesStudios
|
||||
};
|
||||
|
||||
LOG('Module loaded');
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user