Deployment (t4g2): media-worker gains font-dejavu (drawtext lower-thirds) and a dedicated produce-worker compose service running src/produce.ts — claims video_processing_jobs compose|mix by lane, renders assembled/ overlaid/voiced cuts, registers derived library assets. Deliberately its own process so a remote-lane box needs only Postgres + S3 + ffmpeg. Web: compose media attachments UI (t2), Producer panel in the video drawer (t5), collective creation + branding settings + shell branding (brandweb), mobile CSS (mcss: touch targets, icon sizing, safe areas).
32 lines
1.5 KiB
TypeScript
32 lines
1.5 KiB
TypeScript
/**
|
|
* Produce worker env parsing: the two settings a produce box needs that are not
|
|
* plain pass-throughs — the lane this worker claims, and the lower-third font.
|
|
*
|
|
* Both are validated loudly at boot (a silently-defaulted lane would claim the
|
|
* wrong rows; a missing font fails every compose job at encode time, far too late).
|
|
*/
|
|
import { accessSync, constants } from "node:fs";
|
|
|
|
/** `MEDIA_WORKER_LANE`: default worker claims local-or-NULL, a remote worker only remote. */
|
|
export function laneFromEnv(value: string | undefined): "local" | "remote" {
|
|
if (value === undefined || value === "") return "local";
|
|
if (value === "local" || value === "remote") return value;
|
|
throw new Error(`MEDIA_WORKER_LANE must be 'local' or 'remote' (got ${JSON.stringify(value)})`);
|
|
}
|
|
|
|
/**
|
|
* `MEDIA_PRODUCE_FONT`: absolute path to a readable .ttf. Defaults to the
|
|
* DejaVu face present on the worker's base image; validated now (ENOENT at
|
|
* encode time is a 15-minute-late failure for the first job that needs it).
|
|
*/
|
|
export function resolveProduceFont(value: string | undefined): string {
|
|
const font = value ?? "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf";
|
|
if (!font.startsWith("/")) throw new Error("MEDIA_PRODUCE_FONT must be an absolute path");
|
|
if (!font.endsWith(".ttf")) throw new Error("MEDIA_PRODUCE_FONT must point to a .ttf");
|
|
try {
|
|
accessSync(font, constants.R_OK);
|
|
} catch {
|
|
throw new Error(`MEDIA_PRODUCE_FONT is not readable: ${font}`);
|
|
}
|
|
return font;
|
|
}
|