Files
songs2vid/lib/fonts-server.ts
T
Atakan Doğan Özban 9404efd86c Align preview typography with FFmpeg output, add video/song title split, and ship OSS updates.
Separate YouTube video titles from on-video song/artist fields with Pro gating, serve curated fonts and watermark assets for 1:1 preview parity, and include billing/API/docs/deploy stack for self-hosted release.
2026-07-27 16:26:19 +02:00

45 lines
1.5 KiB
TypeScript

/** Server-only font filesystem helpers. Do not import from client components. */
import fs from "fs/promises";
import path from "path";
import { CURATED_FONTS, type CuratedFontKey } from "./fonts";
export function getFontsDir(): string {
return path.join(process.cwd(), "assets", "fonts");
}
/** Resolve a curated font file on disk (must exist under assets/fonts). */
export function resolveCuratedFontPath(key: CuratedFontKey): string {
const meta = CURATED_FONTS.find((f) => f.key === key);
if (!meta) throw new Error("Unknown font");
// Whitelist filename only never accept user-controlled path segments
const safe = meta.file.replace(/[^a-zA-Z0-9._-]/g, "");
if (safe !== meta.file) throw new Error("Invalid font asset name");
return path.join(getFontsDir(), safe);
}
/**
* Validate TTF / OTF magic bytes.
* TTF: 00 01 00 00 | true | typ1
* OTF: OTTO
*/
export async function assertFontFile(filePath: string): Promise<"ttf" | "otf"> {
const fh = await fs.open(filePath, "r");
try {
const buf = Buffer.alloc(4);
await fh.read(buf, 0, 4, 0);
const asStr = buf.toString("ascii");
if (asStr === "OTTO") return "otf";
if (asStr === "true" || asStr === "typ1") return "ttf";
if (buf[0] === 0x00 && buf[1] === 0x01 && buf[2] === 0x00 && buf[3] === 0x00) {
return "ttf";
}
if (asStr === "wOFF" || asStr === "wOF2") {
throw new Error("WOFF fonts are not supported. Upload a .ttf or .otf file.");
}
throw new Error("File is not a valid TTF or OTF font");
} finally {
await fh.close();
}
}