mirror of
https://git.pumpin.online/funkpower/catena.git
synced 2026-10-23 11:17:13 +00:00
booksniff, and one place for the parts every tool shares
This commit is contained in:
+10
-46
@@ -1,11 +1,9 @@
|
||||
//! Any subtitle format in, one normalised cue stream out.
|
||||
|
||||
use std::io::{BufWriter, Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
use std::process::ExitCode;
|
||||
|
||||
use clap::Parser;
|
||||
use corpus_core::{exit, ndjson};
|
||||
|
||||
/// Read a subtitle file — SubRip, WebVTT or SubStation Alpha — and write one
|
||||
/// cue per line as JSON.
|
||||
@@ -35,13 +33,16 @@ struct Args {
|
||||
}
|
||||
|
||||
fn main() -> ExitCode {
|
||||
let args = Args::parse();
|
||||
let args: Args = match catena_cli::parse() {
|
||||
Ok(args) => args,
|
||||
Err(code) => return code,
|
||||
};
|
||||
|
||||
let content = match read(args.path.as_deref()) {
|
||||
let content = match catena_cli::read_lossy(args.path.as_deref()) {
|
||||
Ok(content) => content,
|
||||
Err(e) => {
|
||||
eprintln!("cuenorm: {e}");
|
||||
return ExitCode::from(exit::IO);
|
||||
Err((code, why)) => {
|
||||
eprintln!("cuenorm: {why}");
|
||||
return ExitCode::from(code);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -52,42 +53,5 @@ fn main() -> ExitCode {
|
||||
cuekit::merge_repeats(&cues)
|
||||
};
|
||||
|
||||
let mut out = BufWriter::new(std::io::stdout().lock());
|
||||
for cue in &cues {
|
||||
if let Err(e) = ndjson::write_line(&mut out, cue) {
|
||||
// A consumer that stopped reading is not a failure.
|
||||
if e.is_broken_pipe() {
|
||||
return ExitCode::from(exit::OK);
|
||||
}
|
||||
eprintln!("cuenorm: {e}");
|
||||
return ExitCode::from(exit::IO);
|
||||
}
|
||||
}
|
||||
match out.flush() {
|
||||
Ok(()) => ExitCode::from(exit::OK),
|
||||
Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe => ExitCode::from(exit::OK),
|
||||
Err(e) => {
|
||||
eprintln!("cuenorm: {e}");
|
||||
ExitCode::from(exit::IO)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read the file as text, tolerating the encodings a subtitle file arrives in.
|
||||
///
|
||||
/// Not UTF-8 is common: a subtitle file downloaded from anywhere is as likely
|
||||
/// to be Latin-1, and refusing it would make the tool useless for exactly the
|
||||
/// archives that need it. Undecodable bytes become the replacement character
|
||||
/// rather than an error, because a cue with one wrong character still has its
|
||||
/// timing and most of its words.
|
||||
fn read(path: Option<&Path>) -> std::io::Result<String> {
|
||||
let bytes = match path {
|
||||
Some(path) => std::fs::read(path)?,
|
||||
None => {
|
||||
let mut bytes = Vec::new();
|
||||
std::io::stdin().read_to_end(&mut bytes)?;
|
||||
bytes
|
||||
}
|
||||
};
|
||||
Ok(String::from_utf8_lossy(&bytes).into_owned())
|
||||
catena_cli::stream("cuenorm", &cues)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user