Sort 4K shelf by newest 4K file discovery, not title first-seen.

This commit is contained in:
Jos Vooges | STH 2026-09-12 02:37:03 +02:00
parent 06a022089b
commit 4c15a37783
2 changed files with 47 additions and 23 deletions

View file

@ -508,9 +508,8 @@ async function getMovieCatalog(
} else if (catalogId === "4k-movies") {
if (!search) {
const idRows = await prisma.$queryRaw<Array<{ movie_id: string }>>`
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}
`;

View file

@ -985,16 +985,29 @@ 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<Array<{ movie_id: string }>>`
const idRows = opts.byFileDiscoveredAt
? await prisma.$queryRaw<Array<{ movie_id: string }>>`
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<Array<{ movie_id: string }>>`
SELECT m.id AS movie_id
FROM media_files mf
INNER JOIN movies m ON m.id = mf.movie_id
@ -1013,12 +1026,24 @@ export class ViewerService {
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,