mirror of
https://github.com/crunchy-labs/crunchy-cli.git
synced 2026-01-21 04:02:00 -06:00
Fix crashes when converting subtitles (#408)
This commit is contained in:
parent
53a710a373
commit
48bb7a5ef6
3 changed files with 30 additions and 18 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
|
@ -386,6 +386,7 @@ dependencies = [
|
||||||
"shlex",
|
"shlex",
|
||||||
"sys-locale",
|
"sys-locale",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
"time",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
|
|
@ -1511,12 +1512,13 @@ checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rsubs-lib"
|
name = "rsubs-lib"
|
||||||
version = "0.2.1"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9dcca2a9560fca05de8f95bc3767e46673d4b4c1f2c7a11092e10efd95bbdf62"
|
checksum = "f43e1a7f184bc76407dbaa67bd2aeea8a15430d7e1e498070963336d03ebedee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
|
"time",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ log = { version = "0.4", features = ["std"] }
|
||||||
num_cpus = "1.16"
|
num_cpus = "1.16"
|
||||||
regex = "1.10"
|
regex = "1.10"
|
||||||
reqwest = { version = "0.12", features = ["socks", "stream"] }
|
reqwest = { version = "0.12", features = ["socks", "stream"] }
|
||||||
rsubs-lib = ">=0.2.1"
|
rsubs-lib = "0.3"
|
||||||
rusty-chromaprint = "0.2"
|
rusty-chromaprint = "0.2"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
@ -38,6 +38,7 @@ serde_plain = "1.0"
|
||||||
shlex = "1.3"
|
shlex = "1.3"
|
||||||
sys-locale = "0.3"
|
sys-locale = "0.3"
|
||||||
tempfile = "3.10"
|
tempfile = "3.10"
|
||||||
|
time = "0.3"
|
||||||
tokio = { version = "1.37", features = ["io-util", "macros", "net", "rt-multi-thread", "time"] }
|
tokio = { version = "1.37", features = ["io-util", "macros", "net", "rt-multi-thread", "time"] }
|
||||||
tokio-util = "0.7"
|
tokio-util = "0.7"
|
||||||
tower-service = "0.3"
|
tower-service = "0.3"
|
||||||
|
|
|
||||||
|
|
@ -13,17 +13,19 @@ use indicatif::{ProgressBar, ProgressDrawTarget, ProgressFinish, ProgressStyle};
|
||||||
use log::{debug, warn, LevelFilter};
|
use log::{debug, warn, LevelFilter};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use rsubs_lib::{ssa, vtt};
|
use rsubs_lib::{SSA, VTT};
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use std::ops::Add;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
use tempfile::TempPath;
|
use tempfile::TempPath;
|
||||||
|
use time::Time;
|
||||||
use tokio::io::{AsyncBufReadExt, AsyncReadExt, BufReader};
|
use tokio::io::{AsyncBufReadExt, AsyncReadExt, BufReader};
|
||||||
use tokio::select;
|
use tokio::select;
|
||||||
use tokio::sync::mpsc::unbounded_channel;
|
use tokio::sync::mpsc::unbounded_channel;
|
||||||
|
|
@ -929,36 +931,43 @@ impl Downloader {
|
||||||
) -> Result<TempPath> {
|
) -> Result<TempPath> {
|
||||||
let buf = subtitle.data().await?;
|
let buf = subtitle.data().await?;
|
||||||
let mut ass = match subtitle.format.as_str() {
|
let mut ass = match subtitle.format.as_str() {
|
||||||
"ass" => ssa::parse(String::from_utf8_lossy(&buf).to_string()),
|
"ass" => SSA::parse(String::from_utf8_lossy(&buf))?,
|
||||||
"vtt" => vtt::parse(String::from_utf8_lossy(&buf).to_string()).to_ass(),
|
"vtt" => VTT::parse(String::from_utf8_lossy(&buf))?.to_ssa(),
|
||||||
_ => bail!("unknown subtitle format: {}", subtitle.format),
|
_ => bail!("unknown subtitle format: {}", subtitle.format),
|
||||||
};
|
};
|
||||||
// subtitles aren't always correct sorted and video players may have issues with that. to
|
// subtitles aren't always correct sorted and video players may have issues with that. to
|
||||||
// prevent issues, the subtitles are sorted
|
// prevent issues, the subtitles are sorted
|
||||||
ass.events
|
// (https://github.com/crunchy-labs/crunchy-cli/issues/208)
|
||||||
.sort_by(|a, b| a.line_start.total_ms().cmp(&b.line_start.total_ms()));
|
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
|
// 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
|
// 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() {
|
for i in (0..ass.events.len()).rev() {
|
||||||
if ass.events[i].line_end.total_ms() > max_length.num_milliseconds() as u32 {
|
let max_len = Time::from_hms(0, 0, 0)
|
||||||
if ass.events[i].line_start.total_ms() > max_length.num_milliseconds() as u32 {
|
.unwrap()
|
||||||
ass.events[i]
|
.add(Duration::from_millis(max_length.num_milliseconds() as u64));
|
||||||
.line_start
|
|
||||||
.set_ms(max_length.num_milliseconds() as u32);
|
if ass.events[i].start > max_len {
|
||||||
|
if ass.events[i].end > max_len {
|
||||||
|
ass.events[i].start = max_len
|
||||||
}
|
}
|
||||||
ass.events[i]
|
ass.events[i].end = max_len
|
||||||
.line_end
|
|
||||||
.set_ms(max_length.num_milliseconds() as u32);
|
|
||||||
} else {
|
} else {
|
||||||
break;
|
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 tempfile = tempfile(".ass")?;
|
||||||
let path = tempfile.into_temp_path();
|
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)
|
Ok(path)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue