Rework the media grid with a viewer, metadata banners, and load gate

This commit is contained in:
Fisto
2026-09-16 12:29:45 +02:00
parent fae754fba0
commit f9b4041157
8 changed files with 604 additions and 52 deletions
+36
View File
@@ -114,6 +114,8 @@ export interface MediaItemResult {
width: number | null;
height: number | null;
aspectRatio: number | null;
contentType: string | null;
durationSecs: number | null;
url: string;
localUrl: string | null;
thumbUrl: string | null;
@@ -442,6 +444,38 @@ export class MediaService {
return count;
}
/** Item counts for the status row, under the same filters as queryMedia. */
stats(options: {
kind?: MediaKind;
source?: string;
channelId?: string;
authorId?: string;
aspect?: string;
resolution?: string;
after?: string;
before?: string;
} = {}): { total: number; downloaded: number; cached: number; notDownloaded: number } {
const totals = { total: 0, downloaded: 0, cached: 0, notDownloaded: 0 };
for (const meta of this.engine.list()) {
if (meta.state === "deleted") continue;
if (options.channelId && meta.channelId !== options.channelId) continue;
const store = new ScrapeStore(scrapeDir(this.rootDir, meta.id));
try {
const stats = store.stats(options);
totals.total += stats.total;
totals.downloaded += stats.downloaded;
totals.cached += stats.cached;
totals.notDownloaded += stats.notDownloaded;
} finally {
store.close();
}
}
return totals;
}
/** Distinct posters across every scrape, biggest first. */
listAuthors(): Array<{ id: string | null; name: string | null; count: number }> {
const totals = new Map<string, { id: string | null; name: string | null; count: number }>();
@@ -532,6 +566,8 @@ export class MediaService {
width: row.width,
height: row.height,
aspectRatio: row.aspect_ratio,
contentType: row.content_type,
durationSecs: row.duration_secs,
url: row.url,
localUrl:
row.file_path && !meta.downloadDir