feat: initial
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
// Helpers for resolving uploaded-asset URLs out of loosely-typed API records.
|
||||
// Response field names vary across endpoints, so we probe a list of common keys
|
||||
// and turn relative storage paths into absolute URLs.
|
||||
|
||||
import { ASSET_BASE_URL } from "./config";
|
||||
|
||||
// Turn a possibly-relative path into an absolute URL. The API serves uploads
|
||||
// from `/storage/...`, while DB fields like `file_path` hold paths relative to
|
||||
// that (e.g. "music/x.mp3"), so we add the `storage/` prefix when missing.
|
||||
export function assetUrl(path?: string | null): string | null {
|
||||
if (!path) return null;
|
||||
if (/^(https?:|data:|blob:)/i.test(path)) return path;
|
||||
let p = String(path).replace(/^\/+/, "");
|
||||
if (!p.startsWith("storage/")) p = `storage/${p}`;
|
||||
return `${ASSET_BASE_URL}/${p}`;
|
||||
}
|
||||
|
||||
// A record may store a media reference directly (string) or nested in an object
|
||||
// (e.g. { sound: { url } }). Read the first key that yields a usable value.
|
||||
function readField(row: Record<string, unknown>, key: string): string | null {
|
||||
const v = row[key];
|
||||
if (typeof v === "string" && v) return v;
|
||||
if (v && typeof v === "object") {
|
||||
const obj = v as Record<string, unknown>;
|
||||
for (const k of ["url", "path", "src", "file"]) {
|
||||
if (typeof obj[k] === "string" && obj[k]) return obj[k] as string;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find the first present URL among candidate keys, resolved to absolute.
|
||||
export function pickUrl(
|
||||
row: unknown,
|
||||
keys: string[],
|
||||
): string | null {
|
||||
if (!row || typeof row !== "object") return null;
|
||||
const record = row as Record<string, unknown>;
|
||||
for (const key of keys) {
|
||||
const found = readField(record, key);
|
||||
if (found) return assetUrl(found);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Common key sets per media kind. Ordered most-specific / full-URL first.
|
||||
// (`/media` returns the playable file in `external_url`; `/music` uses `url`.)
|
||||
export const SOUND_KEYS = [
|
||||
"url",
|
||||
"external_url",
|
||||
"sound_url",
|
||||
"sound",
|
||||
"audio_url",
|
||||
"audio",
|
||||
"file_url",
|
||||
"file",
|
||||
"file_path",
|
||||
];
|
||||
export const VIDEO_KEYS = [
|
||||
"external_url",
|
||||
"video_url",
|
||||
"video",
|
||||
"url",
|
||||
"file_url",
|
||||
"file",
|
||||
"file_path",
|
||||
];
|
||||
export const IMAGE_KEYS = [
|
||||
"image_url",
|
||||
"image",
|
||||
"thumbnail",
|
||||
"thumbnail_url",
|
||||
"cover",
|
||||
"url",
|
||||
"path",
|
||||
];
|
||||
Reference in New Issue
Block a user