flesh out first usable version

automove
Ondřej Hruška 5 years ago
parent bce484cb85
commit e6d00bacf5
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 57
      Cargo.lock
  2. 1
      Cargo.toml
  3. 359
      src/main.rs

57
Cargo.lock generated

@ -81,6 +81,18 @@ dependencies = [
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "env_logger"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "failure" name = "failure"
version = "0.1.5" version = "0.1.5"
@ -101,6 +113,14 @@ dependencies = [
"synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "humantime"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "0.4.4" version = "0.4.4"
@ -151,6 +171,11 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "quick-error"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "quote" name = "quote"
version = "0.6.12" version = "0.6.12"
@ -242,6 +267,7 @@ name = "srtune"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -279,6 +305,14 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "termcolor"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "termion" name = "termion"
version = "1.5.3" version = "1.5.3"
@ -350,11 +384,28 @@ name = "winapi-i686-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-util"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "winapi-x86_64-pc-windows-gnu" name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wincolor"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata] [metadata]
"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" "checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
@ -366,8 +417,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d" "checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d"
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" "checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319"
@ -376,6 +429,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
@ -390,6 +444,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)" = "8b4f551a91e2e3848aeef8751d0d4eec9489b6474c720fd4c55958d8d31a430c" "checksum syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)" = "8b4f551a91e2e3848aeef8751d0d4eec9489b6474c720fd4c55958d8d31a430c"
"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330" "checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
@ -401,4 +456,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"

@ -17,3 +17,4 @@ lazy_static = "1.3.0"
nom = "4.2.3" nom = "4.2.3"
regex = "1.1.7" regex = "1.1.7"
env_logger = "0.6.1"

