Rework the media grid with a viewer, metadata banners, and load gate
This commit is contained in:
+52
-17
@@ -102,6 +102,18 @@ export function uniqueScrapeId(root: string, channelId: string, now = new Date()
|
||||
return id;
|
||||
}
|
||||
|
||||
export interface MediaFilterOptions {
|
||||
kind?: MediaKind;
|
||||
source?: string;
|
||||
authorId?: string;
|
||||
aspect?: string;
|
||||
resolution?: string;
|
||||
after?: string;
|
||||
before?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
export interface MediaRow {
|
||||
id: number;
|
||||
kind: MediaKind;
|
||||
@@ -369,22 +381,7 @@ export class ScrapeStore {
|
||||
return row ?? null;
|
||||
}
|
||||
|
||||
queryMedia(
|
||||
options: {
|
||||
kind?: MediaKind;
|
||||
source?: string;
|
||||
authorId?: string;
|
||||
aspect?: string;
|
||||
resolution?: string;
|
||||
after?: string;
|
||||
before?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
} = {}
|
||||
): MediaRow[] {
|
||||
const limit = Math.max(1, Math.min(options.limit ?? 50, 500));
|
||||
const offset = Math.max(0, options.offset ?? 0);
|
||||
|
||||
private mediaWhere(options: MediaFilterOptions): { where: string; values: Array<string | number> } {
|
||||
const conditions: string[] = [];
|
||||
const values: Array<string | number> = [];
|
||||
|
||||
@@ -415,11 +412,49 @@ export class ScrapeStore {
|
||||
const resolution = options.resolution ? resolutionCondition(options.resolution) : null;
|
||||
if (resolution) conditions.push(resolution);
|
||||
|
||||
const where = conditions.length ? `WHERE ${conditions.join(" AND ")}` : "";
|
||||
return { where: conditions.length ? `WHERE ${conditions.join(" AND ")}` : "", values };
|
||||
}
|
||||
|
||||
queryMedia(options: MediaFilterOptions = {}): MediaRow[] {
|
||||
const limit = Math.max(1, Math.min(options.limit ?? 50, 500));
|
||||
const offset = Math.max(0, options.offset ?? 0);
|
||||
const { where, values } = this.mediaWhere(options);
|
||||
|
||||
const rows = this.db
|
||||
.prepare(`SELECT * FROM media ${where} ORDER BY id DESC LIMIT ? OFFSET ?`)
|
||||
.all(...values, limit, offset);
|
||||
|
||||
return rows as unknown as MediaRow[];
|
||||
}
|
||||
|
||||
/** Counts for the status row, under the same filters as queryMedia. */
|
||||
stats(options: MediaFilterOptions = {}): {
|
||||
total: number;
|
||||
downloaded: number;
|
||||
cached: number;
|
||||
notDownloaded: number;
|
||||
} {
|
||||
const { where, values } = this.mediaWhere(options);
|
||||
const row = this.db
|
||||
.prepare(
|
||||
`SELECT COUNT(*) AS total,
|
||||
COALESCE(SUM(downloaded), 0) AS downloaded,
|
||||
COALESCE(SUM(CASE WHEN downloaded = 0 AND preview_hash IS NOT NULL THEN 1 ELSE 0 END), 0) AS cached,
|
||||
COALESCE(SUM(CASE WHEN downloaded = 0 THEN 1 ELSE 0 END), 0) AS not_downloaded
|
||||
FROM media ${where}`
|
||||
)
|
||||
.get(...values) as unknown as {
|
||||
total: number;
|
||||
downloaded: number;
|
||||
cached: number;
|
||||
not_downloaded: number;
|
||||
};
|
||||
|
||||
return {
|
||||
total: row?.total ?? 0,
|
||||
downloaded: row?.downloaded ?? 0,
|
||||
cached: row?.cached ?? 0,
|
||||
notDownloaded: row?.not_downloaded ?? 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user