ai-chatbot/lib/video-canvas/media-contract.ts

48 lines
1.6 KiB
TypeScript

import { z } from "zod";
const fraction = z.number().finite().min(0).max(1);
export const videoTimeRangeSchema = z
.object({ start: fraction, end: fraction })
.refine((range) => range.end > range.start, "结束位置必须晚于开始位置");
export type VideoTimeRange = z.infer<typeof videoTimeRangeSchema>;
export const videoProcessSchema = z.discriminatedUnion("operation", [
z.object({
operation: z.literal("crop"),
url: z.string().url(),
rect: z
.object({
x: fraction,
y: fraction,
width: fraction.positive(),
height: fraction.positive(),
})
.refine(
(rect) => rect.x + rect.width <= 1.001 && rect.y + rect.height <= 1.001,
"裁剪区域超出画面",
),
}),
z.object({ operation: z.literal("audio-video"), url: z.string().url() }),
z.object({
operation: z.literal("frame"),
url: z.string().url(),
kind: z.enum(["first", "last", "current"]),
time: z.number().finite().min(0).default(0),
}),
z.object({
operation: z.literal("slow"),
url: z.string().url(),
factor: z.union([z.literal(2), z.literal(3), z.literal(5)]),
}),
z.object({ operation: z.literal("trim"), url: z.string().url(), range: videoTimeRangeSchema }),
]);
export function toVideoTimeRange(range: VideoTimeRange, duration: number) {
if (!videoTimeRangeSchema.safeParse(range).success || !Number.isFinite(duration) || duration <= 0)
throw new Error("剪辑范围无效");
const start = range.start * duration;
const end = range.end * duration;
if (end - start < 0.1) throw new Error("剪辑时长不能少于 0.1 秒");
return { start, end, duration: end - start };
}