Fix shelf catalog pagination so browse shows all titles.
Shelf endpoints now return a real total and page by skip/take instead of capping around 60. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
38a779c5f8
commit
7e624dd452
2 changed files with 93 additions and 75 deletions
|
|
@ -79,7 +79,12 @@ fun BrowseScreen(
|
|||
val page = api.browse(catalogId, skip = skip, take = 60)
|
||||
title = page.title.ifBlank { titleHint ?: catalogId }
|
||||
total = page.total
|
||||
items = if (reset) page.items else items + page.items.filter { n -> items.none { it.id == n.id } }
|
||||
items = if (reset) {
|
||||
page.items
|
||||
} else {
|
||||
val existing = items.map { "${it.type}:${it.id}" }.toSet()
|
||||
items + page.items.filter { "${it.type}:${it.id}" !in existing }
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
error = e.message
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -328,7 +328,16 @@ export class ViewerService {
|
|||
title: string;
|
||||
kind: "MOVIE" | "SERIES";
|
||||
slug: string;
|
||||
items: Awaited<ReturnType<ViewerService["shelfItems"]>>;
|
||||
items: Array<{
|
||||
type: "movie" | "series";
|
||||
id: string;
|
||||
title: string;
|
||||
year: number | null;
|
||||
posterUrl: string | null;
|
||||
backdropUrl: string | null;
|
||||
mediaFileId: string | null;
|
||||
badge?: string;
|
||||
}>;
|
||||
}> = [];
|
||||
|
||||
if (recentMovies.length) {
|
||||
|
|
@ -567,80 +576,79 @@ export class ViewerService {
|
|||
}
|
||||
|
||||
async shelfItems(shelfId: string, kind: "MOVIE" | "SERIES", take: number) {
|
||||
// Sorteer op laatst toegevoegd mediabestand (niet op metadata-aanmaakdatum)
|
||||
const page = await this.shelfItemsPage(shelfId, kind, 0, take);
|
||||
return page.items;
|
||||
}
|
||||
|
||||
/** Volledige plank met echte total + skip/take (voor browse/Alles). */
|
||||
async shelfItemsPage(
|
||||
shelfId: string,
|
||||
kind: "MOVIE" | "SERIES",
|
||||
skip: number,
|
||||
take: number
|
||||
) {
|
||||
if (kind === "MOVIE") {
|
||||
const files = await prisma.mediaFile.findMany({
|
||||
where: { shelfId, available: true, movieId: { not: null } },
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: Math.max(take * 4, take),
|
||||
include: { movie: true },
|
||||
});
|
||||
const seen = new Set<string>();
|
||||
const out: Array<{
|
||||
type: "movie";
|
||||
id: string;
|
||||
title: string;
|
||||
year: number | null;
|
||||
posterUrl: string | null;
|
||||
backdropUrl: string | null;
|
||||
mediaFileId: string | null;
|
||||
}> = [];
|
||||
for (const f of files) {
|
||||
if (!f.movieId || !f.movie || seen.has(f.movieId)) continue;
|
||||
seen.add(f.movieId);
|
||||
out.push({
|
||||
type: "movie",
|
||||
id: f.movie.id,
|
||||
title: f.movie.title,
|
||||
year: f.movie.year,
|
||||
posterUrl: f.movie.posterUrl,
|
||||
backdropUrl: f.movie.backdropUrl,
|
||||
mediaFileId: f.id,
|
||||
});
|
||||
if (out.length >= take) break;
|
||||
}
|
||||
return out;
|
||||
const where = {
|
||||
mediaFiles: { some: { shelfId, available: true } },
|
||||
};
|
||||
const [total, movies] = await Promise.all([
|
||||
prisma.movie.count({ where }),
|
||||
prisma.movie.findMany({
|
||||
where,
|
||||
orderBy: [{ title: "asc" }, { year: "asc" }],
|
||||
skip,
|
||||
take,
|
||||
include: {
|
||||
mediaFiles: {
|
||||
where: { shelfId, available: true },
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
]);
|
||||
return {
|
||||
total,
|
||||
items: movies.map((m) => ({
|
||||
type: "movie" as const,
|
||||
id: m.id,
|
||||
title: m.title,
|
||||
year: m.year,
|
||||
posterUrl: m.posterUrl,
|
||||
backdropUrl: m.backdropUrl,
|
||||
mediaFileId: m.mediaFiles[0]?.id ?? null,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
const files = await prisma.mediaFile.findMany({
|
||||
where: {
|
||||
shelfId,
|
||||
available: true,
|
||||
episodeId: { not: null },
|
||||
const where = {
|
||||
episodes: {
|
||||
some: {
|
||||
mediaFiles: { some: { shelfId, available: true } },
|
||||
},
|
||||
},
|
||||
orderBy: { createdAt: "desc" },
|
||||
take: Math.max(take * 6, take),
|
||||
include: {
|
||||
episode: { include: { series: true } },
|
||||
},
|
||||
});
|
||||
const seen = new Set<string>();
|
||||
const out: Array<{
|
||||
type: "series";
|
||||
id: string;
|
||||
title: string;
|
||||
year: number | null;
|
||||
posterUrl: string | null;
|
||||
backdropUrl: string | null;
|
||||
mediaFileId: string | null;
|
||||
}> = [];
|
||||
for (const f of files) {
|
||||
const series = f.episode?.series;
|
||||
const seriesId = f.episode?.seriesId;
|
||||
if (!series || !seriesId || seen.has(seriesId)) continue;
|
||||
seen.add(seriesId);
|
||||
out.push({
|
||||
type: "series",
|
||||
id: series.id,
|
||||
title: series.title,
|
||||
year: series.year,
|
||||
posterUrl: series.posterUrl,
|
||||
backdropUrl: series.backdropUrl,
|
||||
mediaFileId: null,
|
||||
});
|
||||
if (out.length >= take) break;
|
||||
}
|
||||
return out;
|
||||
};
|
||||
const [total, series] = await Promise.all([
|
||||
prisma.series.count({ where }),
|
||||
prisma.series.findMany({
|
||||
where,
|
||||
orderBy: [{ title: "asc" }, { year: "asc" }],
|
||||
skip,
|
||||
take,
|
||||
}),
|
||||
]);
|
||||
return {
|
||||
total,
|
||||
items: series.map((s) => ({
|
||||
type: "series" as const,
|
||||
id: s.id,
|
||||
title: s.title,
|
||||
year: s.year,
|
||||
posterUrl: s.posterUrl,
|
||||
backdropUrl: s.backdropUrl,
|
||||
mediaFileId: null as string | null,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
async continueWatching(viewerId: string) {
|
||||
|
|
@ -990,13 +998,18 @@ export class ViewerService {
|
|||
})) || null;
|
||||
if (!shelf) throw new AppError("NOT_FOUND", "Catalogus niet gevonden", 404);
|
||||
|
||||
const items = await this.shelfItems(shelf.id, shelf.kind, skip + take);
|
||||
const page = await this.shelfItemsPage(
|
||||
shelf.id,
|
||||
shelf.kind as "MOVIE" | "SERIES",
|
||||
skip,
|
||||
take
|
||||
);
|
||||
return {
|
||||
id: shelf.slug,
|
||||
title: shelf.name,
|
||||
kind: shelf.kind,
|
||||
total: items.length + skip,
|
||||
items: items.slice(skip, skip + take),
|
||||
total: page.total,
|
||||
items: page.items,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue