improve scanning speed

This commit is contained in:
Lncvrt committed 2026-04-14 23:08:12 -07:00
1 parent 10caf9d56e
commit f98706ed85
2 files changed
+49 -36

No files matched your search

+33 -27
View File
@@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sysinfo::Disks; use sysinfo::Disks;
use tauri::{WebviewUrl, WebviewWindowBuilder}; use tauri::{Emitter, WebviewUrl, WebviewWindowBuilder};
use tauri_plugin_shell::ShellExt; use tauri_plugin_shell::ShellExt;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
@@ -53,7 +53,7 @@ async fn get_file_info_from_dirs(
app: tauri::AppHandle, app: tauri::AppHandle,
path: String, path: String,
min_ratio: String, min_ratio: String,
) -> Result<DirScanResult, String> { ) -> Result<(), String> {
let cmd = app let cmd = app
.shell() .shell()
.sidecar("pdu") .sidecar("pdu")
@@ -70,58 +70,64 @@ async fn get_file_info_from_dirs(
let output = cmd.output().await.map_err(|e| e.to_string())?; let output = cmd.output().await.map_err(|e| e.to_string())?;
if !output.status.success() { if !output.status.success() {
return Err(format!( return Err(String::from_utf8_lossy(&output.stderr).to_string());
"pdu failed: {}",
String::from_utf8_lossy(&output.stderr)
));
} }
let stdout = String::from_utf8_lossy(&output.stdout); let stdout = String::from_utf8_lossy(&output.stdout);
let json: serde_json::Value = let json: serde_json::Value = serde_json::from_str(&stdout).map_err(|e| e.to_string())?;
serde_json::from_str(&stdout).map_err(|e| format!("JSON parse failed: {}", e))?;
let mut items = Vec::new();
if let Some(tree) = json.get("tree") { if let Some(tree) = json.get("tree") {
extract_files(tree, "", &mut items); let mut batch: Vec<FileInfo> = Vec::new();
stream_extract(tree, "", &mut batch, &app);
} }
let total_size = items.iter().map(|i| i.size).sum(); Ok(())
Ok(DirScanResult {
items,
total_size,
error: None,
})
} }
fn extract_files(node: &serde_json::Value, parent_path: &str, items: &mut Vec<FileInfo>) { fn stream_extract(
if let Some(name) = node.get("name").and_then(|v| v.as_str()) { node: &serde_json::Value,
parent_path: &str,
batch: &mut Vec<FileInfo>,
app: &tauri::AppHandle,
) {
let name = match node.get("name").and_then(|v| v.as_str()) {
Some(n) => n,
None => return,
};
let size = node.get("size").and_then(|v| v.as_u64()).unwrap_or(0); let size = node.get("size").and_then(|v| v.as_u64()).unwrap_or(0);
let children = node.get("children").and_then(|v| v.as_array()); let children = node.get("children").and_then(|v| v.as_array());
let is_dir = children.as_ref().map(|c| !c.is_empty()).unwrap_or(false);
let path = if parent_path.is_empty() { let path = if parent_path.is_empty() {
name.to_string() name.to_string()
} else { } else {
format!("{}/{}", parent_path, name) format!("{}/{}", parent_path, name)
}; };
items.push(FileInfo { let is_dir = children.is_some();
batch.push(FileInfo {
name: name.to_string(), name: name.to_string(),
path: path.clone(), path: path.clone(),
size, size,
is_dir, is_dir,
}); });
if let Some(children_array) = children { if batch.len() >= 200 {
if !children_array.is_empty() { let _ = app.emit("scan-batch", batch.clone());
for child in children_array { batch.clear();
extract_files(child, &path, items); }
}
if let Some(children) = children {
for child in children {
stream_extract(child, &path, batch, app);
} }
} }
if parent_path.is_empty() && !batch.is_empty() {
let _ = app.emit("scan-batch", batch.clone());
} }
} }
+16 -9
View File
@@ -7,6 +7,7 @@ import { v5 as uuidv5 } from 'uuid'
import prettyBytes from 'pretty-bytes' import prettyBytes from 'pretty-bytes'
import { FileInfo, scanDir } from './scanlib' import { FileInfo, scanDir } from './scanlib'
import { message, open } from '@tauri-apps/plugin-dialog' import { message, open } from '@tauri-apps/plugin-dialog'
import { listen } from '@tauri-apps/api/event'
interface Disk { interface Disk {
name: string name: string
@@ -31,19 +32,25 @@ export default function App () {
const handleFolderSelect = async (path: string) => { const handleFolderSelect = async (path: string) => {
setSelectedFolder(path) setSelectedFolder(path)
setScanning(true) setScanning(true)
console.log('scanning', path) setFiles([])
const scanResult = await scanDir(path)
console.log('done', scanResult) const unlisten = await listen<FileInfo[]>('scan-batch', event => {
if (scanResult.error) { const batch = event.payload
await message(`Error: ${scanResult.error}`, { setFiles(prev => [...prev, ...batch])
title: 'Tauri',
kind: 'error'
}) })
try {
await invoke('get_file_info_from_dirs', {
path,
minRatio: '0'
})
} catch (e: any) {
await message(`Error: ${e}`, { title: 'Error', kind: 'error' })
setSelectedFolder(null) setSelectedFolder(null)
} else {
setFiles(scanResult.items)
} }
setScanning(false) setScanning(false)
unlisten()
} }
return !selectedFolder ? ( return !selectedFolder ? (