新增日志导出选择
This commit is contained in:
parent
78c750bcbf
commit
763a14265d
@ -69,8 +69,9 @@ fn export_subtitles(
|
|||||||
state: tauri::State<'_, AppState>,
|
state: tauri::State<'_, AppState>,
|
||||||
task_id: String,
|
task_id: String,
|
||||||
format: String,
|
format: String,
|
||||||
|
output_path: String,
|
||||||
) -> std::result::Result<String, String> {
|
) -> std::result::Result<String, String> {
|
||||||
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]
|
#[tauri::command]
|
||||||
|
|||||||
@ -9,16 +9,6 @@ pub enum SubtitleFormat {
|
|||||||
Ass,
|
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 {
|
impl TryFrom<&str> for SubtitleFormat {
|
||||||
type Error = anyhow::Error;
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use std::{
|
|||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::Result;
|
||||||
use tauri::{Emitter, Manager, Window};
|
use tauri::{Emitter, Manager, Window};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
@ -740,24 +740,16 @@ pub fn export_task(
|
|||||||
state: tauri::State<'_, AppState>,
|
state: tauri::State<'_, AppState>,
|
||||||
task_id: String,
|
task_id: String,
|
||||||
format: String,
|
format: String,
|
||||||
|
output_path: String,
|
||||||
) -> Result<String> {
|
) -> Result<String> {
|
||||||
let task = state.get_task(&task_id)?;
|
let task = state.get_task(&task_id)?;
|
||||||
let format = SubtitleFormat::try_from(format.as_str())?;
|
let format = SubtitleFormat::try_from(format.as_str())?;
|
||||||
let content = render(&task.segments, format, task.bilingual_output);
|
let content = render(&task.segments, format, task.bilingual_output);
|
||||||
|
|
||||||
let source_path = PathBuf::from(&task.file_path);
|
let output_path = PathBuf::from(output_path);
|
||||||
let stem = source_path
|
if let Some(output_dir) = output_path.parent() {
|
||||||
.file_stem()
|
fs::create_dir_all(output_dir)?;
|
||||||
.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()));
|
|
||||||
fs::write(&output_path, content)?;
|
fs::write(&output_path, content)?;
|
||||||
|
|
||||||
Ok(output_path.display().to_string())
|
Ok(output_path.display().to_string())
|
||||||
|
|||||||
25
src/App.vue
25
src/App.vue
@ -2,7 +2,7 @@
|
|||||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { invoke } from '@tauri-apps/api/core'
|
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 { listen, type UnlistenFn } from '@tauri-apps/api/event'
|
||||||
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
|
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
|
||||||
import TaskQueue from './components/TaskQueue.vue'
|
import TaskQueue from './components/TaskQueue.vue'
|
||||||
@ -281,9 +281,30 @@ async function handleFiles(event: Event) {
|
|||||||
input.value = ''
|
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') {
|
async function handleExport(format: 'srt' | 'vtt' | 'ass') {
|
||||||
if (!selectedTask.value) return
|
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
|
feedback.value = output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -170,8 +170,8 @@ export const useTaskStore = defineStore('tasks', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async exportTask(taskId: string, format: ExportFormat) {
|
async exportTask(taskId: string, format: ExportFormat, outputPath: string) {
|
||||||
return invoke<string>('export_subtitles', { taskId, format })
|
return invoke<string>('export_subtitles', { taskId, format, outputPath })
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user