Fix crashes when converting subtitles (#408)

This commit is contained in:
bytedream 2024-05-14 16:11:55 +02:00
parent 53a710a373
commit 48bb7a5ef6
3 changed files with 30 additions and 18 deletions

View file

@ -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"

View file

@ -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<TempPath> {
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)
}