#[macro_use] extern crate failure; #[macro_use] extern crate log; #[macro_use] extern crate lazy_static; use regex::Regex; use std::path::Path; use std::fs::File; use std::io::{Read, Seek, SeekFrom}; use std::io; use std::str::FromStr; fn main() { let argv = clap::App::new("srtune") .version(env!("CARGO_PKG_VERSION")) .arg(clap::Arg::with_name("input") .value_name("INFILE") .required(true) .index(1) .help("Input file"), ) .arg(clap::Arg::with_name("output") .value_name("OUTFILE") .required(true) .index(2) .help("Output file"), ) .get_matches(); let inf = argv.value_of("input").unwrap(); let outf = argv.value_of("output").unwrap(); let source = read_file(inf); let mut lines = source.lines(); let mut subs = vec![]; while let Some(x) = lines.next() { if x.is_empty() { continue; } // 236 // 00:18:01,755 --> 00:18:03,774 // (掃除機の音) // う~ん…。 if let Ok(num) = u32::from_str(x) { // println!("Entry {}", num); let datesrow = lines.next().expect("expected date row"); if datesrow.contains(" --> ") { let mut halves = datesrow.split(" --> "); let start = parse_time(halves.next().expect("expected two halves")).expect("invalid time"); let end = parse_time(halves.next().expect("expected two halves")).expect("invalid time"); //println!("{} -> {} secs", start, end); let mut text = vec![]; while let Some(x) = lines.next() { if x.is_empty() { break; } text.push(x); } let text = text.join("\n"); //println!("Lines: {}", text); subs.push(Subtitle { num, start, end, text }) } } } println!("Parsed {} entries.", subs.len()); //println!("{:?}", parsed); } struct Subtitle { num : u32, start: f32, end: f32, text: String } lazy_static! { static ref DATE_RE: Regex = Regex::new(r"(\d+):(\d+):(\d+),(\d+)").unwrap(); } fn parse_time(time : &str) -> Result { // 00:18:01,755 match DATE_RE.captures(time) { Some(caps) => { Ok(f32::from_str(caps.get(1).unwrap().as_str()).unwrap()*3600f32 + f32::from_str(caps.get(2).unwrap().as_str()).unwrap()*60f32 + f32::from_str(caps.get(3).unwrap().as_str()).unwrap()+ f32::from_str(caps.get(4).unwrap().as_str()).unwrap() * 0.001f32) }, None => Err(()) } } /// Read a file to string; panics on error. fn read_file>(path: P) -> String { let path = path.as_ref(); let mut file = File::open(path).expect(&format!("Could not open file: {:?}", path)); let mut buf = String::with_capacity(file_len(&mut file).expect("Er testing file len")); file.read_to_string(&mut buf) .expect(&format!("Error reading file {:?}", path)); buf } fn file_len(file : &mut File) -> io::Result { let old_pos = file.seek(SeekFrom::Current(0))?; let len = file.seek(SeekFrom::End(0))?; // Avoid seeking a third time when we were already at the end of the // stream. The branch is usually way cheaper than a seek operation. if old_pos != len { file.seek(SeekFrom::Start(old_pos))?; } Ok(len as usize) }