Files
ttstd-infinite-canvas/web/src/lib/video-generation-options.ts

87 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export const VIDEO_DURATION_OPTIONS = [6, 9, 10, 15] as const;
export const VIDEO_RESOLUTION_OPTIONS = [480, 720, 1080, 1440, 2160] as const;
export const VIDEO_RESOLUTION_CAPABILITY_OPTIONS = VIDEO_RESOLUTION_OPTIONS.map((value) => `${value}p`);
export const VIDEO_DURATION_MIN = 1;
export function normalizeVideoDuration(value: string | number | undefined) {
const seconds = Math.floor(Number(value) || VIDEO_DURATION_OPTIONS[0]);
return String(Math.max(VIDEO_DURATION_MIN, seconds));
}
export function normalizeVideoResolution(value: string | number | undefined) {
const raw = String(value || "").trim();
const token = raw.toLowerCase();
if (!token) return "";
if (token === "low") return "480";
if (token === "auto" || token === "medium" || token === "high") return "720";
if (token === "2k") return "1440";
if (token === "4k") return "2160";
const resolution = Number(token.replace(/p$/i, ""));
if (Number.isFinite(resolution) && resolution > 0) return String(Math.floor(resolution));
// Channel-declared values are opaque enums, not necessarily numeric tiers.
// Preserve them verbatim so values such as `768p竖` remain selectable and
// can be sent back to the provider without being collapsed to 720p.
return raw;
}
export function normalizeVideoResolutionValue(value: string | number | undefined): string {
return normalizeVideoResolution(value) || "720";
}
export function isVideoResolutionMatch(selected: string | undefined, target: string | undefined) {
const s = String(selected || "").trim().toLowerCase().replace(/p$/i, "");
const t = String(target || "").trim().toLowerCase().replace(/p$/i, "");
if (!s && !t) return true;
if (s === t) return true;
if ((s === "2k" || s === "1440") && (t === "2k" || t === "1440")) return true;
if ((s === "4k" || s === "2160") && (t === "4k" || t === "2160")) return true;
if ((s === "768" || s === "768p") && (t === "768" || t === "768p")) return true;
if ((s === "1080" || s === "1080p") && (t === "1080" || t === "1080p")) return true;
if ((s === "720" || s === "720p") && (t === "720" || t === "720p")) return true;
if ((s === "480" || s === "480p") && (t === "480" || t === "480p")) return true;
return false;
}
export function videoResolutionComparisonKey(value: string | number | undefined) {
const raw = String(value || "").trim();
if (!raw) return "";
const normalized = normalizeVideoResolution(raw);
return /^\d+$/.test(normalized) ? `${normalized}p` : normalized.toLowerCase();
}
export function formatVideoResolutionLabel(value: string | number | undefined) {
const raw = String(value || "").trim();
if (!raw) return "";
const normalized = normalizeVideoResolution(raw);
if (normalized === "1440" || normalized.toLowerCase() === "2k") return "2K";
if (normalized === "2160" || normalized.toLowerCase() === "4k") return "4K";
if (/^\d+$/.test(normalized)) return `${normalized}P`;
return normalized.replace(/^(\d+)p/i, "$1P");
}
export function videoDimensionsForRatioAndResolution(ratio: string | undefined, resolution: string | number | undefined) {
const ratioMatch = String(ratio || "")
.trim()
.toLowerCase()
.replace("×", "x")
.match(/^(\d+(?:\.\d+)?)(?::|x)(\d+(?:\.\d+)?)$/);
if (!ratioMatch) return undefined;
const ratioWidth = Number(ratioMatch[1]);
const ratioHeight = Number(ratioMatch[2]);
if (!Number.isFinite(ratioWidth) || !Number.isFinite(ratioHeight) || ratioWidth <= 0 || ratioHeight <= 0) return undefined;
const normalizedResolution = normalizeVideoResolution(resolution);
const resolutionMatch = normalizedResolution.match(/^(\d+)(?:p)?/i);
const shortEdge = Number(resolutionMatch?.[1]);
if (!Number.isFinite(shortEdge) || shortEdge <= 0) return undefined;
const aspect = ratioWidth / ratioHeight;
if (aspect >= 1) return { width: evenDimension(shortEdge * aspect), height: shortEdge };
return { width: shortEdge, height: evenDimension(shortEdge / aspect) };
}
function evenDimension(value: number) {
return Math.max(2, Math.round(value / 2) * 2);
}