Include custom live lists in admin TV category order.
Lists appear alongside XUI categories and respect the saved order in apps.
This commit is contained in:
parent
c97374c9cb
commit
94bf98ded7
2 changed files with 84 additions and 59 deletions
|
|
@ -919,9 +919,10 @@ export default function SettingsPage() {
|
||||||
Categorie-volgorde
|
Categorie-volgorde
|
||||||
</h3>
|
</h3>
|
||||||
<p className="muted" style={{ marginBottom: "0.75rem" }}>
|
<p className="muted" style={{ marginBottom: "0.75rem" }}>
|
||||||
Volgorde van links naar rechts in de TV-apps. Nieuwe XUI-categorieën komen onderaan.
|
Volgorde van links naar rechts in de TV-apps. XUI-categorieën én Live-lijsten
|
||||||
|
(ClearKey/DASH). Nieuwe items komen onderaan.
|
||||||
{tvCategories.length === 0
|
{tvCategories.length === 0
|
||||||
? " Geen actieve IPTV-lijn gevonden — koppel eerst een kijker."
|
? " Geen categorieën — koppel een IPTV-lijn en/of maak Live-lijsten."
|
||||||
: ""}
|
: ""}
|
||||||
</p>
|
</p>
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: "0.35rem" }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: "0.35rem" }}>
|
||||||
|
|
|
||||||
|
|
@ -84,24 +84,27 @@ export async function getViewerIptvCategories(viewerId: string, config: Config)
|
||||||
throw new AppError("FORBIDDEN", "Geen TV-toegang", 403);
|
throw new AppError("FORBIDDEN", "Geen TV-toegang", 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const prefs = await getIptvSettings(config);
|
||||||
|
|
||||||
let categories: Array<{
|
let categories: Array<{
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
rawName: string;
|
rawName: string;
|
||||||
channelCount: number;
|
channelCount: number;
|
||||||
}> = [];
|
}> = [];
|
||||||
|
let streamCountForAll = 0;
|
||||||
|
|
||||||
if (xt?.line.enableLive) {
|
if (xt?.line.enableLive) {
|
||||||
const [catsRaw, streamsRaw, iptvPrefs] = await Promise.all([
|
const [catsRaw, streamsRaw] = await Promise.all([
|
||||||
xt.client.getLiveCategories().catch(() => [] as Awaited<ReturnType<typeof xt.client.getLiveCategories>>),
|
xt.client.getLiveCategories().catch(() => [] as Awaited<ReturnType<typeof xt.client.getLiveCategories>>),
|
||||||
Promise.race([
|
Promise.race([
|
||||||
xt.client.getLiveStreams().catch(() => [] as XtreamLiveStream[]),
|
xt.client.getLiveStreams().catch(() => [] as XtreamLiveStream[]),
|
||||||
new Promise<XtreamLiveStream[]>((resolve) => setTimeout(() => resolve([]), 6_000)),
|
new Promise<XtreamLiveStream[]>((resolve) => setTimeout(() => resolve([]), 6_000)),
|
||||||
]),
|
]),
|
||||||
getIptvSettings(config),
|
|
||||||
]);
|
]);
|
||||||
const cats = Array.isArray(catsRaw) ? catsRaw : [];
|
const cats = Array.isArray(catsRaw) ? catsRaw : [];
|
||||||
const streams: XtreamLiveStream[] = Array.isArray(streamsRaw) ? streamsRaw : [];
|
const streams: XtreamLiveStream[] = Array.isArray(streamsRaw) ? streamsRaw : [];
|
||||||
|
streamCountForAll = streams.length;
|
||||||
|
|
||||||
const counts = new Map<string, number>();
|
const counts = new Map<string, number>();
|
||||||
for (const s of streams) {
|
for (const s of streams) {
|
||||||
|
|
@ -131,18 +134,6 @@ export async function getViewerIptvCategories(viewerId: string, config: Config)
|
||||||
channelCount,
|
channelCount,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const prefs = iptvPrefs ?? (await getIptvSettings(config));
|
|
||||||
categories = applyIptvCategoryOrder(categories, prefs.categoryOrder);
|
|
||||||
|
|
||||||
if (prefs.showAlleZenders) {
|
|
||||||
categories.unshift({
|
|
||||||
id: "__all__",
|
|
||||||
name: "Alle zenders",
|
|
||||||
rawName: "Alle zenders",
|
|
||||||
channelCount: streams.length,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const customLists = await listAssignedLiveListsForViewer(viewerId);
|
const customLists = await listAssignedLiveListsForViewer(viewerId);
|
||||||
|
|
@ -155,30 +146,46 @@ export async function getViewerIptvCategories(viewerId: string, config: Config)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
categories = applyIptvCategoryOrder(categories, prefs.categoryOrder);
|
||||||
|
|
||||||
|
if (prefs.showAlleZenders && xt?.line.enableLive) {
|
||||||
|
categories.unshift({
|
||||||
|
id: "__all__",
|
||||||
|
name: "Alle zenders",
|
||||||
|
rawName: "Alle zenders",
|
||||||
|
channelCount: streamCountForAll,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return { categories };
|
return { categories };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Admin: categorieën uit een actieve IPTV-lijn voor volgorde-UI. */
|
/** Admin: XUI-categorieën + custom live-lijsten voor volgorde-UI. */
|
||||||
export async function listIptvCategoriesForAdmin(config: Config) {
|
export async function listIptvCategoriesForAdmin(config: Config) {
|
||||||
|
const iptvPrefs = await getIptvSettings(config);
|
||||||
|
|
||||||
|
let categories: Array<{
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
rawName: string;
|
||||||
|
channelCount: number;
|
||||||
|
}> = [];
|
||||||
|
|
||||||
const line = await prisma.iptvLine.findFirst({
|
const line = await prisma.iptvLine.findFirst({
|
||||||
where: { enableLive: true },
|
where: { enableLive: true },
|
||||||
orderBy: { updatedAt: "desc" },
|
orderBy: { updatedAt: "desc" },
|
||||||
select: { id: true },
|
select: { id: true },
|
||||||
});
|
});
|
||||||
if (!line) return [] as Array<{ id: string; name: string; channelCount: number }>;
|
|
||||||
|
|
||||||
|
if (line) {
|
||||||
const xt = await loadXtreamByLineId(line.id, config);
|
const xt = await loadXtreamByLineId(line.id, config);
|
||||||
if (!xt?.line.enableLive) {
|
if (xt?.line.enableLive) {
|
||||||
return [] as Array<{ id: string; name: string; channelCount: number }>;
|
const [catsRaw, streamsRaw] = await Promise.all([
|
||||||
}
|
|
||||||
|
|
||||||
const [catsRaw, streamsRaw, iptvPrefs] = await Promise.all([
|
|
||||||
xt.client.getLiveCategories().catch(() => []),
|
xt.client.getLiveCategories().catch(() => []),
|
||||||
Promise.race([
|
Promise.race([
|
||||||
xt.client.getLiveStreams().catch(() => [] as XtreamLiveStream[]),
|
xt.client.getLiveStreams().catch(() => [] as XtreamLiveStream[]),
|
||||||
new Promise<XtreamLiveStream[]>((resolve) => setTimeout(() => resolve([]), 8_000)),
|
new Promise<XtreamLiveStream[]>((resolve) => setTimeout(() => resolve([]), 8_000)),
|
||||||
]),
|
]),
|
||||||
getIptvSettings(config),
|
|
||||||
]);
|
]);
|
||||||
const cats = Array.isArray(catsRaw) ? catsRaw : [];
|
const cats = Array.isArray(catsRaw) ? catsRaw : [];
|
||||||
const streams = Array.isArray(streamsRaw) ? streamsRaw : [];
|
const streams = Array.isArray(streamsRaw) ? streamsRaw : [];
|
||||||
|
|
@ -190,7 +197,7 @@ export async function listIptvCategoriesForAdmin(config: Config) {
|
||||||
counts.set(key, (counts.get(key) ?? 0) + 1);
|
counts.set(key, (counts.get(key) ?? 0) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let categories = cats
|
categories = cats
|
||||||
.map((c) => {
|
.map((c) => {
|
||||||
const id = normalizeIptvCategoryId(c.category_id);
|
const id = normalizeIptvCategoryId(c.category_id);
|
||||||
const rawName = String(c.category_name ?? "");
|
const rawName = String(c.category_name ?? "");
|
||||||
|
|
@ -211,6 +218,23 @@ export async function listIptvCategoriesForAdmin(config: Config) {
|
||||||
channelCount,
|
channelCount,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const customLists = await prisma.liveChannelList.findMany({
|
||||||
|
where: { enabled: true },
|
||||||
|
orderBy: [{ sortOrder: "asc" }, { name: "asc" }],
|
||||||
|
include: { _count: { select: { channels: { where: { enabled: true } } } } },
|
||||||
|
});
|
||||||
|
const { customCategoryId } = await import("./live-channels");
|
||||||
|
for (const list of customLists) {
|
||||||
|
categories.push({
|
||||||
|
id: customCategoryId(list.id),
|
||||||
|
name: list.name,
|
||||||
|
rawName: list.name,
|
||||||
|
channelCount: list._count.channels,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
categories = applyIptvCategoryOrder(categories, iptvPrefs.categoryOrder);
|
categories = applyIptvCategoryOrder(categories, iptvPrefs.categoryOrder);
|
||||||
return categories.map(({ id, name, channelCount }) => ({ id, name, channelCount }));
|
return categories.map(({ id, name, channelCount }) => ({ id, name, channelCount }));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue