feat: origin filename support.
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -54,7 +54,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bilibili-merge"
|
name = "bilibili-merge"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "bilibili-merge"
|
name = "bilibili-merge"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
authors = ["licsber <admin@licsber.site>"]
|
authors = ["licsber <admin@licsber.site>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ impl ShellScript {
|
|||||||
self.lines.push(format!("{}=\"{}\"", name, escaped));
|
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) {
|
pub fn add_command(&mut self, command: &str) {
|
||||||
self.lines.push(command.to_string());
|
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> {
|
pub fn find_audio_file(video_path: &Path) -> Result<PathBuf> {
|
||||||
let video_name = video_path.file_name().unwrap().to_str().unwrap();
|
let parent = video_path.parent().unwrap();
|
||||||
let video_extension = video_path.extension().unwrap();
|
let video_extension = video_path.extension().and_then(|e| e.to_str());
|
||||||
let audio_name = format!("{}.m4a", &video_name[..video_name.len() - video_extension.len() - 1]);
|
|
||||||
let audio_path = video_path.parent().unwrap().join(audio_name);
|
|
||||||
|
|
||||||
if !audio_path.exists() {
|
// Try to find .m4a file first (old format)
|
||||||
return Err(std::io::Error::new(
|
let video_name = video_path.file_stem().and_then(|n| n.to_str()).unwrap_or("");
|
||||||
std::io::ErrorKind::NotFound,
|
let audio_m4a_path = parent.join(format!("{}.m4a", video_name));
|
||||||
format!("Audio file does not exist: {}", audio_path.display())
|
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::audio_converter::convert_audio_to_aac;
|
||||||
use crate::dry_run::{print_shell_script_header, ShellScript};
|
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 crate::video_merger::merge_video_and_audio;
|
||||||
use std::io::Result;
|
use std::io::Result;
|
||||||
use std::path::Path;
|
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);
|
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!();
|
||||||
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)?;
|
let aac_path = convert_audio_to_aac(&audio_path, dry_run, overwrite)?;
|
||||||
println!();
|
println!();
|
||||||
|
|
||||||
println!("Step 4: Merging video and audio...");
|
println!("Step 5: Merging video and audio...");
|
||||||
let output_path = merge_video_and_audio(&video_path, &aac_path, dry_run, overwrite)?;
|
let output_path = merge_video_and_audio(&video_path, &aac_path, &output_name, path, dry_run, overwrite)?;
|
||||||
|
|
||||||
if dry_run {
|
if dry_run {
|
||||||
println!();
|
println!();
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ use std::io::Result;
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::fs;
|
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_video_extension = video_path.extension().unwrap().to_str().unwrap();
|
||||||
let origin_filename = format!("original.{}", &origin_video_extension);
|
let origin_filename = format!("original.{}", &origin_video_extension);
|
||||||
let origin_path = video_path.parent().unwrap().join(origin_filename);
|
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 {
|
if dry_run {
|
||||||
let mut script = ShellScript::new();
|
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("VIDEO_BACKUP")
|
||||||
.input_var("AUDIO_AAC")
|
.input_var("AUDIO_AAC")
|
||||||
.codec("copy")
|
.codec("copy")
|
||||||
.output_var("VIDEO_OUTPUT")
|
.output(&output_path)
|
||||||
.execute(true)?;
|
.execute(true)?;
|
||||||
return Ok(output_path);
|
return Ok(output_path);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user