From 940eeb96efd70c6b32eb6100c695730731a8ea73 Mon Sep 17 00:00:00 2001 From: "fengchuanhn@gmail.com" Date: Mon, 25 May 2026 01:15:42 +0800 Subject: [PATCH] 11 --- src-tauri/src/audio_db.rs | 18 ++++++++++++++ src-tauri/src/commands/fs_util.rs | 19 +++++++++++++++ src-tauri/src/commands/material.rs | 39 +++++++----------------------- src-tauri/src/material_db.rs | 31 ++++++++++++++---------- src-tauri/src/material_store.rs | 7 +++++- src/views/MaterialView.vue | 31 +++++++++++++++++++++--- 6 files changed, 98 insertions(+), 47 deletions(-) diff --git a/src-tauri/src/audio_db.rs b/src-tauri/src/audio_db.rs index 6ad2eff..242d51d 100644 --- a/src-tauri/src/audio_db.rs +++ b/src-tauri/src/audio_db.rs @@ -3,6 +3,7 @@ use std::path::PathBuf; use std::sync::Mutex; +use crate::commands::fs_util; use chrono::{Datelike, Local, Timelike}; use rusqlite::{params, Connection}; use serde::Serialize; @@ -182,16 +183,33 @@ impl AudioDb { return Ok(()); } let excess = count - MAX_RECORDS; + let mut stmt = conn.prepare( + "SELECT file_path FROM generated_audios ORDER BY id ASC LIMIT ?1", + )?; + let paths: Vec = stmt + .query_map(params![excess], |row| row.get(0))? + .filter_map(|r| r.ok()) + .collect(); conn.execute( "DELETE FROM generated_audios WHERE id IN ( SELECT id FROM generated_audios ORDER BY id ASC LIMIT ?1 )", params![excess], )?; + for path in paths { + if let Err(e) = fs_util::remove_allowed_local_media_file(&path) { + log::warn!(target: "audio", "裁剪历史时删除音频文件失败 {path}: {e}"); + } + } Ok(()) } pub fn delete(&self, id: i64) -> Result { + let Some(record) = self.get(id)? else { + return Ok(false); + }; + fs_util::remove_allowed_local_media_file(&record.file_path) + .map_err(AudioDbError::Message)?; let conn = self.conn.lock().map_err(|_| { AudioDbError::Message("语音数据库锁异常".into()) })?; diff --git a/src-tauri/src/commands/fs_util.rs b/src-tauri/src/commands/fs_util.rs index 525d081..e6877ac 100644 --- a/src-tauri/src/commands/fs_util.rs +++ b/src-tauri/src/commands/fs_util.rs @@ -26,6 +26,7 @@ fn is_allowed_local_media(path: &Path) -> bool { || lower.contains("aiclient-subtitle-bgm") || lower.contains("aiclient-cover") || lower.contains("aiclient-cover-previews") + || lower.contains("video-material") || lower.contains("avatars") { return true; @@ -38,6 +39,24 @@ fn is_allowed_local_media(path: &Path) -> bool { false } +/// 删除受信任目录下的本地媒体文件(语音/视频历史记录删除时清理磁盘)。 +pub(crate) fn remove_allowed_local_media_file(path: &str) -> Result<(), String> { + let normalized = normalize_path(path.trim()); + if normalized.as_os_str().is_empty() { + return Ok(()); + } + if !normalized.is_file() { + return Ok(()); + } + if !is_allowed_local_media(&normalized) { + return Err(format!( + "不允许删除该路径下的文件: {}", + normalized.display() + )); + } + std::fs::remove_file(&normalized).map_err(|e| format!("删除文件失败: {e}")) +} + /// 读取本地文件为 base64(用于 `