From 48bb7a5ef669d3d89ccecfbf02929adeea99a6bd Mon Sep 17 00:00:00 2001 From: bytedream Date: Tue, 14 May 2024 16:11:55 +0200 Subject: [PATCH] Fix crashes when converting subtitles (#408) --- Cargo.lock | 6 ++-- crunchy-cli-core/Cargo.toml | 3 +- crunchy-cli-core/src/utils/download.rs | 39 ++++++++++++++++---------- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 44a47cd..cd1f282 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -386,6 +386,7 @@ dependencies = [ "shlex", "sys-locale", "tempfile", + "time", "tokio", "tokio-util", "tower-service", @@ -1511,12 +1512,13 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rsubs-lib" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dcca2a9560fca05de8f95bc3767e46673d4b4c1f2c7a11092e10efd95bbdf62" +checksum = "f43e1a7f184bc76407dbaa67bd2aeea8a15430d7e1e498070963336d03ebedee" dependencies = [ "regex", "serde", + "time", ] [[package]] diff --git a/crunchy-cli-core/Cargo.toml b/crunchy-cli-core/Cargo.toml index 8e1ba3a..49f7a5e 100644 --- a/crunchy-cli-core/Cargo.toml +++ b/crunchy-cli-core/Cargo.toml @@ -30,7 +30,7 @@ log = { version = "0.4", features = ["std"] } num_cpus = "1.16" regex = "1.10" reqwest = { version = "0.12", features = ["socks", "stream"] } -rsubs-lib = ">=0.2.1" +rsubs-lib = "0.3" rusty-chromaprint = "0.2" serde = "1.0" serde_json = "1.0" @@ -38,6 +38,7 @@ serde_plain = "1.0" shlex = "1.3" sys-locale = "0.3" tempfile = "3.10" +time = "0.3" tokio = { version = "1.37", features = ["io-util", "macros", "net", "rt-multi-thread", "time"] } tokio-util = "0.7" tower-service = "0.3" diff --git a/crunchy-cli-core/src/utils/download.rs b/crunchy-cli-core/src/utils/download.rs index 8a8ad57..43d165b 100644 --- a/crunchy-cli-core/src/utils/download.rs +++ b/crunchy-cli-core/src/utils/download.rs @@ -13,17 +13,19 @@ use indicatif::{ProgressBar, ProgressDrawTarget, ProgressFinish, ProgressStyle}; use log::{debug, warn, LevelFilter}; use regex::Regex; use reqwest::Client; -use rsubs_lib::{ssa, vtt}; +use rsubs_lib::{SSA, VTT}; use std::borrow::Borrow; use std::cmp::Ordering; use std::collections::{BTreeMap, HashMap}; use std::io::Write; +use std::ops::Add; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::sync::Arc; use std::time::Duration; use std::{env, fs}; use tempfile::TempPath; +use time::Time; use tokio::io::{AsyncBufReadExt, AsyncReadExt, BufReader}; use tokio::select; use tokio::sync::mpsc::unbounded_channel; @@ -929,36 +931,43 @@ impl Downloader { ) -> Result { let buf = subtitle.data().await?; let mut ass = match subtitle.format.as_str() { - "ass" => ssa::parse(String::from_utf8_lossy(&buf).to_string()), - "vtt" => vtt::parse(String::from_utf8_lossy(&buf).to_string()).to_ass(), + "ass" => SSA::parse(String::from_utf8_lossy(&buf))?, + "vtt" => VTT::parse(String::from_utf8_lossy(&buf))?.to_ssa(), _ => bail!("unknown subtitle format: {}", subtitle.format), }; // subtitles aren't always correct sorted and video players may have issues with that. to // prevent issues, the subtitles are sorted - ass.events - .sort_by(|a, b| a.line_start.total_ms().cmp(&b.line_start.total_ms())); + // (https://github.com/crunchy-labs/crunchy-cli/issues/208) + ass.events.sort_by(|a, b| a.start.cmp(&b.start)); // it might be the case that the start and/or end time are greater than the actual video // length. this might also result in issues with video players, thus the times are stripped - // to be maxim + // to be at most as long as `max_length` + // (https://github.com/crunchy-labs/crunchy-cli/issues/32) for i in (0..ass.events.len()).rev() { - if ass.events[i].line_end.total_ms() > max_length.num_milliseconds() as u32 { - if ass.events[i].line_start.total_ms() > max_length.num_milliseconds() as u32 { - ass.events[i] - .line_start - .set_ms(max_length.num_milliseconds() as u32); + let max_len = Time::from_hms(0, 0, 0) + .unwrap() + .add(Duration::from_millis(max_length.num_milliseconds() as u64)); + + if ass.events[i].start > max_len { + if ass.events[i].end > max_len { + ass.events[i].start = max_len } - ass.events[i] - .line_end - .set_ms(max_length.num_milliseconds() as u32); + ass.events[i].end = max_len } else { break; } } + // without this additional info, subtitle look very messy in some video player + // (https://github.com/crunchy-labs/crunchy-cli/issues/66) + ass.info + .additional_fields + .insert("ScaledBorderAndShadows".to_string(), "yes".to_string()); + let tempfile = tempfile(".ass")?; let path = tempfile.into_temp_path(); - ass.to_file(path.to_string_lossy().to_string().as_str())?; + fs::write(&path, ass.to_string())?; Ok(path) }