feat: implement robust format identification, plugin availability checks, and automatic conversion path rerouting on failure
Release / check-release (push) Successful in 16s
Release / build_gnu (push) Skipped
Release / build_musl (push) Skipped
Release / build_windows (push) Skipped
Release / package_gnu (deb) (push) Skipped
Release / package_gnu (rpm) (push) Skipped
Release / package_musl (deb) (push) Skipped
Release / package_musl (rpm) (push) Skipped
Release / publish-release (push) Skipped
CI / Test (push) Successful in 1m52s
CI / Build Linux (push) Successful in 2m0s

This commit is contained in:
Elias Wendland committed 2026-07-16 14:37:21 +02:00
1 parent a372937854
commit d3b7d7a18f
8 files changed
+244 -97

No files matched your search

+61 -41
View File
@@ -23,41 +23,61 @@ impl Plugin for PluginImpl {
fn name(&self) -> &'static str {
"ffmpeg_audio"
}
fn from_formats(&self) -> Vec<&'static str> {
vec![
"mp3", "wav", "ogg", "flac", "aac", "m4a", "opus", "wma", "amr", "aiff", "aiff", "au",
"mp3", "ogg", "aac", "m4a", "opus", "wma", "mka", "mp2", "ra", "wav", "flac", "alac",
"aiff", "au", "caf", "w64", "ac3", "eac3", "dts", "truehd", "thd", "ape", "wv", "tta",
"amr", "spx", "gsm", "voc",
]
}
fn to_formats(&self) -> Vec<&'static str> {
vec![
"mp3", "wav", "ogg", "flac", "aac", "m4a", "opus", "wma", "amr", "aiff", "aiff", "au",
"mp3", "ogg", "aac", "m4a", "opus", "wma", "mka", "mp2", "ra", "wav", "flac", "alac",
"aiff", "au", "caf", "w64", "ac3", "eac3", "dts", "truehd", "thd", "ape", "wv", "tta",
"amr", "spx", "gsm", "voc",
]
}
fn is_available(&self) -> bool {
std::process::Command::new("ffmpeg")
.arg("-version")
.output()
.is_ok()
}
fn familiarity(&self, _from: &str, to: &str) -> u8 {
match to {
"mp3" | "wav" => 255,
"flac" | "m4a" | "aac" => 240,
"ogg" | "opus" => 220,
"wma" | "amr" => 150,
"aiff" | "au" => 120,
"m4a" | "aac" | "flac" => 240,
"ogg" | "opus" | "alac" => 220,
"ac3" | "eac3" | "dts" => 180,
"wma" | "amr" | "mka" | "mp2" => 150,
"aiff" | "au" | "caf" | "w64" => 120,
"ape" | "wv" | "tta" | "truehd" | "thd" => 100,
"spx" | "gsm" | "voc" | "ra" => 80,
_ => 128,
}
}
fn quality(&self, _from: &str, to: &str) -> u8 {
match to {
"flac" | "wav" | "aiff" | "au" => 255,
"opus" | "ogg" | "aac" | "m4a" => 220,
"mp3" => 200,
"wma" | "amr" => 150,
"flac" | "wav" | "aiff" | "au" | "alac" | "ape" | "wv" | "tta" | "caf" | "w64"
| "truehd" | "thd" => 255,
"opus" | "ogg" | "aac" | "m4a" | "eac3" | "dts" => 220,
"mp3" | "ac3" | "mka" | "mp2" | "ra" => 200,
"wma" | "amr" | "spx" | "gsm" | "voc" => 150,
_ => 128,
}
}
fn speed(&self, _from: &str, to: &str) -> u8 {
match to {
"wav" | "aiff" | "au" => 255,
"flac" => 200,
"mp3" | "aac" | "m4a" | "ogg" => 180,
"opus" | "wma" | "amr" => 150,
"wav" | "aiff" | "au" | "caf" | "w64" | "voc" => 255,
"flac" | "alac" | "wv" | "mp2" | "ac3" | "dts" => 200,
"mp3" | "aac" | "m4a" | "ogg" | "mka" | "eac3" => 180,
"opus" | "wma" | "amr" | "ape" | "tta" | "truehd" | "thd" | "spx" | "gsm" | "ra" => 150,
_ => 128,
}
}
@@ -85,33 +105,33 @@ impl Plugin for PluginImpl {
let mut raw_args = vec![];
match to {
"mp3" => {
raw_args.extend(vec!["-c:a", "libmp3lame", "-q:a", "2"]);
}
"ogg" => {
raw_args.extend(vec!["-c:a", "libvorbis", "-q:a", "4"]);
}
"flac" => {
raw_args.extend(vec!["-c:a", "flac"]);
}
"aac" | "m4a" => {
raw_args.extend(vec!["-c:a", "aac", "-b:a", "192k"]);
}
"opus" => {
raw_args.extend(vec!["-c:a", "libopus", "-b:a", "128k"]);
}
"wma" => {
raw_args.extend(vec!["-c:a", "wmav2", "-b:a", "192k"]);
}
"amr" => {
raw_args.extend(vec!["-ar", "8000", "-c:a", "libopencore_amrnb", "-b:a", "12.2k"]);
}
"wav" | "aiff" | "au" => {
raw_args.extend(vec!["-c:a", "pcm_s16le"]);
}
_ => {
raw_args.extend(vec!["-c:a", "copy"]);
}
"mp3" => raw_args.extend(vec!["-c:a", "libmp3lame", "-q:a", "2"]),
"ogg" => raw_args.extend(vec!["-c:a", "libvorbis", "-q:a", "4"]),
"aac" | "m4a" | "mka" => raw_args.extend(vec!["-c:a", "aac", "-b:a", "192k"]),
"opus" => raw_args.extend(vec!["-c:a", "libopus", "-b:a", "128k"]),
"mp2" => raw_args.extend(vec!["-c:a", "mp2", "-b:a", "192k"]),
"wma" => raw_args.extend(vec!["-c:a", "wmav2", "-b:a", "192k"]),
"flac" => raw_args.extend(vec!["-c:a", "flac"]),
"alac" => raw_args.extend(vec!["-c:a", "alac"]),
"ape" => raw_args.extend(vec!["-c:a", "ape"]),
"wv" => raw_args.extend(vec!["-c:a", "wavpack"]),
"tta" => raw_args.extend(vec!["-c:a", "tta"]),
"ac3" => raw_args.extend(vec!["-c:a", "ac3", "-b:a", "384k"]),
"eac3" => raw_args.extend(vec!["-c:a", "eac3", "-b:a", "640k"]),
"dts" => raw_args.extend(vec!["-c:a", "dca", "-strict", "-2", "-b:a", "1536k"]),
"truehd" | "thd" => raw_args.extend(vec!["-c:a", "truehd", "-strict", "-2"]),
"wav" | "aiff" | "au" | "caf" | "w64" => raw_args.extend(vec!["-c:a", "pcm_s16le"]),
"amr" => raw_args.extend(vec![
"-ar",
"8000",
"-c:a",
"libopencore_amrnb",
"-b:a",
"12.2k",
]),
"spx" => raw_args.extend(vec!["-c:a", "libspeex"]),
"gsm" => raw_args.extend(vec!["-ar", "8000", "-c:a", "libgsm"]),
_ => raw_args.extend(vec!["-c:a", "copy"]),
}
let rt = tokio::runtime::Runtime::new().map_err(|e| e.to_string())?;
+115 -21
View File
@@ -23,47 +23,63 @@ impl Plugin for PluginImpl {
fn name(&self) -> &'static str {
"ffmpeg_video"
}
fn from_formats(&self) -> Vec<&'static str> {
vec!["mp4", "webm", "mkv", "avi", "mov", "wmv", "flv", "gif"]
vec![
"mp4", "webm", "mkv", "avi", "mov", "wmv", "flv", "gif", "m4v", "3gp", "ts", "m2ts",
"vob", "mpg", "mpeg", "mxf", "ogv", "apng", "webp",
]
}
fn to_formats(&self) -> Vec<&'static str> {
vec!["mp4", "webm", "mkv", "avi", "mov", "wmv", "flv", "gif"]
vec![
"mp4", "webm", "mkv", "avi", "mov", "wmv", "flv", "gif", "m4v", "3gp", "ts", "m2ts",
"vob", "mpg", "mpeg", "mxf", "ogv", "apng", "webp",
]
}
fn is_available(&self) -> bool {
std::process::Command::new("ffmpeg")
.arg("-version")
.output()
.is_ok()
}
fn familiarity(&self, _from: &str, to: &str) -> u8 {
match to {
"mp4" | "gif" => 255,
"mov" => 240,
"mov" | "m4v" => 240,
"webm" => 220,
"mkv" => 180,
"wmv" => 160,
"flv" => 120,
"avi" => 100,
"wmv" | "mpg" | "mpeg" => 160,
"flv" | "avi" | "3gp" | "vob" => 120,
"ts" | "m2ts" | "mxf" | "ogv" | "apng" | "webp" => 100,
_ => 128,
}
}
fn quality(&self, _from: &str, to: &str) -> u8 {
match to {
"mkv" => 250,
"mov" => 250,
"mp4" => 240,
"mkv" | "mxf" | "ts" | "m2ts" => 250,
"mov" | "mp4" | "m4v" => 240,
"webm" => 210,
"wmv" => 200,
"flv" => 180,
"avi" => 150,
"gif" => 80,
"wmv" | "mpg" | "mpeg" | "vob" => 200,
"flv" | "avi" | "ogv" | "3gp" => 150,
"gif" | "apng" => 100,
"webp" => 50,
_ => 200,
}
}
fn speed(&self, _from: &str, to: &str) -> u8 {
match to {
"mp4" => 220,
"mov" => 220,
"mkv" => 200,
"flv" => 190,
"avi" => 180,
"mp4" | "mov" | "m4v" => 220,
"mkv" | "mpg" | "mpeg" | "ts" | "m2ts" | "mxf" | "vob" => 200,
"flv" | "avi" | "3gp" | "ogv" => 180,
"wmv" => 170,
"gif" => 150,
"webm" => 100,
"gif" | "apng" => 150,
"webp" => 100,
"webm" => 50,
_ => 150,
}
}
@@ -91,7 +107,7 @@ impl Plugin for PluginImpl {
let mut raw_args = vec![];
match to {
"mp4" | "mkv" | "mov" => {
"mp4" | "mkv" | "mov" | "m4v" => {
raw_args.extend(vec![
"-c:v", "libx264", "-crf", "23", "-c:a", "aac", "-pix_fmt", "yuv420p",
]);
@@ -120,9 +136,87 @@ impl Plugin for PluginImpl {
"libmp3lame",
]);
}
"wmv" => {
raw_args.extend(vec![
"-c:v", "wmv2", "-b:v", "1024k", "-c:a", "wmav2", "-b:a", "128k",
]);
}
"flv" => {
raw_args.extend(vec![
"-c:v",
"flv1",
"-b:v",
"800k",
"-c:a",
"libmp3lame",
"-b:a",
"128k",
]);
}
"ts" | "m2ts" | "mpg" | "mpeg" | "vob" => {
raw_args.extend(vec![
"-c:v",
"mpeg2video",
"-qscale:v",
"2",
"-c:a",
"mp2",
"-b:a",
"192k",
]);
}
"mxf" => {
raw_args.extend(vec![
"-c:v",
"mpeg2video",
"-qscale:v",
"2",
"-c:a",
"pcm_s16le",
]);
}
"ogv" => {
raw_args.extend(vec![
"-c:v",
"libtheora",
"-qscale:v",
"6",
"-c:a",
"libvorbis",
"-qscale:a",
"4",
]);
}
"3gp" => {
raw_args.extend(vec![
"-c:v",
"h263",
"-s",
"352x288",
"-c:a",
"libopencore_amrnb",
"-ar",
"8000",
]);
}
"gif" => {
raw_args.extend(vec!["-vf", "fps=15,scale=320:-1:flags=lanczos"]);
}
"webp" => {
raw_args.extend(vec![
"-c:v",
"libwebp",
"-lossless",
"0",
"-qscale",
"75",
"-loop",
"0",
]);
}
"apng" => {
raw_args.extend(vec!["-plays", "0"]);
}
_ => {
raw_args.extend(vec!["-qscale:v", "3"]);
}