From a6cb9addb076b35b121d530107eaa96ce44cb9cb Mon Sep 17 00:00:00 2001 From: 44r0n7 <44r0n7+gitea@pm.me> Date: Wed, 31 Dec 2025 22:50:01 -0500 Subject: [PATCH] Improve scan escalation, watch stability, and plan output --- README.md | 6 ++++ vid-repair-core/src/fix/planner.rs | 44 ++++++++++++++++++++++++++++-- vid-repair-core/src/report/text.rs | 12 +++++++- vid-repair-core/src/scan/mod.rs | 16 +++++++++-- vid-repair-core/src/watch/mod.rs | 21 +++++++++++++- 5 files changed, 93 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 3db4682..993aa1c 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,12 @@ vid-repair scan /path/to/videos # Scan and watch for new files vid-repair scan --watch /path/to/videos +# Scan depth (quick|standard|deep) +vid-repair scan --scan-depth quick /path/to/videos + +# Disable recursive scanning +vid-repair scan --no-recursive /path/to/videos + # Fix (safe policy, in-place) vid-repair fix /path/to/videos diff --git a/vid-repair-core/src/fix/planner.rs b/vid-repair-core/src/fix/planner.rs index 682a92a..57f43c3 100644 --- a/vid-repair-core/src/fix/planner.rs +++ b/vid-repair-core/src/fix/planner.rs @@ -41,7 +41,7 @@ pub fn plan_fix(issues: &[Issue], policy: FixPolicy) -> FixPlan { } else { actions.push(FixAction { kind, - command: Vec::new(), + command: command_template(kind), destructive: true, }); } @@ -56,12 +56,52 @@ pub fn plan_fix(issues: &[Issue], policy: FixPolicy) -> FixPlan { } pub fn plan_outcome(plan: FixPlan) -> FixOutcome { + let message = if let Some(kind) = plan.recommended { + format!("Fix plan generated: {:?}", kind) + } else { + "Fix plan generated".to_string() + }; + FixOutcome { plan, applied: false, success: false, - message: "Fix plan generated".to_string(), + message, output_path: None, re_scan_required: false, } } + +fn command_template(kind: FixKind) -> Vec { + let mut cmd = vec![ + "ffmpeg".to_string(), + "-v".to_string(), + "error".to_string(), + "-i".to_string(), + "".to_string(), + ]; + + match kind { + FixKind::Remux => { + cmd.push("-c".to_string()); + cmd.push("copy".to_string()); + } + FixKind::Faststart => { + cmd.push("-c".to_string()); + cmd.push("copy".to_string()); + cmd.push("-movflags".to_string()); + cmd.push("+faststart".to_string()); + } + FixKind::Reencode => { + cmd.push("-c:v".to_string()); + cmd.push("libx264".to_string()); + cmd.push("-c:a".to_string()); + cmd.push("aac".to_string()); + cmd.push("-movflags".to_string()); + cmd.push("+faststart".to_string()); + } + } + + cmd.push("".to_string()); + cmd +} diff --git a/vid-repair-core/src/report/text.rs b/vid-repair-core/src/report/text.rs index fc3968a..d86e455 100644 --- a/vid-repair-core/src/report/text.rs +++ b/vid-repair-core/src/report/text.rs @@ -22,7 +22,17 @@ pub fn render_fix_line(scan: &ScanOutcome, fix: &FixOutcome) -> String { } else if fix.applied { format!("[FAILED] {} - {}", scan.path.display(), fix.message) } else { - format!("[SKIPPED] {} - {}", scan.path.display(), fix.message) + let action = fix + .plan + .recommended + .map(|kind| format!("{:?}", kind)) + .unwrap_or_else(|| "none".to_string()); + format!( + "[SKIPPED] {} - {} (plan: {})", + scan.path.display(), + fix.message, + action + ) } } diff --git a/vid-repair-core/src/scan/mod.rs b/vid-repair-core/src/scan/mod.rs index 0bc2ac5..ee9dc10 100644 --- a/vid-repair-core/src/scan/mod.rs +++ b/vid-repair-core/src/scan/mod.rs @@ -18,21 +18,33 @@ pub fn scan_file(path: &Path, config: &Config, ruleset: &RuleSet) -> Result>(); + if issues.is_empty() && !decode.lines.is_empty() { + issues.push(Issue { + code: "UNKNOWN_DECODE_ERROR".to_string(), + severity: crate::rules::Severity::High, + fix_tier: crate::rules::FixTier::Reencode, + message: "Decoder reported errors not matched by ruleset".to_string(), + evidence: decode.lines.iter().take(3).cloned().collect(), + action: None, + }); + } + Ok(ScanOutcome { path: path.to_path_buf(), probe, diff --git a/vid-repair-core/src/watch/mod.rs b/vid-repair-core/src/watch/mod.rs index 4b4aba7..3285eef 100644 --- a/vid-repair-core/src/watch/mod.rs +++ b/vid-repair-core/src/watch/mod.rs @@ -86,8 +86,27 @@ where .collect(); for path in ready { + let before = std::fs::metadata(&path).ok(); entries.remove(&path); - handler(path); + handler(path.clone()); + if let Some(meta) = before { + let size = meta.len(); + let mtime = meta.modified().unwrap_or_else(|_| std::time::SystemTime::UNIX_EPOCH); + if let Ok(after) = std::fs::metadata(&path) { + if after.len() != size || after.modified().unwrap_or_else(|_| std::time::SystemTime::UNIX_EPOCH) != mtime { + entries.insert( + path, + WatchEntry { + last_event: Instant::now(), + size: after.len(), + mtime: after + .modified() + .unwrap_or_else(|_| std::time::SystemTime::UNIX_EPOCH), + }, + ); + } + } + } } }