feat: initial commit - Jhonny Editor
- Adicionado estrutura completa do projeto - Configurado MCP server para Premiere Pro - Adicionado documentação e skills - Configurado Gitignore para o projeto
This commit is contained in:
Executable
+71
@@ -0,0 +1,71 @@
|
||||
export type SilenceRange = { startSeconds: number; endSeconds: number };
|
||||
export type FrameRange = { startFrame: number; endFrame: number };
|
||||
|
||||
export type SilenceRemovalPlan = {
|
||||
frameRate: number;
|
||||
totalFrames: number;
|
||||
removedFrames: number;
|
||||
keptFrames: number;
|
||||
removalRanges: FrameRange[];
|
||||
keepRanges: FrameRange[];
|
||||
};
|
||||
|
||||
function finite(value: number, label: string): number {
|
||||
if (!Number.isFinite(value)) throw new Error(`${label} must be finite`);
|
||||
return value;
|
||||
}
|
||||
|
||||
export function planDerivedSilenceRemoval(input: {
|
||||
durationSeconds: number;
|
||||
frameRate: number;
|
||||
silenceRanges: SilenceRange[];
|
||||
keepHandleFrames?: number;
|
||||
maximumRemovals?: number;
|
||||
}): SilenceRemovalPlan {
|
||||
const duration = finite(input.durationSeconds, "durationSeconds");
|
||||
const frameRate = finite(input.frameRate, "frameRate");
|
||||
if (duration <= 0 || frameRate <= 0) throw new Error("durationSeconds and frameRate must be positive");
|
||||
if (!Array.isArray(input.silenceRanges)) throw new Error("silenceRanges must be an array");
|
||||
const keepHandleFrames = input.keepHandleFrames ?? 0;
|
||||
const maximumRemovals = input.maximumRemovals ?? 256;
|
||||
if (!Number.isInteger(keepHandleFrames) || keepHandleFrames < 0 || keepHandleFrames > 2400) throw new Error("keepHandleFrames must be an integer between 0 and 2400");
|
||||
if (!Number.isInteger(maximumRemovals) || maximumRemovals < 1 || maximumRemovals > 512) throw new Error("maximumRemovals must be an integer between 1 and 512");
|
||||
|
||||
const totalFrames = Math.floor(duration * frameRate + 1e-7);
|
||||
if (totalFrames < 1) throw new Error("media duration is shorter than one frame");
|
||||
const snappedSilenceRanges: FrameRange[] = [];
|
||||
for (let index = 0; index < input.silenceRanges.length; index += 1) {
|
||||
const range = input.silenceRanges[index];
|
||||
const start = finite(range?.startSeconds, `silenceRanges[${index}].startSeconds`);
|
||||
const end = finite(range?.endSeconds, `silenceRanges[${index}].endSeconds`);
|
||||
if (start < 0 || end <= start || end > duration + 1e-7) throw new Error(`silenceRanges[${index}] is outside the media duration`);
|
||||
const startFrame = Math.max(0, Math.ceil(start * frameRate - 1e-7));
|
||||
const endFrame = Math.min(totalFrames, Math.floor(end * frameRate + 1e-7));
|
||||
if (endFrame > startFrame) snappedSilenceRanges.push({ startFrame, endFrame });
|
||||
}
|
||||
snappedSilenceRanges.sort((left, right) => left.startFrame - right.startFrame || left.endFrame - right.endFrame);
|
||||
const mergedSilenceRanges: FrameRange[] = [];
|
||||
for (const candidate of snappedSilenceRanges) {
|
||||
const previous = mergedSilenceRanges.at(-1);
|
||||
if (previous && candidate.startFrame <= previous.endFrame) previous.endFrame = Math.max(previous.endFrame, candidate.endFrame);
|
||||
else mergedSilenceRanges.push({ ...candidate });
|
||||
}
|
||||
const removalRanges: FrameRange[] = [];
|
||||
for (const silence of mergedSilenceRanges) {
|
||||
const startFrame = silence.startFrame + keepHandleFrames;
|
||||
const endFrame = silence.endFrame - keepHandleFrames;
|
||||
if (endFrame > startFrame) removalRanges.push({ startFrame, endFrame });
|
||||
}
|
||||
if (removalRanges.length > maximumRemovals) throw new Error(`silence plan exceeds maximumRemovals (${maximumRemovals})`);
|
||||
|
||||
const keepRanges: FrameRange[] = [];
|
||||
let cursor = 0;
|
||||
for (const removal of removalRanges) {
|
||||
if (removal.startFrame > cursor) keepRanges.push({ startFrame: cursor, endFrame: removal.startFrame });
|
||||
cursor = removal.endFrame;
|
||||
}
|
||||
if (cursor < totalFrames) keepRanges.push({ startFrame: cursor, endFrame: totalFrames });
|
||||
if (!keepRanges.length) throw new Error("silence plan would remove the entire source");
|
||||
const removedFrames = removalRanges.reduce((sum, range) => sum + range.endFrame - range.startFrame, 0);
|
||||
return { frameRate, totalFrames, removedFrames, keptFrames: totalFrames - removedFrames, removalRanges, keepRanges };
|
||||
}
|
||||
Reference in New Issue
Block a user