Skip to content

Commit

Permalink
Write srt to vtt conversion logic in rust
Browse files Browse the repository at this point in the history
  • Loading branch information
dormant-user committed Feb 17, 2024
1 parent 758688f commit 87cbaf3
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 53 deletions.
40 changes: 20 additions & 20 deletions src/routes/video.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,11 @@ fn url_encode(path: &String) -> String {
/// Returns a `Subtitles` struct containing paths and filenames for both SRT and VTT subtitle files.
fn subtitles(true_path: PathBuf, relative_path: &String) -> Subtitles {
// Set srt and vtt extensions to true path to check if they exist
let mut srt = true_path.clone();
let mut vtt = true_path.clone();
srt.set_extension("srt");
vtt.set_extension("vtt");
let srt = true_path.with_extension("srt");
let vtt = true_path.with_extension("vtt");

// Set vtt extension to the relative path, so it could be used as a parameter in HTML
let mut vtt_filepath = PathBuf::new().join(relative_path);
vtt_filepath.set_extension("vtt");
let vtt_filepath = PathBuf::new().join(relative_path).with_extension("vtt");
let vtt_file = vtt_filepath.to_string_lossy().to_string();

Subtitles { srt, vtt, vtt_file }
Expand Down Expand Up @@ -170,20 +167,23 @@ pub async fn stream(config: web::Data<Arc<squire::settings::Config>>,
track => sfx_file
)).unwrap();
} else if subtitle.srt.exists() {
log::info!("Converting '{}' to '{}' for subtitles",
subtitle.srt.file_name().unwrap().to_string_lossy(),
subtitle.vtt.file_name().unwrap().to_string_lossy());
if squire::fileio::srt_to_vtt(&subtitle.srt.to_string_lossy().to_string()) {
log::debug!("Successfully converted srt to vtt file");
let sfx_file = format!("/track?file={}", url_encode(&subtitle.vtt_file));
response_body = landing.render(context!(
video_title => &filepath, path => render_path,
previous => &iter.previous,
next => &iter.next,
previous_title => &iter.previous,
next_title => &iter.next,
track => sfx_file
)).unwrap();
log::info!("Converting '{:?}' to '{:?}' for subtitles",
subtitle.srt.file_name(),
subtitle.vtt.file_name());
match squire::subtitles::srt_to_vtt(&subtitle.srt) {
Ok(_) => {
log::debug!("Successfully converted srt to vtt file");
let sfx_file = format!("/track?file={}", url_encode(&subtitle.vtt_file));
response_body = landing.render(context!(
video_title => &filepath, path => render_path,
previous => &iter.previous,
next => &iter.next,
previous_title => &iter.previous,
next_title => &iter.next,
track => sfx_file
)).unwrap();
}
Err(err) => log::error!("Failed to convert srt to vtt: {}", err),
}
}
return HttpResponse::build(StatusCode::OK)
Expand Down
33 changes: 0 additions & 33 deletions src/squire/fileio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,36 +129,3 @@ pub fn get_iter(args: (&String, (&String, &String))) -> Iter {
}
}
}

/// Converts an SRT file to VTT format.
///
/// # Arguments
///
/// * `input_file` - The path to the input SRT file.
///
/// # Returns
///
/// A boolean indicating whether the conversion was successful.
pub fn srt_to_vtt(input_file: &String) -> bool {
let py_app = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/python/fileio.py"));
let from_python = Python::with_gil(|py| -> PyResult<Py<PyAny>> {
let app: Py<PyAny> = PyModule::from_code(py, py_app, "", "")?
.getattr("srt_to_vtt")?
.into();
app.call1(py, (input_file, ))
});
match from_python {
Ok(result) => {
let result_string = result.to_string();
match result_string.as_str() {
"true" => true,
"false" => false,
_ => false,
}
}
Err(err) => {
log::error!("{}", err);
false
}
}
}
1 change: 1 addition & 0 deletions src/squire/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ pub mod fileio;
pub mod logger;
pub mod ascii_art;
pub mod middleware;
pub mod subtitles;
59 changes: 59 additions & 0 deletions src/squire/subtitles.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use std::ffi::OsStr;
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
use std::result::Result;

/// Converts an SRT file to VTT format.
///
/// # Arguments
///
/// * `filename` - The path to the input SRT file.
///
/// # Returns
///
/// A boolean indicating whether the conversion was successful.
pub fn srt_to_vtt(filepath: &PathBuf) -> Result<bool, String> {
if filepath.extension().and_then(OsStr::to_str) != Some("srt") {
return Ok(false);
}

let output_file = filepath.with_extension("vtt");
let mut rf = match File::open(filepath) {
Ok(file) => file,
Err(err) => return Err(format!("Error opening file: {}", err)),
};

let mut srt_content = String::new();
if let Err(err) = rf.read_to_string(&mut srt_content) {
return Err(format!("Error reading file: {}", err));
}

let srt_content = srt_content.replace(',', ".");
let srt_content = srt_content.replace(" --> ", "-->");

let mut vtt_content = String::from("WEBVTT\n\n");
let subtitle_blocks: Vec<&str> = srt_content.trim().split("\n\n").collect();

for block in subtitle_blocks {
let lines: Vec<&str> = block.split('\n').collect();
let timecode = lines[1];
let text = lines[2..].join("\n");
vtt_content.push_str(&format!("{}\n{}\n\n", timecode, text));
}

let mut wf = match File::create(output_file) {
Ok(file) => file,
Err(err) => return Err(format!("Error creating output file: {}", err)),
};

if let Err(err) = wf.write_all(vtt_content.as_bytes()) {
return Err(format!("Error writing to output file: {}", err));
}

if let Err(err) = wf.flush() {
return Err(format!("Error flushing output file: {}", err));
}

Ok(true)
}

0 comments on commit 87cbaf3

Please sign in to comment.