Files
2026-05-26 22:46:00 +02:00

44 lines
1.9 KiB
TypeScript

/**
* URL builders for our asset routes. The path basename is the friendly filename
* (used as the browser tab title and "Save as…" suggestion). The query string
* carries the actual lookup key.
*/
function safe(name: string): string {
// Browser-safe: encode anything that's not alphanumeric, dash, dot, or underscore.
return encodeURIComponent(name);
}
export function imageUrl(opts: { id: number; code: string | null; ext?: string; v?: string }): string {
const ext = opts.ext ?? ".jpg";
const params = new URLSearchParams({ id: String(opts.id) });
if (opts.v) params.set("v", opts.v);
if (opts.code) {
const friendly = `${opts.code}${ext}`;
return `/api/image/${safe(friendly)}?${params.toString()}`;
}
const friendly = `image-${opts.id}${ext}`;
return `/api/image/${safe(friendly)}?${params.toString()}`;
}
export function thumbUrl(opts: { thumbPath: string; code?: string | null; id?: number | null }): string {
// thumbPath is the SHA-based filename ("<sha>.webp"). Friendly name uses code if available.
const friendly = `${opts.code ?? (opts.id != null ? `image-${opts.id}` : "thumb")}.webp`;
return `/api/thumb/${safe(friendly)}?p=${encodeURIComponent(opts.thumbPath)}`;
}
export function portraitUrl(opts: { path: string; slug?: string | null; slot?: "1" | "2" | "3" | "4" | "h" }): string {
const ext = opts.path.match(/\.[^.]+$/)?.[0] ?? ".jpg";
const slotSuffix = opts.slot && opts.slot !== "1" ? `-${opts.slot === "h" ? "l" : `p${opts.slot}`}` : "";
const friendly = `${opts.slug ?? "portrait"}${slotSuffix}${ext}`;
return `/api/portrait/${safe(friendly)}?p=${encodeURIComponent(opts.path)}`;
}
export function categoryCoverUrl(filename: string): string {
return `/api/category-cover-file/${safe(filename)}`;
}
export function collectionCoverUrl(filename: string): string {
return `/api/collection-cover-file/${safe(filename)}`;
}