From 33a1dfa27b89321f2b72a0946866c2d60f1e93a0 Mon Sep 17 00:00:00 2001 From: Julian Freeman Date: Tue, 3 Mar 2026 17:02:40 -0400 Subject: [PATCH] add clean browsers --- src-tauri/src/cleaner.rs | 115 ++++++++++++ src-tauri/src/lib.rs | 18 +- src/App.vue | 365 +++++++++++++++++++++++++++++++++------ 3 files changed, 441 insertions(+), 57 deletions(-) diff --git a/src-tauri/src/cleaner.rs b/src-tauri/src/cleaner.rs index 4bc66bf..375be69 100644 --- a/src-tauri/src/cleaner.rs +++ b/src-tauri/src/cleaner.rs @@ -365,3 +365,118 @@ fn clean_directory_contents(path: &Path, filter_days: Option) -> (u64, u32, } (freed, success, fail) } + +// --- 浏览器清理逻辑 --- + +#[derive(Serialize, Clone)] +pub struct BrowserProfile { + pub name: String, + pub path_name: String, + pub cache_size: u64, + pub cache_size_str: String, +} + +#[derive(Serialize)] +pub struct BrowserScanResult { + pub profiles: Vec, + pub total_size: String, +} + +pub enum BrowserType { + Chrome, + Edge, +} + +impl BrowserType { + fn get_user_data_path(&self) -> Result { + let local_app_data = std::env::var("LOCALAPPDATA").map_err(|_| "无法获取 LocalAppData 路径")?; + let base = std::path::Path::new(&local_app_data); + match self { + BrowserType::Chrome => Ok(base.join("Google\\Chrome\\User Data")), + BrowserType::Edge => Ok(base.join("Microsoft\\Edge\\User Data")), + } + } +} + +pub async fn run_browser_scan(browser: BrowserType) -> Result { + let user_data_path = browser.get_user_data_path()?; + let local_state_path = user_data_path.join("Local State"); + + let mut profiles = Vec::new(); + let mut total_bytes = 0; + + if local_state_path.exists() { + let content = fs::read_to_string(local_state_path).map_err(|e| e.to_string())?; + let v: serde_json::Value = serde_json::from_str(&content).map_err(|e| e.to_string())?; + + if let Some(info_cache) = v.get("profile").and_then(|p| p.get("info_cache")).and_then(|i| i.as_object()) { + for (dir_name, info) in info_cache { + let profile_display_name = info.get("name").and_then(|n| n.as_str()).unwrap_or(dir_name); + let profile_path = user_data_path.join(dir_name); + + if profile_path.exists() { + let mut size = 0; + // 扫描常见的缓存目录 + let cache_dirs = ["Cache", "Code Cache", "GPUCache", "Media Cache"]; + for sub in cache_dirs { + let target = profile_path.join(sub); + if target.exists() { + size += get_dir_size_simple(&target); + } + } + + total_bytes += size; + profiles.push(BrowserProfile { + name: profile_display_name.to_string(), + path_name: dir_name.clone(), + cache_size: size, + cache_size_str: format_size(size), + }); + } + } + } + } + + Ok(BrowserScanResult { + profiles, + total_size: format_size(total_bytes), + }) +} + +fn get_dir_size_simple(path: &std::path::Path) -> u64 { + walkdir::WalkDir::new(path) + .into_iter() + .filter_map(|e| e.ok()) + .filter(|e| e.file_type().is_file()) + .map(|e| e.metadata().map(|m| m.len()).unwrap_or(0)) + .sum() +} + +pub async fn run_browser_clean(browser: BrowserType, profile_paths: Vec) -> Result { + let user_data_path = browser.get_user_data_path()?; + let mut total_freed = 0; + let mut success_count = 0; + let mut fail_count = 0; + + for profile_dir in profile_paths { + let profile_path = user_data_path.join(&profile_dir); + if profile_path.exists() { + let cache_dirs = ["Cache", "Code Cache", "GPUCache", "Media Cache"]; + for sub in cache_dirs { + let target = profile_path.join(sub); + if target.exists() { + let (f, s, fl) = clean_directory_contents(&target, None); + total_freed += f; + success_count += s; + fail_count += fl; + } + } + } + } + + Ok(CleanResult { + total_freed: format_size(total_freed), + success_count, + fail_count, + }) +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index bb9a6cd..ead23fc 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -46,6 +46,20 @@ async fn disable_hibernation() -> Result { cleaner::disable_hibernation().await } +// --- 浏览器清理命令 --- + +#[tauri::command] +async fn start_browser_scan(browser: String) -> Result { + let b_type = if browser == "chrome" { cleaner::BrowserType::Chrome } else { cleaner::BrowserType::Edge }; + cleaner::run_browser_scan(b_type).await +} + +#[tauri::command] +async fn start_browser_clean(browser: String, profiles: Vec) -> Result { + let b_type = if browser == "chrome" { cleaner::BrowserType::Chrome } else { cleaner::BrowserType::Edge }; + cleaner::run_browser_clean(b_type, profiles).await +} + #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() @@ -62,7 +76,9 @@ pub fn run() { open_in_explorer, clean_system_components, clean_thumbnails, - disable_hibernation + disable_hibernation, + start_browser_scan, + start_browser_clean ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src/App.vue b/src/App.vue index 6532c2c..df348b5 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,19 +1,22 @@