Files
lazyff/src/main.rs
T
otto 4daca8247c Decouple option codes, fix encode bugs, add test suite
Maintainability:
- Choice options now carry a stable `code` separate from the display
  `label`. The command builder and recipe storage key off codes, so
  relabeling a menu entry no longer silently changes the encode or
  breaks a saved recipe. Format/Audio dispatch is now a clean code
  match instead of `starts_with` on display strings. Old recipes that
  stored labels still load via a label fallback.

Correctness:
- Fade start times now scale by the speed factor already applied in the
  filter chain, so Speed + Fade produces a fade in the right place
  regardless of op order (video and audio).
- Two-pass pass 1 uses the platform null device (NUL on Windows).
- The stderr drain thread is joined before Finished is sent, so the
  failure tail reported to the user is never truncated.

Features / cleanup:
- Accept multiple file arguments on the CLI to open batch mode directly.
- try_recv() instead of recv_timeout(ZERO); drop unused import.

Testing:
- 23 unit tests covering build() arg generation, speed/fade ordering,
  recipe round-trip + old-label fallback, and the pure helpers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 15:47:16 +01:00

74 lines
2.2 KiB
Rust

mod app;
mod ffmpeg;
mod ops;
mod recipes;
mod ui;
use std::process::Command;
use std::time::Duration;
use anyhow::{bail, Result};
use ratatui::crossterm::event::{self, Event, KeyEventKind};
use ratatui::DefaultTerminal;
use app::App;
fn main() -> Result<()> {
let mut initial: Vec<std::path::PathBuf> = Vec::new();
for arg in std::env::args().skip(1) {
match arg.as_str() {
"--version" | "-V" => {
println!("lazyff {}", env!("CARGO_PKG_VERSION"));
return Ok(());
}
"--help" | "-h" => {
println!("lazyff {} — a friendly TUI for FFmpeg", env!("CARGO_PKG_VERSION"));
println!("Usage: lazyff [FILE...]");
println!(" no argument open a file browser in the current directory");
println!(" FILE open this video/audio file straight in the editor");
println!(" FILE FILE... open several files together in batch mode");
return Ok(());
}
_ => {
let path = std::path::PathBuf::from(&arg);
if !path.is_file() {
bail!("{arg}: no such file");
}
initial.push(path);
}
}
}
for bin in ["ffmpeg", "ffprobe"] {
if Command::new(bin).arg("-version").output().is_err() {
bail!("{bin} was not found on your PATH. Please install FFmpeg first.");
}
}
// Probe the initial file before entering the alternate screen so errors
// print normally.
let app = App::new(initial)?;
let mut terminal = ratatui::init();
let result = run(&mut terminal, app);
ratatui::restore();
result
}
fn run(terminal: &mut DefaultTerminal, mut app: App) -> Result<()> {
loop {
app.poll_run_messages();
terminal.draw(|f| ui::draw(f, &mut app))?;
if event::poll(Duration::from_millis(100))? {
if let Event::Key(key) = event::read()? {
if key.kind == KeyEventKind::Press {
app.on_key(key);
}
}
}
if app.should_quit {
return Ok(());
}
}
}