@ -1,46 +1,172 @@
#[macro_use] #[macro_use]
extern crate failure;
#[macro_use]
extern crate log; extern crate log;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
use regex::Regex; use regex::Regex;
use std::path::Path; use std::fs::{File, OpenOptions};
use std::fs::File; use std::io::{BufReader, Write};
use std::io::{Read, Seek, SeekFrom};
use std::io; use std::io;
use std::str::FromStr; use std::str::FromStr;
use std::convert::TryFrom;
use std::io::BufRead;
use std::ops::{Add, Mul, MulAssign, AddAssign};
use std::fmt::{self, Display};
const LOG_LEVELS: [&str; 5] = ["error", "warn", "info", "debug", "trace"];
const SPAMMY_LIBS: [&str; 5] = ["tokio_reactor", "hyper", "reqwest", "mio", "want"];
fn main() { fn main() {
let argv = let argv =
clap::App::new("srtune") clap::App::new("srtune")
.version(env!("CARGO_PKG_VERSION")) .version(env!("CARGO_PKG_VERSION"))
.arg(clap::Arg::with_name("input") .arg(clap::Arg::with_name("input")
.value_name("INFILE") .value_name("INFILE")
.required(true) .help("Input file, -- for stdin"),
.index(1)
.help("Input file"),
) )
.arg(clap::Arg::with_name("output") .arg(clap::Arg::with_name("output")
.short("o")
.long("output")
.value_name("OUTFILE") .value_name("OUTFILE")
.required(true) .help("Output file, defaults to stdout"),
.index(2) )
.help("Output file"), .arg(clap::Arg::with_name("from")
.short("f")
.long("from")
.value_name("FROM")
.help("Index of the first affected entry, defaults to 0. With '--renumber', the original numbers are use."),
)
.arg(clap::Arg::with_name("move")
.short("m")
.long("move")
.value_name("SECS")
.help("Time shift, accepts positive or negative float"),
) )
.arg(clap::Arg::with_name("scale")
.short("s")
.long("scale")
.value_name("RATIO")
.help("Scale subtitle times and durations to compensate for bitrate differences.\nIf a start time was given, the scaling is relative to this point, otherwise to the first subtitle in the file."),
)
.arg(clap::Arg::with_name("durscale")
.short("d")
.long("durscale")
.value_name("RATIO")
.help("Scale durations, can be combined with '--scale'"),
)
.arg(clap::Arg::with_name("renumber")
.short("r")
.long("renumber")
.help("Change all numbers to be sequential starting with 1"),
)
.arg(clap::Arg::with_name("v").short("v").multiple(true).help(
"Sets the level of verbosity (adds to the default - info)",
))
.get_matches(); .get_matches();
let inf = argv.value_of("input").unwrap(); let mut log_level = "info".to_owned();
let outf = argv.value_of("output").unwrap();
if argv.is_present("v") {
// bump verbosity if -v's are present
let pos = LOG_LEVELS
.iter()
.position(|x| x == &log_level)
.unwrap();
log_level = match LOG_LEVELS
.iter()
.nth(pos + argv.occurrences_of("v") as usize)
{
Some(new_level) => new_level.to_string(),
None => "trace".to_owned(),
};
}
//println!("LEVEL={}", log_level);
// init logging
let env = env_logger::Env::default().default_filter_or(log_level);
let mut builder = env_logger::Builder::from_env(env);
let lib_level = log::LevelFilter::Info;
for lib in &SPAMMY_LIBS {
builder.filter_module(lib, lib_level);
}
builder.init();
let inf = argv.value_of("input");
let outf = argv.value_of("output");
let stdin = io::stdin();
let stdout = io::stdout();
let mut iter: Box<dyn Iterator<Item=Result<String, io::Error>>> = match inf {
None => {
Box::new(stdin.lock().lines())
}
Some(f) => {
let file = File::open(f).expect(&format!("Could not open file: {:?}", f));
Box::new(BufReader::new(file).lines())
}
};
let mut out : Box<dyn Write> = match outf {
None => {
Box::new(stdout.lock())
}
Some(f) => {
let file = OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(f)
.expect(&format!("Could not open file: {:?}", f));
Box::new(file)
}
};
let from_s = match argv.value_of("from") {
Some(s) => {
s.parse().expect("Bad --from format")
},
None => 0u32
};
let move_s = match argv.value_of("move") {
Some(s) => {
s.parse().expect("Bad --move format")
},
None => 0f32
};
let scale_s = match argv.value_of("scale") {
Some(s) => {
s.parse().expect("Bad --scale format")
},
None => 1f32
};
let durscale_s = match argv.value_of("durscale") {
Some(s) => {
s.parse().expect("Bad --durscale format")
},
None => 1f32
};
let source = read_file(inf); let renumber = argv.is_present("renumber");
let mut lines = source.lines(); info!("Opts: from #{}, move {}s, scale {}x, durscale {}x", from_s, move_s, scale_s, durscale_s);
let mut subs = vec![]; let mut scale_start = SubTime(0f32);
let mut first_found = false;
let mut renumber_i : u32 = 0;
while let Some(x) = lines.next() { let mut text = vec![];
while let Some(Ok(x)) = iter.next() {
let mut x = x.trim();
if x.starts_with('\u{feff}') {
debug!("Stripping BOM mark");
x = &x[3..];
}
let x = x.trim();
if x.is_empty() { if x.is_empty() {
continue; continue;
} }
@ -49,85 +175,168 @@ fn main() {
// 00:18:01,755 --> 00:18:03,774 // 00:18:01,755 --> 00:18:03,774
// (掃除機の音) // (掃除機の音)
// う~ん…。 // う~ん…。
if let Ok(num) = u32::from_str(x) { match u32::from_str(x) {
// println!("Entry {}", num); Ok(num) => {
let datesrow = lines.next().expect("expected date row"); // println!("Entry {}", num);
if datesrow.contains(" --> ") { let datesrow = iter.next().unwrap().unwrap();
let mut halves = datesrow.split(" --> "); if datesrow.contains(" --> ") {
let start = parse_time(halves.next().expect("expected two halves")).expect("invalid time"); let mut halves = datesrow.split(" --> ");
let end = parse_time(halves.next().expect("expected two halves")).expect("invalid time"); let (first, second) = (halves.next().unwrap(), halves.next().unwrap());
let start = SubTime::try_from(first).unwrap();
//println!("{} -> {} secs", start, end); let end = SubTime::try_from(second).unwrap();
let mut text = vec![]; text.clear();
while let Some(x) = lines.next() { while let Some(Ok(x)) = iter.next() {
if x.is_empty() { if x.is_empty() {
break; break; // space between the entries
}
text.push(x);
} }
text.push(x);
}
let text = text.join("\n"); let mut one = Subtitle {
num,
start,
dur: SubDuration(end.0 - start.0),
text: text.join("\n"),
};
//println!("Lines: {}", text); if num >= from_s {
if !first_found {
debug!("Scaling anchored at {} (#{}), start edits", start, num);
scale_start = start;
first_found = true;
}
subs.push(Subtitle { if scale_s != 1f32 {
num, start, end, text one.start = one.start.scale(scale_start, scale_s);
}) }
one.dur *= durscale_s;
one.start += move_s;
}
if one.start.0 < 0f32 {
warn!("Discarding negative time entry #{} @ {:.3}s", one.num, one.start.0);
continue;
}
// advance numbering only for the really emitted entries
if renumber {
renumber_i += 1;
one.num = renumber_i;
}
out.write(one.to_string().as_bytes()).expect("failed to write");
}
}
Err(e) => {
error!("couldnt parse >{}<: {}", x, e);
for b in x.as_bytes() {
error!("{:#02x} - {}", b, b);
}
error!("\n");
} }
} }
} }
println!("Parsed {} entries.", subs.len()); out.flush().unwrap();
}
#[derive(Copy, Clone, Debug)]
struct SubTime(f32);
#[derive(Copy, Clone, Debug)]
struct SubDuration(f32);
//println!("{:?}", parsed); impl Add<SubDuration> for SubTime {
type Output = SubTime;
fn add(self, rhs: SubDuration) -> Self::Output {
SubTime(self.0 + rhs.0)
}
} }
struct Subtitle { impl Mul<f32> for SubDuration {
num : u32, type Output = SubDuration;
start: f32,
end: f32, fn mul(self, rhs: f32) -> Self::Output {
text: String SubDuration(self.0 * rhs)
}
} }
lazy_static! { impl MulAssign<f32> for SubDuration {
static ref DATE_RE: Regex = Regex::new(r"(\d+):(\d+):(\d+),(\d+)").unwrap(); fn mul_assign(&mut self, rhs: f32) {
self.0 *= rhs;
}
} }
fn parse_time(time : &str) -> Result<f32, ()> { impl AddAssign<f32> for SubDuration {
// 00:18:01,755 fn add_assign(&mut self, rhs: f32) {
match DATE_RE.captures(time) { self.0 += rhs;
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. impl SubTime {
fn read_file<P: AsRef<Path>>(path: P) -> String { /// Scale by a factor with a custom start time
let path = path.as_ref(); pub fn scale(&self, start : SubTime, factor : f32) -> SubTime {
let mut file = File::open(path).expect(&format!("Could not open file: {:?}", path)); SubTime(start.0 + (self.0 - start.0) * factor)
}
}
let mut buf = String::with_capacity(file_len(&mut file).expect("Er testing file len")); impl AddAssign<f32> for SubTime {
file.read_to_string(&mut buf) fn add_assign(&mut self, rhs: f32) {
.expect(&format!("Error reading file {:?}", path)); self.0 += rhs;
buf }
} }
fn file_len(file : &mut File) -> io::Result<usize> { impl Display for SubTime {
let old_pos = file.seek(SeekFrom::Current(0))?; fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let len = file.seek(SeekFrom::End(0))?; // TODO optimize this
let mut secs = self.0;
let hours = (secs / 3600f32).floor();
secs -= hours * 3600f32;
let minutes = (secs / 60f32).floor();
secs -= minutes * 60f32;
let msecs = ((secs % 1f32)*1000f32).round();
write!(f, "{:02}:{:02}:{:02},{:03}", hours, minutes, secs.floor(), msecs)
}
}
// Avoid seeking a third time when we were already at the end of the #[derive(Clone, Debug)]
// stream. The branch is usually way cheaper than a seek operation. struct Subtitle {
if old_pos != len { num: u32,
file.seek(SeekFrom::Start(old_pos))?; start: SubTime,
dur: SubDuration,
text: String,
}
impl Display for Subtitle {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}\n{} --> {}\n{}\n\n",
self.num,
self.start, self.start + self.dur,
self.text
)
} }
}
Ok(len as usize) lazy_static! {
static ref DATE_RE: Regex = Regex::new(r"(\d+):(\d+):(\d+),(\d+)").unwrap();
}
impl TryFrom<&str> for SubTime {
type Error = failure::Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match DATE_RE.captures(value) {
Some(caps) => {
Ok(SubTime(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(failure::err_msg("Error parsing time."))
}
}
} }

Loading…
Cancel
Save