feat: origin filename support.
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -54,7 +54,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bilibili-merge"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bilibili-merge"
|
||||
version = "0.2.0"
|
||||
version = "0.3.0"
|
||||
authors = ["licsber <admin@licsber.site>"]
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -20,6 +20,11 @@ impl ShellScript {
|
||||
self.lines.push(format!("{}=\"{}\"", name, escaped));
|
||||
}
|
||||
|
||||
pub fn add_variable_str(&mut self, name: &str, value: &str) {
|
||||
let escaped = value.replace('"', r#"\""#).replace('$', r#"\$"#);
|
||||
self.lines.push(format!("{}=\"{}\"", name, escaped));
|
||||
}
|
||||
|
||||
pub fn add_command(&mut self, command: &str) {
|
||||
self.lines.push(command.to_string());
|
||||
}
|
||||
|
||||
@@ -21,17 +21,65 @@ pub fn find_largest_video_file(path: &Path) -> Result<PathBuf> {
|
||||
}
|
||||
|
||||
pub fn find_audio_file(video_path: &Path) -> Result<PathBuf> {
|
||||
let video_name = video_path.file_name().unwrap().to_str().unwrap();
|
||||
let video_extension = video_path.extension().unwrap();
|
||||
let audio_name = format!("{}.m4a", &video_name[..video_name.len() - video_extension.len() - 1]);
|
||||
let audio_path = video_path.parent().unwrap().join(audio_name);
|
||||
let parent = video_path.parent().unwrap();
|
||||
let video_extension = video_path.extension().and_then(|e| e.to_str());
|
||||
|
||||
if !audio_path.exists() {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::NotFound,
|
||||
format!("Audio file does not exist: {}", audio_path.display())
|
||||
));
|
||||
// Try to find .m4a file first (old format)
|
||||
let video_name = video_path.file_stem().and_then(|n| n.to_str()).unwrap_or("");
|
||||
let audio_m4a_path = parent.join(format!("{}.m4a", video_name));
|
||||
if audio_m4a_path.exists() {
|
||||
return Ok(audio_m4a_path);
|
||||
}
|
||||
|
||||
Ok(audio_path)
|
||||
// Try to find another .m4s file (new format)
|
||||
if video_extension == Some("m4s") {
|
||||
let mut audio_candidates = Vec::new();
|
||||
for entry in std::fs::read_dir(parent)? {
|
||||
let entry_path = entry?.path();
|
||||
if entry_path.is_file() {
|
||||
if let Some(ext) = entry_path.extension().and_then(|e| e.to_str()) {
|
||||
if ext == "m4s" && entry_path != video_path {
|
||||
let size = entry_path.metadata()?.len();
|
||||
audio_candidates.push((entry_path, size));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !audio_candidates.is_empty() {
|
||||
// Return the largest .m4s file that's not the video file
|
||||
audio_candidates.sort_by(|a, b| b.1.cmp(&a.1));
|
||||
return Ok(audio_candidates[0].0.clone());
|
||||
}
|
||||
}
|
||||
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::NotFound,
|
||||
format!("Audio file does not exist. Looked for: {}", audio_m4a_path.display())
|
||||
))
|
||||
}
|
||||
|
||||
pub fn find_ass_file(path: &Path) -> Result<PathBuf> {
|
||||
for entry in std::fs::read_dir(path)? {
|
||||
let entry_path = entry?.path();
|
||||
if entry_path.is_file() {
|
||||
if let Some(ext) = entry_path.extension().and_then(|e| e.to_str()) {
|
||||
if ext == "ass" {
|
||||
return Ok(entry_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(std::io::Error::new(
|
||||
std::io::ErrorKind::NotFound,
|
||||
"ASS subtitle file not found in directory"
|
||||
))
|
||||
}
|
||||
|
||||
pub fn get_output_name_from_ass(ass_path: &Path) -> String {
|
||||
ass_path.file_stem()
|
||||
.and_then(|n| n.to_str())
|
||||
.unwrap_or("output")
|
||||
.to_string()
|
||||
}
|
||||
|
||||
33
src/merge.rs
33
src/merge.rs
@@ -1,6 +1,6 @@
|
||||
use crate::audio_converter::convert_audio_to_aac;
|
||||
use crate::dry_run::{print_shell_script_header, ShellScript};
|
||||
use crate::file_finder::{find_audio_file, find_largest_video_file};
|
||||
use crate::file_finder::{find_audio_file, find_ass_file, find_largest_video_file, get_output_name_from_ass};
|
||||
use crate::video_merger::merge_video_and_audio;
|
||||
use std::io::Result;
|
||||
use std::path::Path;
|
||||
@@ -34,13 +34,38 @@ pub fn merge_video_from_path(path: &Path, dry_run: bool, overwrite: bool) -> Res
|
||||
crate::dry_run::print_shell_script(&script);
|
||||
}
|
||||
|
||||
println!("Step 3: Looking for ASS subtitle file to determine output name...");
|
||||
let output_name = match find_ass_file(path) {
|
||||
Ok(ass_path) => {
|
||||
println!("Found ASS file: {}", ass_path.display());
|
||||
let name = get_output_name_from_ass(&ass_path);
|
||||
println!("Output name will be: {}", name);
|
||||
if dry_run {
|
||||
let mut script = ShellScript::new();
|
||||
script.add_variable("ASS_FILE", &ass_path);
|
||||
script.add_variable_str("OUTPUT_NAME", &name);
|
||||
crate::dry_run::print_shell_script(&script);
|
||||
}
|
||||
name
|
||||
}
|
||||
Err(_) => {
|
||||
println!("No ASS file found, using video file name as output name");
|
||||
let name = video_path.file_stem()
|
||||
.and_then(|n| n.to_str())
|
||||
.unwrap_or("output")
|
||||
.to_string();
|
||||
println!("Output name will be: {}", name);
|
||||
name
|
||||
}
|
||||
};
|
||||
|
||||
println!();
|
||||
println!("Step 3: Converting audio to AAC format...");
|
||||
println!("Step 4: Converting audio to AAC format...");
|
||||
let aac_path = convert_audio_to_aac(&audio_path, dry_run, overwrite)?;
|
||||
println!();
|
||||
|
||||
println!("Step 4: Merging video and audio...");
|
||||
let output_path = merge_video_and_audio(&video_path, &aac_path, dry_run, overwrite)?;
|
||||
println!("Step 5: Merging video and audio...");
|
||||
let output_path = merge_video_and_audio(&video_path, &aac_path, &output_name, path, dry_run, overwrite)?;
|
||||
|
||||
if dry_run {
|
||||
println!();
|
||||
|
||||
@@ -4,11 +4,11 @@ use std::io::Result;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::fs;
|
||||
|
||||
pub fn merge_video_and_audio(video_path: &Path, audio_path: &Path, dry_run: bool, overwrite: bool) -> Result<PathBuf> {
|
||||
pub fn merge_video_and_audio(video_path: &Path, audio_path: &Path, output_name: &str, output_dir: &Path, dry_run: bool, overwrite: bool) -> Result<PathBuf> {
|
||||
let origin_video_extension = video_path.extension().unwrap().to_str().unwrap();
|
||||
let origin_filename = format!("original.{}", &origin_video_extension);
|
||||
let origin_path = video_path.parent().unwrap().join(origin_filename);
|
||||
let output_path = video_path.with_extension("mp4");
|
||||
let output_path = output_dir.join(format!("{}.mp4", output_name));
|
||||
|
||||
if dry_run {
|
||||
let mut script = ShellScript::new();
|
||||
@@ -24,7 +24,7 @@ pub fn merge_video_and_audio(video_path: &Path, audio_path: &Path, dry_run: bool
|
||||
.input_var("VIDEO_BACKUP")
|
||||
.input_var("AUDIO_AAC")
|
||||
.codec("copy")
|
||||
.output_var("VIDEO_OUTPUT")
|
||||
.output(&output_path)
|
||||
.execute(true)?;
|
||||
return Ok(output_path);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user