From 4c15a37783021896701499777f3bf8e2b93633c7 Mon Sep 17 00:00:00 2001 From: Jos Vooges | STH Date: Sat, 12 Sep 2026 02:37:03 +0200 Subject: [PATCH] Sort 4K shelf by newest 4K file discovery, not title first-seen. --- apps/master-api/src/stremio/routes.ts | 8 ++-- apps/master-api/src/viewer/service.ts | 62 +++++++++++++++++++-------- 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/apps/master-api/src/stremio/routes.ts b/apps/master-api/src/stremio/routes.ts index 3d9e770..a46cc97 100644 --- a/apps/master-api/src/stremio/routes.ts +++ b/apps/master-api/src/stremio/routes.ts @@ -508,9 +508,8 @@ async function getMovieCatalog( } else if (catalogId === "4k-movies") { if (!search) { const idRows = await prisma.$queryRaw>` - SELECT m.id AS movie_id + SELECT mf.movie_id FROM media_files mf - INNER JOIN movies m ON m.id = mf.movie_id WHERE mf.available = true AND mf.movie_id IS NOT NULL AND ( @@ -518,9 +517,8 @@ async function getMovieCatalog( OR mf.resolution ILIKE '%4K%' OR mf.resolution ILIKE '%UHD%' ) - GROUP BY m.id, m.library_added_at - ORDER BY COALESCE(m.library_added_at, MAX(mf.discovered_at)) DESC NULLS LAST, - MAX(mf.discovered_at) DESC + GROUP BY mf.movie_id + ORDER BY MAX(mf.discovered_at) DESC, MIN(mf.release_name) ASC OFFSET ${skip} LIMIT ${CATALOG_PAGE} `; diff --git a/apps/master-api/src/viewer/service.ts b/apps/master-api/src/viewer/service.ts index 55e4962..86f3ba3 100644 --- a/apps/master-api/src/viewer/service.ts +++ b/apps/master-api/src/viewer/service.ts @@ -985,40 +985,65 @@ export class ViewerService { /** * Sorteer op library_added_at (cluster first-seen). Fallback discovered_at. * Tweede node bump’t niet; mtime bij eerste index voorkomt scan-flood. + * Optie byFileDiscoveredAt: voor 4K — nieuwste 4K-file (mtime/discovered_at), niet titel-first-seen. */ private async moviesByRecency( skip: number, take: number, extraWhereSql: Prisma.Sql = Prisma.empty, - opts: { cap?: number; kidsMode?: boolean } = {} + opts: { cap?: number; kidsMode?: boolean; byFileDiscoveredAt?: boolean } = {} ) { const cap = opts.cap; const kidsSql = opts.kidsMode ? kidsMovieSql() : Prisma.empty; - const idRows = await prisma.$queryRaw>` - SELECT m.id AS movie_id - FROM media_files mf - INNER JOIN movies m ON m.id = mf.movie_id - WHERE mf.available = true - AND mf.movie_id IS NOT NULL - ${extraWhereSql} - ${kidsSql} - GROUP BY m.id, m.library_added_at - ORDER BY COALESCE(m.library_added_at, MAX(mf.discovered_at)) DESC NULLS LAST, - MAX(mf.discovered_at) DESC, - MIN(mf.release_name) ASC - ${cap != null ? Prisma.sql`LIMIT ${cap}` : Prisma.empty} - `; + const idRows = opts.byFileDiscoveredAt + ? await prisma.$queryRaw>` + SELECT mf.movie_id + FROM media_files mf + WHERE mf.available = true + AND mf.movie_id IS NOT NULL + ${extraWhereSql} + ${kidsSql} + GROUP BY mf.movie_id + ORDER BY MAX(mf.discovered_at) DESC, MIN(mf.release_name) ASC + ${cap != null ? Prisma.sql`LIMIT ${cap}` : Prisma.empty} + ` + : await prisma.$queryRaw>` + SELECT m.id AS movie_id + FROM media_files mf + INNER JOIN movies m ON m.id = mf.movie_id + WHERE mf.available = true + AND mf.movie_id IS NOT NULL + ${extraWhereSql} + ${kidsSql} + GROUP BY m.id, m.library_added_at + ORDER BY COALESCE(m.library_added_at, MAX(mf.discovered_at)) DESC NULLS LAST, + MAX(mf.discovered_at) DESC, + MIN(mf.release_name) ASC + ${cap != null ? Prisma.sql`LIMIT ${cap}` : Prisma.empty} + `; const allIds = idRows.map((r) => r.movie_id); const total = allIds.length; const ids = allIds.slice(skip, skip + take); if (!ids.length) return { total, items: [], offset: skip }; + const fourKOnly = opts.byFileDiscoveredAt === true; const movies = await prisma.movie.findMany({ where: { id: { in: ids } }, include: { mediaFiles: { - where: { available: true }, - orderBy: [{ lastSeen: "desc" }, { createdAt: "desc" }], + where: fourKOnly + ? { + available: true, + OR: [ + { resolution: { contains: "2160" } }, + { resolution: { contains: "4K", mode: "insensitive" } }, + { resolution: { contains: "UHD", mode: "insensitive" } }, + ], + } + : { available: true }, + orderBy: fourKOnly + ? [{ discoveredAt: "desc" }, { lastSeen: "desc" }] + : [{ lastSeen: "desc" }, { createdAt: "desc" }], take: 1, }, }, @@ -1332,7 +1357,7 @@ export class ViewerService { OR mf.resolution ILIKE '%4K%' OR mf.resolution ILIKE '%UHD%' )`, - { cap: RECENT_CATALOG_CAP, kidsMode } + { cap: RECENT_CATALOG_CAP, kidsMode, byFileDiscoveredAt: true } ); return page.items; } @@ -1912,6 +1937,7 @@ export class ViewerService { : await this.moviesByRecency(skip, take, fourKSql, { cap: RECENT_CATALOG_CAP, kidsMode, + byFileDiscoveredAt: true, }); return { id,