25 lines
1.6 KiB
TypeScript
25 lines
1.6 KiB
TypeScript
export function tvstarTiming(goal: string, shots: Array<{ duration: string }>) {
|
||
if (!shots.length) throw new Error("没有可生成的分镜");
|
||
const duration = /(\d+(?:\.\d+)?)\s*(秒钟|秒|s(?:ec(?:onds?)?)?|分钟|分|min(?:utes?)?)(?![a-z])/gi;
|
||
const requests = goal.split(/[,,。;;\n]/).flatMap(part => {
|
||
if (/(?:镜头\s*[0-9一二三四五六七八九十]+|片段\s*[0-9一二三四五六七八九十]+|单段|每段|每个镜头|关键帧\s*[0-9一二三四五六七八九十]*)/.test(part)
|
||
&& !/(?:总时长|整体时长|整片|全片|成片时长|片长)/.test(part)) return [];
|
||
return [...part.matchAll(duration)].map(match => {
|
||
const value = Number(match[1]);
|
||
return /^(?:分钟|分|min)/i.test(match[2]) ? value * 60 : value;
|
||
});
|
||
});
|
||
const requested = requests.at(-1) || 0;
|
||
const original = shots.map(shot => {
|
||
const duration = Number.parseFloat(shot.duration);
|
||
return Number.isFinite(duration) && duration > 0 ? duration : 5;
|
||
});
|
||
const sourceTotal = original.reduce((sum, duration) => sum + duration, 0);
|
||
const targetDuration = Math.max(1, Math.min(300, Math.round(requested || sourceTotal)));
|
||
const scale = targetDuration / sourceTotal;
|
||
const shotDurations = original.map(duration => Math.max(0.2, Math.round(duration * scale * 10) / 10));
|
||
const excess = Math.round((shotDurations.reduce((sum, duration) => sum + duration, 0) - targetDuration) * 10) / 10;
|
||
shotDurations[shotDurations.length - 1] = Math.max(0.2, Math.round((shotDurations.at(-1)! - excess) * 10) / 10);
|
||
return { targetDuration, shotDurations };
|
||
}
|