From 73fab488155bea3f7fb0b4d1978db1b4678bf1c8 Mon Sep 17 00:00:00 2001 From: Esa Kataja Date: Thu, 14 Aug 2025 16:39:34 +0300 Subject: [PATCH] refactor: split subtitle processing into discrete functions with error handling --- src/main.ts | 86 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 28 deletions(-) diff --git a/src/main.ts b/src/main.ts index 9b4f88f..3082927 100644 --- a/src/main.ts +++ b/src/main.ts @@ -19,21 +19,62 @@ const lang_codes = { "tur": "tr", }; -function main() { +function subtitlesLookup(file: string): videoFile { + console.log("Looking up subtitles from " + file); const command = new Deno.Command("mkvmerge", { - args: ["-J", input], + args: ["-J", file], }); - - const { code, stdout, stderr } = command.outputSync(); - - const mkvmerge_output = JSON.parse( - new TextDecoder().decode(stdout), - ) as videoFile; + const { code, stderr, stdout } = command.outputSync(); const error = new TextDecoder().decode(stderr); if (code !== 0) { console.error(error); - return; + throw new Error(error); } + return JSON.parse(new TextDecoder().decode(stdout)) as videoFile; +} + +function ripSubtitles(file: string, languages: Record) { + console.log("Ripping subtitles from " + file); + const command = new Deno.Command("mkvextract", { + args: [ + "tracks", + file, + ...Object.entries(languages).map(([id, lang]) => `${id}:${lang}`), + ], + }); + const { code, stderr } = command.outputSync(); + const error = new TextDecoder().decode(stderr); + if (code !== 0) { + console.error(error); + throw new Error(error); + } +} + +async function convertSubtitles(languages: Record) { + console.log("Converting subtitles"); + const pool: Deno.ChildProcess[] = []; + for (const [_, lang] of Object.entries(languages)) { + const child = new Deno.Command("vobsub2srt", { + args: ["-l", lang, "--blacklist", "|", lang], + }).spawn(); + pool.push(child); + } + for (const child of pool) { + await child.status; + } +} + +function cleanUp(languages: Record) { + console.log("Cleaning up"); + for (const [_, lang] of Object.entries(languages)) { + Deno.remove(lang + ".srt"); + Deno.remove(lang + ".idx"); + Deno.remove(lang + ".sub"); + } +} + +async function main() { + const mkvmerge_output = subtitlesLookup(input); const languages_in_file: Record = {}; for (const track of mkvmerge_output.tracks) { if (!(track.type === "subtitles")) { @@ -47,21 +88,9 @@ function main() { } languages_in_file[track.id] = lang; } - const formatted_language_string = Object.entries(languages_in_file) - .map(([id, lang]) => `${id}:${lang}`); - const rip_cmd = new Deno.Command("mkvextract", { - args: ["tracks", input, ...formatted_language_string], - }); - rip_cmd.outputSync(); + ripSubtitles(input, languages_in_file); - for (const [_, lang] of Object.entries(languages_in_file)) { - const convert_cmd = new Deno.Command("vobsub2srt", { - args: ["-l", lang, "--blacklist", "|", lang], - }); - convert_cmd.outputSync(); - Deno.remove(lang + ".idx"); - Deno.remove(lang + ".sub"); - } + await convertSubtitles(languages_in_file); const ffmpeg_cmd_raw = []; const subTracksById = new Map( @@ -104,13 +133,14 @@ function main() { const ffmpeg_error = new TextDecoder().decode(ffmpeg_stderr); if (ffmpeg_code !== 0) { console.error(ffmpeg_error); - return; - } - for (const [_, lang] of Object.entries(languages_in_file)) { - Deno.remove(lang + ".srt"); + throw new Error(ffmpeg_error); } + cleanUp(languages_in_file); } if (import.meta.main) { - main(); + main().catch((e) => { + console.error(e); + Deno.exit(1); + }); }