diff --git a/messages/en.json b/messages/en.json index a104ecb..2f34788 100644 --- a/messages/en.json +++ b/messages/en.json @@ -188,9 +188,11 @@ }, "workers": { "errors": { - "general": "Error converting file {file}: {message}", - "magick": "Error in Magick worker, image conversion may not work as expected.`", - "ffmpeg": "Error loading ffmpeg, some features may not work." + "general": "Error converting {file}: {message}", + "magick": "Error in Magick worker, image conversion may not work as expected.", + "ffmpeg": "Error loading ffmpeg, some features may not work.", + "no_audio": "No audio stream found.", + "invalid_rate": "Invalid sample rate specified: {rate}Hz" } }, "jpegify": { diff --git a/src/lib/converters/ffmpeg.svelte.ts b/src/lib/converters/ffmpeg.svelte.ts index d73c167..9a9c88e 100644 --- a/src/lib/converters/ffmpeg.svelte.ts +++ b/src/lib/converters/ffmpeg.svelte.ts @@ -98,7 +98,34 @@ export class FFmpegConverter extends Converter { public async convert(input: VertFile, to: string): Promise { if (!to.startsWith(".")) to = `.${to}`; + let conversionError: string | null = null; const ffmpeg = await this.setupFFmpeg(input); + + // listen for errors during conversion + const errorListener = (l: { message: string }) => { + const msg = l.message; + if ( + msg.includes("Specified sample rate") && + msg.includes("is not supported") + ) { + const rate = Settings.instance.settings.ffmpegCustomSampleRate; + conversionError = m["workers.errors.invalid_rate"]({ rate }); + } else if (msg.includes("Stream map '0:a:0' matches no streams.")) { + conversionError = m["workers.errors.no_audio"](); + } else if ( + msg.includes("Error initializing output stream") || + msg.includes("Error while opening encoder") || + msg.includes("Error while opening decoder") || + (msg.includes("Error") && msg.includes("stream")) || + msg.includes("Conversion failed!") + ) { + // other general errors + if (!conversionError) conversionError = msg; + } + }; + + ffmpeg.on("log", errorListener); + const buf = new Uint8Array(await input.file.arrayBuffer()); await ffmpeg.writeFile("input", buf); log( @@ -111,15 +138,30 @@ export class FFmpegConverter extends Converter { await ffmpeg.exec(command); log(["converters", this.name], "executed ffmpeg command"); + if (conversionError) { + ffmpeg.off("log", errorListener); + ffmpeg.terminate(); + throw new Error(conversionError); + } + const output = (await ffmpeg.readFile( "output" + to, )) as unknown as Uint8Array; + + if (!output || output.length === 0) { + ffmpeg.off("log", errorListener); + ffmpeg.terminate(); + throw new Error("empty file returned"); + } + const outputFileName = input.name.split(".").slice(0, -1).join(".") + to; log( ["converters", this.name], `read ${outputFileName} from ffmpeg virtual fs`, ); + + ffmpeg.off("log", errorListener); ffmpeg.terminate(); const outBuf = new Uint8Array(output).buffer.slice(0); @@ -135,14 +177,6 @@ export class FFmpegConverter extends Converter { ffmpeg.on("log", (l) => { log(["converters", this.name], l.message); - if (l.message.includes("Stream map '0:a:0' matches no streams.")) { - const fileName = input.name; - error( - ["converters", this.name], - `No audio stream found in ${fileName}.`, - ); - addToast("error", `No audio stream found in ${fileName}.`); - } }); const baseURL = diff --git a/src/lib/sections/settings/Conversion.svelte b/src/lib/sections/settings/Conversion.svelte index f9a4620..70ebb26 100644 --- a/src/lib/sections/settings/Conversion.svelte +++ b/src/lib/sections/settings/Conversion.svelte @@ -39,7 +39,7 @@