Fix IPTV categories timing out under per-category stream fetches.
Return all live categories immediately; only wait briefly for bulk counts and keep a single Alle zenders entry. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
318f613b40
commit
1834d42bd5
2 changed files with 16 additions and 36 deletions
|
|
@ -205,7 +205,8 @@ export class XtreamClient {
|
|||
}
|
||||
|
||||
getLiveCategories() {
|
||||
return this.getJson<XtreamCategory[]>({ action: "get_live_categories" }, 5 * 60_000);
|
||||
// Korte TTL: na IPTV-wijzigingen snel weer alle planken zichtbaar
|
||||
return this.getJson<XtreamCategory[]>({ action: "get_live_categories" }, 60_000);
|
||||
}
|
||||
|
||||
getLiveStreams(categoryId?: string) {
|
||||
|
|
|
|||
|
|
@ -82,9 +82,14 @@ export async function getViewerIptvCategories(viewerId: string, config: Config)
|
|||
const xt = await loadXtreamForToken(tokenId, config);
|
||||
if (!xt?.line.enableLive) throw new AppError("FORBIDDEN", "Live TV niet beschikbaar", 403);
|
||||
|
||||
// Categorieën zijn leidend — nooit blokkeren op de (soms trage/incomplete) bulk-zenderlijst
|
||||
const catsRaw = await xt.client.getLiveCategories().catch(() => null);
|
||||
const streamsRaw = await xt.client.getLiveStreams().catch(() => null);
|
||||
const cats = Array.isArray(catsRaw) ? catsRaw : [];
|
||||
|
||||
const streamsRaw = await Promise.race([
|
||||
xt.client.getLiveStreams().catch(() => null),
|
||||
new Promise<null>((resolve) => setTimeout(() => resolve(null), 6_000)),
|
||||
]);
|
||||
const streams = Array.isArray(streamsRaw) ? streamsRaw : [];
|
||||
|
||||
const counts = new Map<string, number>();
|
||||
|
|
@ -94,23 +99,10 @@ export async function getViewerIptvCategories(viewerId: string, config: Config)
|
|||
counts.set(key, (counts.get(key) ?? 0) + 1);
|
||||
}
|
||||
|
||||
// Als de bulk-lijst incompleet is: per categorie bijtellen (gecached in XtreamClient)
|
||||
const idsNeedingCount = cats
|
||||
.map((c) => normalizeIptvCategoryId(c.category_id))
|
||||
.filter((id) => id && (counts.get(id) ?? 0) === 0);
|
||||
if (idsNeedingCount.length > 0) {
|
||||
await mapPool(idsNeedingCount, 8, async (id) => {
|
||||
const list = await xt.client.getLiveStreams(id).catch(() => null);
|
||||
if (Array.isArray(list) && list.length > 0) {
|
||||
counts.set(id, list.length);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const categories = cats
|
||||
.map((c) => {
|
||||
const id = normalizeIptvCategoryId(c.category_id);
|
||||
const rawName = c.category_name ?? "";
|
||||
const rawName = String(c.category_name ?? "");
|
||||
return {
|
||||
id,
|
||||
name: friendlyCategoryName(rawName),
|
||||
|
|
@ -118,26 +110,25 @@ export async function getViewerIptvCategories(viewerId: string, config: Config)
|
|||
channelCount: counts.get(id) ?? 0,
|
||||
};
|
||||
})
|
||||
// Alleen lege ids + provider-verzamelcategorieën weg (niet echte genre-planken)
|
||||
// Toon ALLE echte planken; alleen pure verzamelbakken van de provider weg
|
||||
.filter((c) => c.id.length > 0 && !isAggregateCategoryName(c.rawName))
|
||||
.sort((a, b) => a.name.localeCompare(b.name, "nl"));
|
||||
|
||||
// Één verzamelknop van ons — niet van de IPTV-provider
|
||||
const totalChannels =
|
||||
streams.length > 0
|
||||
? streams.length
|
||||
: [...counts.values()].reduce((a, b) => a + b, 0);
|
||||
// Één eigen verzamelknop
|
||||
categories.unshift({
|
||||
id: "__all__",
|
||||
name: "Alle zenders",
|
||||
rawName: "Alle zenders",
|
||||
channelCount: totalChannels,
|
||||
channelCount: streams.length,
|
||||
});
|
||||
|
||||
return { categories };
|
||||
}
|
||||
|
||||
/** Alleen echte verzamelbakken (Alles / All / Alle zenders), geen Sport/Films/etc. */
|
||||
/**
|
||||
* Alleen pure verzamelbakken (Alles / All), géén "All Sports", "Alle films", enz.
|
||||
* Exacte match ná friendly-name (landcode-prefix al gestript).
|
||||
*/
|
||||
export function isAggregateCategoryName(raw: string): boolean {
|
||||
const n = friendlyCategoryName(raw).toLowerCase().replace(/\s+/g, " ").trim();
|
||||
return (
|
||||
|
|
@ -162,18 +153,6 @@ export function normalizeIptvCategoryId(raw: unknown): string {
|
|||
return s;
|
||||
}
|
||||
|
||||
async function mapPool<T>(items: T[], concurrency: number, fn: (item: T) => Promise<void>) {
|
||||
const queue = [...items];
|
||||
const workers = Array.from({ length: Math.min(concurrency, queue.length) }, async () => {
|
||||
while (queue.length > 0) {
|
||||
const item = queue.shift();
|
||||
if (item === undefined) return;
|
||||
await fn(item);
|
||||
}
|
||||
});
|
||||
await Promise.all(workers);
|
||||
}
|
||||
|
||||
function sortChannels(streams: XtreamLiveStream[]): XtreamLiveStream[] {
|
||||
return [...streams].sort((a, b) => (a.num ?? a.stream_id) - (b.num ?? b.stream_id));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue