feat: initial

This commit is contained in:
2026-06-03 03:08:57 +03:30
parent 3d9585ac5c
commit 6fa30eb29a
45 changed files with 7053 additions and 86 deletions
+76
View File
@@ -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",
];