feat: settings auto-adjustment, audio fixes

automatically adjust certain settings to ensure conversions complete + warn user
removed two incompatible audio formats (weba, amr)
This commit is contained in:
Maya 2026-06-01 22:24:42 +03:00
parent b6497de556
commit 84c36aa0a1
No known key found for this signature in database
3 changed files with 80 additions and 9 deletions

View File

@ -414,8 +414,11 @@
"no_audio": "No audio stream found.", "no_audio": "No audio stream found.",
"invalid_rate": "Invalid sample rate specified: {rate}Hz", "invalid_rate": "Invalid sample rate specified: {rate}Hz",
"file_too_large": "This file exceeds the {limit}GB browser / device limit. Try Firefox or Safari to convert this large file, which typically have higher limits." "file_too_large": "This file exceeds the {limit}GB browser / device limit. Try Firefox or Safari to convert this large file, which typically have higher limits."
},
"warnings": {
"settings_change": "Changed the setting '{setting}' from '{oldValue}' to '{newValue}' for {file} to prevent conversion failure."
} }
}, },
"privacy": { "privacy": {
"title": "Privacy Policy", "title": "Privacy Policy",
"summary": { "summary": {

View File

@ -79,6 +79,17 @@ export const getCodecs = (
case ".wma": case ".wma":
return { video: "libx264", audio: "wmav2" }; return { video: "libx264", audio: "wmav2" };
case ".aiff":
case ".aifc":
case ".aif":
return { video: "libx264", audio: "pcm_s16be" };
case ".au":
return { video: "libx264", audio: "pcm_mulaw" };
case ".m4b":
return { video: "libx264", audio: "aac" };
case ".voc":
return { video: "libx264", audio: "pcm_u8" };
// animated images // animated images
case ".gif": case ".gif":
case ".webp": case ".webp":

View File

@ -48,7 +48,6 @@ export class FFmpegConverter extends Converter {
new FormatInfo("caf", true, false), // can be alac new FormatInfo("caf", true, false), // can be alac
new FormatInfo("qoa", true, true), new FormatInfo("qoa", true, true),
new FormatInfo("wma", true, true), new FormatInfo("wma", true, true),
new FormatInfo("amr", true, true),
new FormatInfo("ac3", true, true), new FormatInfo("ac3", true, true),
new FormatInfo("aiff", true, true), new FormatInfo("aiff", true, true),
new FormatInfo("aifc", true, true), new FormatInfo("aifc", true, true),
@ -64,7 +63,6 @@ export class FFmpegConverter extends Converter {
new FormatInfo("au", true, true), new FormatInfo("au", true, true),
new FormatInfo("m4b", true, true), new FormatInfo("m4b", true, true),
new FormatInfo("voc", true, true), new FormatInfo("voc", true, true),
new FormatInfo("weba", true, true),
...videoFormats.map( ...videoFormats.map(
(f: string) => new FormatInfo(f, true, true, false, 0), (f: string) => new FormatInfo(f, true, true, false, 0),
), ),
@ -245,6 +243,12 @@ export class FFmpegConverter extends Converter {
ffmpeg.on("log", errorListener); ffmpeg.on("log", errorListener);
const logListener = (l: { message: string }) => {
this.log(l.message);
};
ffmpeg.on("log", logListener);
try { try {
let buf = new Uint8Array(await input.file.arrayBuffer()); let buf = new Uint8Array(await input.file.arrayBuffer());
@ -304,6 +308,7 @@ export class FFmpegConverter extends Converter {
} }
} finally { } finally {
ffmpeg.off("log", errorListener); ffmpeg.off("log", errorListener);
ffmpeg.off("log", logListener);
this.activeConversions.delete(input.id); this.activeConversions.delete(input.id);
ffmpeg.terminate(); ffmpeg.terminate();
} }
@ -332,10 +337,6 @@ export class FFmpegConverter extends Converter {
ffmpeg.on("progress", (progress) => { ffmpeg.on("progress", (progress) => {
input.progress = progress.progress * 100; input.progress = progress.progress * 100;
}); });
ffmpeg.on("log", (l) => {
this.log(l.message);
});
} }
const baseURL = const baseURL =
@ -491,11 +492,12 @@ export class FFmpegConverter extends Converter {
this.log( this.log(
`using detected audio sample rate: ${inputSampleRate}Hz`, `using detected audio sample rate: ${inputSampleRate}Hz`,
); );
// TODO: maybe have a hard cap for certain conversions - 3072kbps is very unrealistic for a mp3 for example lol (qoa -> mp3 detected as 3072kbps)
} }
} }
// channels setting // channels setting
if (settings.channels !== "auto") { if (settings.channels !== 2) {
channelsArgs = ["-ac", settings.channels]; channelsArgs = ["-ac", settings.channels];
this.log( this.log(
`using user setting for audio channels: ${settings.channels}`, `using user setting for audio channels: ${settings.channels}`,
@ -573,6 +575,54 @@ export class FFmpegConverter extends Converter {
const { audio: audioCodec } = getCodecs(to, isAlac); const { audio: audioCodec } = getCodecs(to, isAlac);
if (m4a && keepMetadata) m4aArgs = ["-c:v", "copy"]; // for album art if (m4a && keepMetadata) m4aArgs = ["-c:v", "copy"]; // for album art
/*
* sanity check settings for certain formats, to prevent conversion failure
*/
const settingsChanged: SettingChange[] = [];
if (to === ".opus") {
// work around browser stereo+libopus wasm crash
// no idea why its broken like this in the browser only lol
if (settings.channels >= 2) {
channelsArgs = ["-ac", "1"];
settingsChanged.push({
setting: "channels",
oldValue: settings.channels,
newValue: 1,
file: input.name,
});
}
// TODO: surely better way to do this as well :sob:
if (
audioBitrateArgs[1] &&
parseInt(audioBitrateArgs[1], 10) > 256
) {
audioBitrateArgs = ["-b:a", "256k"];
settingsChanged.push({
setting: "bitrate",
oldValue: settings.bitrate,
newValue: 256,
file: input.name,
});
}
}
for (const change of settingsChanged) {
this.log(
`changed setting "${change.setting}" from "${change.oldValue}" to "${change.newValue}" for file ${change.file} to prevent conversion failure`,
);
ToastManager.add({
type: "warning",
message: m["workers.warnings.settings_change"]({
setting: change.setting,
oldValue: change.oldValue,
newValue: change.newValue,
file: change.file,
}),
});
}
return [ return [
"-i", "-i",
"input", "input",
@ -584,6 +634,8 @@ export class FFmpegConverter extends Converter {
...sampleRateArgs, ...sampleRateArgs,
...channelsArgs, ...channelsArgs,
...tracksArgs, ...tracksArgs,
"-strict",
"experimental",
"output" + to, "output" + to,
]; ];
} }
@ -680,4 +732,9 @@ const handleSpecialOutput = async (
return null; return null;
}; };
/* probeFfprobeValue moved to ./ffprobe.ts */ interface SettingChange {
setting: string;
oldValue: string | number;
newValue: string | number;
file: string;
}