11
This commit is contained in:
@@ -3,6 +3,7 @@ pub mod app_config;
|
||||
pub mod auth;
|
||||
pub mod audio;
|
||||
pub mod avatar;
|
||||
pub mod video;
|
||||
pub mod fs_util;
|
||||
pub mod nodejs;
|
||||
pub mod quickjs;
|
||||
|
||||
121
src-tauri/src/commands/video.rs
Normal file
121
src-tauri/src/commands/video.rs
Normal file
@@ -0,0 +1,121 @@
|
||||
//! 工作流口播视频历史(SQLite + 文件落盘)
|
||||
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
|
||||
use tauri::{AppHandle, Manager, State};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::video_db::GeneratedVideoRecord;
|
||||
use crate::video_store::VideoStore;
|
||||
|
||||
fn normalize_path(path: &str) -> PathBuf {
|
||||
Path::new(path)
|
||||
.components()
|
||||
.filter(|c| !matches!(c, Component::ParentDir))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn generated_videos_dir(app: &AppHandle) -> Result<PathBuf, String> {
|
||||
let dir = app
|
||||
.path()
|
||||
.app_data_dir()
|
||||
.map_err(|e| format!("无法获取应用数据目录: {e}"))?
|
||||
.join("generated_videos");
|
||||
Ok(dir)
|
||||
}
|
||||
|
||||
fn is_under_generated_videos_dir(root: &Path, target: &Path) -> bool {
|
||||
if let (Ok(root), Ok(canonical)) = (root.canonicalize(), target.canonicalize()) {
|
||||
return canonical.starts_with(&root);
|
||||
}
|
||||
let root_s = root.to_string_lossy().to_lowercase();
|
||||
let target_s = target.to_string_lossy().to_lowercase();
|
||||
target_s.contains("generated_videos") && target_s.starts_with(&root_s)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn list_generated_videos(
|
||||
store: State<'_, VideoStore>,
|
||||
) -> Result<Vec<GeneratedVideoRecord>, String> {
|
||||
store.list().await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn insert_generated_video(
|
||||
store: State<'_, VideoStore>,
|
||||
name: String,
|
||||
file_path: String,
|
||||
avatar_id: Option<i64>,
|
||||
audio_id: Option<i64>,
|
||||
) -> Result<GeneratedVideoRecord, String> {
|
||||
store.insert(name, file_path, avatar_id, audio_id).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn delete_generated_video(
|
||||
app: AppHandle,
|
||||
store: State<'_, VideoStore>,
|
||||
id: i64,
|
||||
) -> Result<(), String> {
|
||||
let file_path = store.delete(id).await?;
|
||||
if let Some(path) = file_path {
|
||||
delete_video_file_if_allowed(&app, &path).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 将数字人输出视频复制到应用数据目录并写入 SQLite
|
||||
#[tauri::command]
|
||||
pub async fn import_generated_video(
|
||||
app: AppHandle,
|
||||
store: State<'_, VideoStore>,
|
||||
source_path: String,
|
||||
name: String,
|
||||
avatar_id: Option<i64>,
|
||||
audio_id: Option<i64>,
|
||||
) -> Result<GeneratedVideoRecord, String> {
|
||||
let src = normalize_path(source_path.trim());
|
||||
if !src.is_file() {
|
||||
return Err(format!("视频文件不存在: {}", src.display()));
|
||||
}
|
||||
|
||||
let ext = src
|
||||
.extension()
|
||||
.and_then(|e| e.to_str())
|
||||
.unwrap_or("mp4")
|
||||
.to_lowercase();
|
||||
let allowed = ["mp4", "mov", "webm", "mkv", "m4v", "avi"];
|
||||
if !allowed.contains(&ext.as_str()) {
|
||||
return Err("仅支持 mp4、mov、webm、mkv 等常见视频格式".into());
|
||||
}
|
||||
|
||||
let dir = generated_videos_dir(&app)?;
|
||||
tokio::fs::create_dir_all(&dir)
|
||||
.await
|
||||
.map_err(|e| format!("创建视频目录失败: {e}"))?;
|
||||
|
||||
let file_name = format!("{}.{}", Uuid::new_v4(), ext);
|
||||
let dest = dir.join(&file_name);
|
||||
|
||||
tokio::fs::copy(&src, &dest)
|
||||
.await
|
||||
.map_err(|e| format!("复制视频失败: {e}"))?;
|
||||
|
||||
store
|
||||
.insert(name, dest.to_string_lossy().to_string(), avatar_id, audio_id)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn delete_video_file_if_allowed(app: &AppHandle, path: &str) -> Result<(), String> {
|
||||
let target = normalize_path(path);
|
||||
let dir = generated_videos_dir(app)?;
|
||||
if !is_under_generated_videos_dir(&dir, &target) {
|
||||
return Err("不允许删除该路径下的文件".into());
|
||||
}
|
||||
if target.is_file() {
|
||||
tokio::fs::remove_file(&target)
|
||||
.await
|
||||
.map_err(|e| format!("删除文件失败: {e}"))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user