close sh;able to save/load projects

This commit is contained in:
2026-03-30 18:36:41 -06:00
parent 246d816f84
commit ea3f1d2b23
15 changed files with 44871 additions and 31 deletions

View File

@ -1,10 +1,11 @@
import { create } from 'zustand';
import { temporal } from 'zundo';
import type { Word, Segment, DeletedRange, TranscriptionResult } from '../types/project';
import type { Word, Segment, DeletedRange, TranscriptionResult, ProjectFile } from '../types/project';
interface EditorState {
videoPath: string | null;
videoUrl: string | null;
exportedAudioPath: string | null; // path to modified audio from a previous export
words: Word[];
segments: Segment[];
deletedRanges: DeletedRange[];
@ -29,6 +30,8 @@ interface EditorState {
interface EditorActions {
setBackendUrl: (url: string) => void;
loadVideo: (path: string) => void;
setExportedAudioPath: (path: string | null) => void;
saveProject: () => ProjectFile;
setTranscription: (result: TranscriptionResult) => void;
setCurrentTime: (time: number) => void;
setDuration: (duration: number) => void;
@ -49,6 +52,7 @@ interface EditorActions {
const initialState: EditorState = {
videoPath: null,
videoUrl: null,
exportedAudioPath: null,
words: [],
segments: [],
deletedRanges: [],
@ -75,6 +79,27 @@ export const useEditorStore = create<EditorState & EditorActions>()(
setBackendUrl: (url) => set({ backendUrl: url }),
setExportedAudioPath: (path) => set({ exportedAudioPath: path }),
saveProject: (): ProjectFile => {
const { videoPath, words, segments, deletedRanges, language, exportedAudioPath } = get();
if (!videoPath) throw new Error('No video loaded');
const now = new Date().toISOString();
// Strip globalStartIndex (runtime-only field) before persisting
const persistSegments = segments.map(({ globalStartIndex: _drop, ...rest }) => rest);
return {
version: 1,
videoPath,
exportedAudioPath: exportedAudioPath ?? undefined,
words,
segments: persistSegments as unknown as Segment[],
deletedRanges,
language,
createdAt: now, // will be overwritten if we track original creation time later
modifiedAt: now,
};
},
loadVideo: (path) => {
const backend = get().backendUrl;
const url = `${backend}/file?path=${encodeURIComponent(path)}`;
@ -225,6 +250,7 @@ export const useEditorStore = create<EditorState & EditorActions>()(
segments: annotatedSegments,
deletedRanges: data.deletedRanges || [],
language: data.language || '',
exportedAudioPath: data.exportedAudioPath ?? null,
});
},