111
This commit is contained in:
@@ -16,10 +16,15 @@ const APP_COMMANDS: &[&str] = &[
|
||||
"run_nodejs_script_source",
|
||||
"list_nodejs_scripts",
|
||||
"read_local_file_base64",
|
||||
"write_local_file_base64",
|
||||
"get_media_duration_seconds",
|
||||
"copy_local_file",
|
||||
"write_local_text_file",
|
||||
"temp_voice_reference_path",
|
||||
"stage_voice_reference_audio",
|
||||
"import_voice_clone_reference",
|
||||
"reveal_local_file_in_folder",
|
||||
"stop_nodejs_script",
|
||||
"list_avatars",
|
||||
"insert_avatar",
|
||||
"update_avatar_name",
|
||||
|
||||
@@ -18,10 +18,15 @@ permissions = [
|
||||
"allow-run-nodejs-script-source",
|
||||
"allow-list-nodejs-scripts",
|
||||
"allow-read-local-file-base64",
|
||||
"allow-write-local-file-base64",
|
||||
"allow-get-media-duration-seconds",
|
||||
"allow-copy-local-file",
|
||||
"allow-write-local-text-file",
|
||||
"allow-temp-voice-reference-path",
|
||||
"allow-stage-voice-reference-audio",
|
||||
"allow-import-voice-clone-reference",
|
||||
"allow-reveal-local-file-in-folder",
|
||||
"allow-stop-nodejs-script",
|
||||
"allow-list-avatars",
|
||||
"allow-insert-avatar",
|
||||
"allow-update-avatar-name",
|
||||
|
||||
@@ -14,6 +14,46 @@ fn normalize_path(path: &str) -> PathBuf {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// 解析用户通过系统对话框选择的文件路径(兼容 file:// 与 /C:/ 形式)。
|
||||
fn resolve_user_selected_file(path: &str) -> Result<PathBuf, String> {
|
||||
let mut trimmed = path.trim();
|
||||
if trimmed.is_empty() {
|
||||
return Err("路径为空".into());
|
||||
}
|
||||
if let Some(rest) = trimmed.strip_prefix("file:///") {
|
||||
trimmed = rest;
|
||||
} else if let Some(rest) = trimmed.strip_prefix("file://") {
|
||||
trimmed = rest;
|
||||
}
|
||||
// `/C:/Users/...` → `C:/Users/...`
|
||||
if trimmed.len() >= 3 {
|
||||
let bytes = trimmed.as_bytes();
|
||||
if bytes[0] == b'/' && bytes[2] == b':' {
|
||||
trimmed = &trimmed[1..];
|
||||
}
|
||||
}
|
||||
|
||||
let direct = PathBuf::from(trimmed);
|
||||
if direct.is_file() {
|
||||
return Ok(direct);
|
||||
}
|
||||
let normalized = normalize_path(trimmed);
|
||||
if normalized.is_file() {
|
||||
return Ok(normalized);
|
||||
}
|
||||
if let Ok(canonical) = dunce::canonicalize(&direct) {
|
||||
if canonical.is_file() {
|
||||
return Ok(canonical);
|
||||
}
|
||||
}
|
||||
if let Ok(canonical) = dunce::canonicalize(&normalized) {
|
||||
if canonical.is_file() {
|
||||
return Ok(canonical);
|
||||
}
|
||||
}
|
||||
Err(format!("文件不存在: {trimmed}"))
|
||||
}
|
||||
|
||||
/// 仅允许读取临时目录下的试听/流水线产物,避免任意路径读取。
|
||||
fn is_allowed_local_media(path: &Path) -> bool {
|
||||
let lower = path.to_string_lossy().to_lowercase();
|
||||
@@ -165,6 +205,34 @@ fn voice_clones_dir(app: &tauri::AppHandle) -> Result<PathBuf, String> {
|
||||
Ok(dir)
|
||||
}
|
||||
|
||||
/// 将用户通过文件对话框选择的音频复制到临时目录,供时长探测与试听。
|
||||
#[tauri::command]
|
||||
pub async fn stage_voice_reference_audio(source_path: String) -> Result<String, String> {
|
||||
let source = resolve_user_selected_file(&source_path)?;
|
||||
let ext = source
|
||||
.extension()
|
||||
.and_then(|e| e.to_str())
|
||||
.unwrap_or("wav");
|
||||
let ext = if ext.is_empty() { "wav" } else { ext };
|
||||
let dir = std::env::temp_dir().join("aiclient-voice-ref");
|
||||
tokio::fs::create_dir_all(&dir)
|
||||
.await
|
||||
.map_err(|e| format!("创建临时目录失败: {e}"))?;
|
||||
let dest = dir.join(format!(
|
||||
"upload_{}_{}.{}",
|
||||
std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.map(|d| d.as_millis())
|
||||
.unwrap_or(0),
|
||||
rand_simple(),
|
||||
ext
|
||||
));
|
||||
tokio::fs::copy(&source, &dest)
|
||||
.await
|
||||
.map_err(|e| format!("复制参考音频失败: {e}"))?;
|
||||
Ok(dest.to_string_lossy().into_owned())
|
||||
}
|
||||
|
||||
/// 生成临时参考音频路径(录音/上传中转)。
|
||||
#[tauri::command]
|
||||
pub async fn temp_voice_reference_path(ext: String) -> Result<String, String> {
|
||||
|
||||
@@ -137,6 +137,7 @@ pub fn run() {
|
||||
commands::fs_util::copy_local_file,
|
||||
commands::fs_util::write_local_text_file,
|
||||
commands::fs_util::temp_voice_reference_path,
|
||||
commands::fs_util::stage_voice_reference_audio,
|
||||
commands::fs_util::import_voice_clone_reference,
|
||||
commands::fs_util::reveal_local_file_in_folder,
|
||||
commands::avatar::list_avatars,
|
||||
|
||||
Reference in New Issue
Block a user