added cut and mute zones

This commit is contained in:
2026-04-03 11:14:31 -06:00
parent d7bc6ea74d
commit 585262c3e7
13 changed files with 554 additions and 117 deletions

View File

@ -1,6 +1,6 @@
import { create } from 'zustand';
import { temporal } from 'zundo';
import type { Word, Segment, DeletedRange, TranscriptionResult, ProjectFile } from '../types/project';
import type { Word, Segment, DeletedRange, CutRange, MuteRange, TranscriptionResult, ProjectFile } from '../types/project';
interface EditorState {
videoPath: string | null;
@ -9,6 +9,8 @@ interface EditorState {
words: Word[];
segments: Segment[];
deletedRanges: DeletedRange[];
cutRanges: CutRange[];
muteRanges: MuteRange[];
language: string;
currentTime: number;
@ -41,6 +43,10 @@ interface EditorActions {
deleteSelectedWords: () => void;
deleteWordRange: (startIndex: number, endIndex: number) => void;
restoreRange: (rangeId: string) => void;
addCutRange: (start: number, end: number) => void;
addMuteRange: (start: number, end: number) => void;
removeCutRange: (id: string) => void;
removeMuteRange: (id: string) => void;
setTranscribing: (active: boolean, progress?: number, status?: string) => void;
setExporting: (active: boolean, progress?: number) => void;
getKeepSegments: () => Array<{ start: number; end: number }>;
@ -56,6 +62,8 @@ const initialState: EditorState = {
words: [],
segments: [],
deletedRanges: [],
cutRanges: [],
muteRanges: [],
language: '',
currentTime: 0,
duration: 0,
@ -82,7 +90,7 @@ export const useEditorStore = create<EditorState & EditorActions>()(
setExportedAudioPath: (path) => set({ exportedAudioPath: path }),
saveProject: (): ProjectFile => {
const { videoPath, words, segments, deletedRanges, language, exportedAudioPath } = get();
const { videoPath, words, segments, deletedRanges, cutRanges, muteRanges, language, exportedAudioPath } = get();
if (!videoPath) throw new Error('No video loaded');
const now = new Date().toISOString();
// Strip globalStartIndex (runtime-only field) before persisting
@ -94,6 +102,8 @@ export const useEditorStore = create<EditorState & EditorActions>()(
words,
segments: persistSegments as unknown as Segment[],
deletedRanges,
cutRanges,
muteRanges,
language,
createdAt: now, // will be overwritten if we track original creation time later
modifiedAt: now,
@ -174,11 +184,41 @@ export const useEditorStore = create<EditorState & EditorActions>()(
set({ deletedRanges: deletedRanges.filter((r) => r.id !== rangeId) });
},
addCutRange: (start, end) => {
const { cutRanges } = get();
const newRange: CutRange = {
id: `cut_${nextRangeId++}`,
start,
end,
};
set({ cutRanges: [...cutRanges, newRange] });
},
addMuteRange: (start, end) => {
const { muteRanges } = get();
const newRange: MuteRange = {
id: `mute_${nextRangeId++}`,
start,
end,
};
set({ muteRanges: [...muteRanges, newRange] });
},
removeCutRange: (id) => {
const { cutRanges } = get();
set({ cutRanges: cutRanges.filter((r) => r.id !== id) });
},
removeMuteRange: (id) => {
const { muteRanges } = get();
set({ muteRanges: muteRanges.filter((r) => r.id !== id) });
},
setTranscribing: (active, progress, status) =>
set({
isTranscribing: active,
transcriptionProgress: progress ?? (active ? 0 : 100),
transcriptionStatus: status ?? (active ? '' : ''),
transcriptionStatus: status ?? (active ? 'Transcribing...' : ''),
}),
setExporting: (active, progress) =>
@ -188,7 +228,7 @@ export const useEditorStore = create<EditorState & EditorActions>()(
}),
getKeepSegments: () => {
const { words, deletedRanges, duration } = get();
const { words, deletedRanges, cutRanges, duration } = get();
if (words.length === 0) return [{ start: 0, end: duration }];
const deletedSet = new Set<number>();
@ -196,6 +236,16 @@ export const useEditorStore = create<EditorState & EditorActions>()(
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];
if (word.start >= cutRange.start && word.end <= cutRange.end) {
deletedSet.add(i);
}
}
}
const segments: Array<{ start: number; end: number }> = [];
let segStart: number | null = null;
@ -249,6 +299,8 @@ export const useEditorStore = create<EditorState & EditorActions>()(
words: data.words || [],
segments: annotatedSegments,
deletedRanges: data.deletedRanges || [],
cutRanges: data.cutRanges || [],
muteRanges: data.muteRanges || [],
language: data.language || '',
exportedAudioPath: data.exportedAudioPath ?? null,
});