/*
[RFC-0210] Canonical media playback contract — the single, source-agnostic config that drives
every
- Do not resolve files — that is @warpgogol/werkstatt-site/content-source (resolveMedia) + the generated manifest.
- Do not implement playback or transcoding — that is @warpgogol/werkstatt-site/ui + the kernel command.
- RFC-0210: introduced the unified media playback contract + video manifest types.
- RFC-0525: added av1 field to VideoManifestSources for AV1 progressive delivery.
- RFC-0525: added opt-in av1 boolean to mediaSchema (default false) to skip slow AV1 encoding.
- RFC-0591: added maxSizeMb field to mediaSchema for two-pass bitrate-capped MP4 encoding.
- RFC-0950: added fullscreen field to mediaSchema for content-controlled edge-to-edge layout.
*/
import { z } from "zod";
import type { LivePhoto } from "./live-photo.ts";
/** The three delivery profiles. Profile drives generated formats, transport, player JS, and a11y. */
export const mediaProfileSchema = z.enum(["feature", "background", "ambient"]);
export type MediaProfile = z.infer;
/** When the loop starts (ambient/background) — mirrors RFC-0202 livePhotoTriggerSchema. */
export const mediaTriggerSchema = z.enum(["in-viewport", "tap", "autoplay"]);
export type MediaTrigger = z.infer;
/** Source addressing. Exactly one of `name` (explicit token) or `fromImage` (ambient convention). */
export const mediaSourceSchema = z
.object({
/** Bare media token (RFC-0053 style). Resolved like resolveImage: /assets/.. */
name: z.string().min(1).optional(),
/** Ambient only: derive the clip from a sibling image token (RFC-0202 convention). */
fromImage: z.string().min(1).optional(),
})
.strict();
export type MediaSource = z.infer;
/** One caption/subtitle track (WCAG 1.2.2). VTT resolved by convention (..vtt) or named. */
export const mediaCaptionSchema = z
.object({
lang: z.string().min(2),
label: z.string().optional(),
/** Default true: this track is shown by default for its language. */
default: z.boolean().optional(),
})
.strict();
export type MediaCaption = z.infer;
export const mediaSchema = z
.object({
profile: mediaProfileSchema.default("feature"),
source: mediaSourceSchema,
/** Poster image token. Defaults: sibling raster, else generated first-frame poster. */
poster: z.string().optional(),
/**
* Seconds offset for the auto-generated first-frame poster (ffmpeg `-ss`). Default 1.
* Use to skip an intro/title card and capture a representative, fully-rendered frame.
*/
posterTime: z.number().nonnegative().optional(),
/** Required by the validator for feature; ambient/background