23 lines
1.2 KiB
TypeScript
23 lines
1.2 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("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 };
|
|
}
|