diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 1ac1833..027fa31 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -69,8 +69,9 @@ fn export_subtitles( state: tauri::State<'_, AppState>, task_id: String, format: String, + output_path: String, ) -> std::result::Result { - task::export_task(state, task_id, format).map_err(error_to_string) + task::export_task(state, task_id, format, output_path).map_err(error_to_string) } #[tauri::command] diff --git a/src-tauri/src/subtitle.rs b/src-tauri/src/subtitle.rs index 5e81f4d..ed23453 100644 --- a/src-tauri/src/subtitle.rs +++ b/src-tauri/src/subtitle.rs @@ -9,16 +9,6 @@ pub enum SubtitleFormat { Ass, } -impl SubtitleFormat { - pub fn extension(&self) -> &'static str { - match self { - Self::Srt => "srt", - Self::Vtt => "vtt", - Self::Ass => "ass", - } - } -} - impl TryFrom<&str> for SubtitleFormat { type Error = anyhow::Error; diff --git a/src-tauri/src/task.rs b/src-tauri/src/task.rs index 277b540..c29eee5 100644 --- a/src-tauri/src/task.rs +++ b/src-tauri/src/task.rs @@ -8,7 +8,7 @@ use std::{ time::Duration, }; -use anyhow::{Context, Result}; +use anyhow::Result; use tauri::{Emitter, Manager, Window}; use uuid::Uuid; @@ -740,24 +740,16 @@ pub fn export_task( state: tauri::State<'_, AppState>, task_id: String, format: String, + output_path: String, ) -> Result { let task = state.get_task(&task_id)?; let format = SubtitleFormat::try_from(format.as_str())?; let content = render(&task.segments, format, task.bilingual_output); - let source_path = PathBuf::from(&task.file_path); - let stem = source_path - .file_stem() - .and_then(|item| item.to_str()) - .unwrap_or("subtitle"); - - let output_dir = source_path - .parent() - .map(PathBuf::from) - .unwrap_or(std::env::current_dir().context("failed to get current directory")?); - fs::create_dir_all(&output_dir)?; - - let output_path = output_dir.join(format!("{stem}.{}", format.extension())); + let output_path = PathBuf::from(output_path); + if let Some(output_dir) = output_path.parent() { + fs::create_dir_all(output_dir)?; + } fs::write(&output_path, content)?; Ok(output_path.display().to_string()) diff --git a/src/App.vue b/src/App.vue index d855fef..db2219d 100644 --- a/src/App.vue +++ b/src/App.vue @@ -2,7 +2,7 @@ import { computed, onMounted, onUnmounted, ref, watch } from 'vue' import { useI18n } from 'vue-i18n' import { invoke } from '@tauri-apps/api/core' -import { open } from '@tauri-apps/plugin-dialog' +import { open, save } from '@tauri-apps/plugin-dialog' import { listen, type UnlistenFn } from '@tauri-apps/api/event' import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow' import TaskQueue from './components/TaskQueue.vue' @@ -281,9 +281,30 @@ async function handleFiles(event: Event) { input.value = '' } +function getDefaultExportPath(filePath: string, format: 'srt' | 'vtt' | 'ass') { + const separatorIndex = Math.max(filePath.lastIndexOf('/'), filePath.lastIndexOf('\\')) + const directory = separatorIndex >= 0 ? filePath.slice(0, separatorIndex + 1) : '' + const fileName = separatorIndex >= 0 ? filePath.slice(separatorIndex + 1) : filePath + const stem = fileName.replace(/\.[^./\\]*$/, '') || 'subtitle' + return `${directory}${stem}.${format}` +} + async function handleExport(format: 'srt' | 'vtt' | 'ass') { if (!selectedTask.value) return - const output = await taskStore.exportTask(selectedTask.value.id, format) + const outputPath = await save({ + title: t('app.exportSubtitles'), + defaultPath: getDefaultExportPath(selectedTask.value.filePath, format), + filters: [ + { + name: format.toUpperCase(), + extensions: [format], + }, + ], + }) + + if (!outputPath) return + + const output = await taskStore.exportTask(selectedTask.value.id, format, outputPath) feedback.value = output } diff --git a/src/stores/tasks.ts b/src/stores/tasks.ts index d9b56fb..d501c7f 100644 --- a/src/stores/tasks.ts +++ b/src/stores/tasks.ts @@ -170,8 +170,8 @@ export const useTaskStore = defineStore('tasks', { } }, - async exportTask(taskId: string, format: ExportFormat) { - return invoke('export_subtitles', { taskId, format }) + async exportTask(taskId: string, format: ExportFormat, outputPath: string) { + return invoke('export_subtitles', { taskId, format, outputPath }) }, }, })