You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
3.7 KiB
134 lines
3.7 KiB
6 years ago
|
#[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<f32, ()> {
|
||
|
// 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<P: AsRef<Path>>(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<usize> {
|
||
|
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)
|
||
|
}
|
||
|
|