speed zones work now

This commit is contained in:
2026-04-15 20:17:05 -06:00
parent b7a795f986
commit 4d3d8a2218
8 changed files with 127 additions and 155 deletions

View File

@ -3,7 +3,6 @@ import { temporal } from 'zundo';
import type {
Word,
Segment,
DeletedRange,
CutRange,
MuteRange,
GainRange,
@ -21,7 +20,6 @@ interface EditorState {
exportedAudioPath: string | null; // path to modified audio from a previous export
words: Word[];
segments: Segment[];
deletedRanges: DeletedRange[];
cutRanges: CutRange[];
muteRanges: MuteRange[];
gainRanges: GainRange[];
@ -61,7 +59,6 @@ interface EditorActions {
setHoveredWordIndex: (index: number | null) => void;
deleteSelectedWords: () => void;
deleteWordRange: (startIndex: number, endIndex: number) => void;
restoreRange: (rangeId: string) => void;
addCutRange: (start: number, end: number, trimGroupId?: string) => void;
addMuteRange: (start: number, end: number) => void;
addGainRange: (start: number, end: number, gainDb: number) => void;
@ -97,7 +94,6 @@ const initialState: EditorState = {
exportedAudioPath: null,
words: [],
segments: [],
deletedRanges: [],
cutRanges: [],
muteRanges: [],
gainRanges: [],
@ -159,7 +155,7 @@ export const useEditorStore = create<EditorState & EditorActions>()(
setTranscriptionModel: (model) => set({ transcriptionModel: model }),
saveProject: (): ProjectFile => {
const { videoPath, words, segments, deletedRanges, cutRanges, muteRanges, gainRanges, speedRanges, globalGainDb, silenceTrimGroups, transcriptionModel, language, exportedAudioPath } = get();
const { videoPath, words, segments, cutRanges, muteRanges, gainRanges, speedRanges, globalGainDb, silenceTrimGroups, transcriptionModel, language, exportedAudioPath } = get();
if (!videoPath) throw new Error('No video loaded');
const now = new Date().toISOString();
// Strip globalStartIndex (runtime-only field) before persisting.
@ -175,7 +171,6 @@ export const useEditorStore = create<EditorState & EditorActions>()(
transcriptionModel: transcriptionModel ?? undefined,
words,
segments: persistSegments as unknown as Segment[],
deletedRanges,
cutRanges,
muteRanges,
gainRanges,
@ -210,7 +205,6 @@ export const useEditorStore = create<EditorState & EditorActions>()(
words: result.words,
segments: annotatedSegments,
language: result.language,
deletedRanges: [],
selectedWordIndices: [],
});
},
@ -222,44 +216,20 @@ export const useEditorStore = create<EditorState & EditorActions>()(
setHoveredWordIndex: (index) => set({ hoveredWordIndex: index }),
deleteSelectedWords: () => {
const { selectedWordIndices, words, deletedRanges } = get();
const { selectedWordIndices, words } = get();
if (selectedWordIndices.length === 0) return;
const sorted = [...selectedWordIndices].sort((a, b) => a - b);
const startWord = words[sorted[0]];
const endWord = words[sorted[sorted.length - 1]];
const newRange: DeletedRange = {
id: `dr_${nextRangeId++}`,
start: startWord.start,
end: endWord.end,
wordIndices: sorted,
};
set({
deletedRanges: [...deletedRanges, newRange],
selectedWordIndices: [],
});
get().addCutRange(startWord.start, endWord.end);
set({ selectedWordIndices: [] });
},
deleteWordRange: (startIndex, endIndex) => {
const { words, deletedRanges } = get();
const indices = [];
for (let i = startIndex; i <= endIndex; i++) indices.push(i);
const newRange: DeletedRange = {
id: `dr_${nextRangeId++}`,
start: words[startIndex].start,
end: words[endIndex].end,
wordIndices: indices,
};
set({ deletedRanges: [...deletedRanges, newRange] });
},
restoreRange: (rangeId) => {
const { deletedRanges } = get();
set({ deletedRanges: deletedRanges.filter((r) => r.id !== rangeId) });
const { words } = get();
get().addCutRange(words[startIndex].start, words[endIndex].end);
},
addCutRange: (start, end, trimGroupId) => {
@ -438,15 +408,10 @@ export const useEditorStore = create<EditorState & EditorActions>()(
}),
getKeepSegments: () => {
const { words, deletedRanges, cutRanges, duration } = get();
const { words, cutRanges, duration } = get();
if (words.length === 0) return [{ start: 0, end: duration }];
const deletedSet = new Set<number>();
for (const range of deletedRanges) {
for (const idx of range.wordIndices) deletedSet.add(idx);
}
// Also exclude words that fall within cut ranges
for (const cutRange of cutRanges) {
for (let i = 0; i < words.length; i++) {
const word = words[i];
@ -508,8 +473,11 @@ export const useEditorStore = create<EditorState & EditorActions>()(
videoUrl: url,
words: data.words || [],
segments: annotatedSegments,
deletedRanges: data.deletedRanges || [],
cutRanges: data.cutRanges || [],
// Backward compat: merge legacy deletedRanges into cutRanges as time-range cuts
cutRanges: [
...(data.cutRanges || []),
...(data.deletedRanges || []).map((r: any) => ({ id: r.id, start: r.start, end: r.end })),
],
muteRanges: data.muteRanges || [],
gainRanges: data.gainRanges || [],
speedRanges: data.speedRanges || [],