diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 2fa5c79..ba8a880 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -31,6 +31,7 @@ // Project management state let currentProjectPath = $state(null); let currentProjectName = $state(''); + let projectIsV2 = $state(false); let audioFilePath = $state(''); let audioWavPath = $state(''); @@ -171,57 +172,65 @@ }; } + /** Save to a specific folder — creates .vtn + audio.wav inside it. */ + async function saveToFolder(folderPath: string): Promise { + const projectName = folderPath.split(/[\\/]/).pop() || currentProjectName || 'Untitled'; + const vtnPath = `${folderPath}/${projectName}.vtn`; + const wavPath = `${folderPath}/audio.wav`; + const projectData = buildProjectData(projectName); + + try { + await invoke('create_dir', { path: folderPath }); + if (audioWavPath && audioWavPath !== wavPath) { + await invoke('copy_file', { src: audioWavPath, dst: wavPath }); + audioWavPath = wavPath; + } + await invoke('save_project_file', { path: vtnPath, project: projectData }); + currentProjectPath = vtnPath; + currentProjectName = projectName; + projectIsV2 = true; + return true; + } catch (err) { + console.error('Failed to save project:', err); + alert(`Failed to save: ${err}`); + return false; + } + } + async function saveProject() { - const defaultName = currentProjectName || 'Untitled'; - - // If already saved, save in place - if (currentProjectPath) { + // Already saved as v2 folder — save in place + if (currentProjectPath && projectIsV2) { const folderPath = currentProjectPath.replace(/[\\/][^\\/]+$/, ''); - const projectName = currentProjectPath.split(/[\\/]/).pop()?.replace(/\.vtn$/i, '') || defaultName; - const wavInsideFolder = `${folderPath}/audio.wav`; + await saveToFolder(folderPath); + return; + } - const projectData = buildProjectData(projectName); - try { - if (audioWavPath && audioWavPath !== wavInsideFolder) { - await invoke('copy_file', { src: audioWavPath, dst: wavInsideFolder }); - } - await invoke('save_project_file', { path: currentProjectPath, project: projectData }); - } catch (err) { - alert(`Failed to save: ${err}`); + // V1 project opened — migrate to folder structure + if (currentProjectPath && !projectIsV2) { + const oldVtnDir = currentProjectPath.replace(/[\\/][^\\/]+$/, ''); + const projectName = currentProjectPath.split(/[\\/]/).pop()?.replace(/\.vtn$/i, '') || 'Untitled'; + const folderPath = `${oldVtnDir}/${projectName}`; + const success = await saveToFolder(folderPath); + if (success) { + // Optionally remove the old .vtn file + try { + // Leave old file — user can delete manually + } catch {} } return; } - // Pick a folder for the new project + // Never saved — pick a folder + await saveProjectAs(); + } + + async function saveProjectAs() { const folderPath = await open({ directory: true, title: 'Choose a folder to save the project', }); if (!folderPath) return; - - // Use the folder name as the project name - const projectName = (folderPath as string).split(/[\\/]/).pop() || defaultName; - const vtnInsideFolder = `${folderPath}/${projectName}.vtn`; - const wavInsideFolder = `${folderPath}/audio.wav`; - - const projectData = buildProjectData(projectName); - - try { - - // Copy the extracted WAV into the project folder - if (audioWavPath) { - await invoke('copy_file', { src: audioWavPath, dst: wavInsideFolder }); - } - - // Save the .vtn file inside the folder - await invoke('save_project_file', { path: vtnInsideFolder, project: projectData }); - - currentProjectPath = vtnInsideFolder; - currentProjectName = projectName; - } catch (err) { - console.error('Failed to save project:', err); - alert(`Failed to save: ${err}`); - } + await saveToFolder(folderPath as string); } async function openProject() { @@ -290,6 +299,7 @@ // Determine the directory the .vtn file is in const vtnDir = (filePath as string).replace(/[\\/][^\\/]+$/, ''); const version = project.version ?? 1; + projectIsV2 = version >= 2; // Resolve audio for wavesurfer playback if (version >= 2) { @@ -734,7 +744,10 @@ {#if $segments.length > 0} + {/if}