diff --git a/Community/Tdarr_Plugin_gabehf_Make_First_Subtitle_In_Lang_Default.js b/Community/Tdarr_Plugin_gabehf_Make_First_Subtitle_In_Lang_Default.js new file mode 100644 index 0000000..e5a3e9f --- /dev/null +++ b/Community/Tdarr_Plugin_gabehf_Make_First_Subtitle_In_Lang_Default.js @@ -0,0 +1,106 @@ +/* eslint max-len: 0, no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */ +const details = () => ({ + id: 'Tdarr_Plugin_gabehf_Make_First_Subtitle_In_Lang_Default', + Stage: 'Pre-processing', + Name: 'Make First Subtitle In The Preferred Language Default', + Type: 'Subtitle', + Operation: 'Transcode', + Description: + 'If no subtitles in the preferred language are made default already, this plugin sets the first subtitle stream in that language as default. \\n', + Version: '1.0', + Tags: 'pre-processing,ffmpeg,subtitle only,configurable', + Inputs: [{ + name: 'preferred_language', + type: 'string', + defaultValue: 'eng,en', + inputUI: { + type: 'text', + }, + tooltip: + 'Your preferred language code(s) in ISO 639-2 language scheme, separated by a comma. Only the first track that matches any of these language codes will be made default. \\n Default: eng,en', + }], + }); + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const plugin = (file, librarySettings, inputs, otherArguments) => { + const lib = require('../methods/lib')(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign + inputs = lib.loadDefaultValues(inputs, details); + var languages = [] + if (inputs.preferred_language == "") { + languages = ["eng", "en"]; //these languages should be kept, named according to ISO 639-2 language scheme + } else { + languages = inputs.preferred_language.toLowerCase().split(","); //these languages should be kept, named according to ISO 639-2 language scheme + } + + const response = { + processFile: false, + preset: '', + container: `.${file.container}`, + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: false, + infoLog: '', + }; + + // Check if file is a video. If it isn't then exit plugin. + if (file.fileMedium !== 'video') { + // eslint-disable-next-line no-console + console.log('File is not video'); + response.infoLog += '☒File is not video \n'; + response.processFile = false; + return response; + } + + // Set up required variables. + let ffmpegCommandInsert = ''; + let subtitleIdx = 0; + let convert = false; + let defaults = [] // list of tracks currently set as default + + for (let i = 0; i < file.ffProbeData.streams.length; i++) { + try { + if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'subtitle') { + defaults[subtitleIdx] = file.ffProbeData.streams[i].disposition.default === 1 + if (!convert && file.ffProbeData.streams[i].disposition.default === 0 && languages.includes(file.ffProbeData.streams[i].tags.language)) { + convert = true; + ffmpegCommandInsert += `-disposition:s:${subtitleIdx} default `; + response.infoLog += `☒Subtitle stream 0:s:${subtitleIdx} is the first track in preferred language and not currently default; setting as default. \n`; + } else if (file.ffProbeData.streams[i].disposition.default === 1 && languages.includes(file.ffProbeData.streams[i].tags.language)) { + // if any subtitle with the preferred language is marked default, no action is needed. + convert = false; + response.infoLog = ''; + break; + } + subtitleIdx += 1; + } + } catch (err) { + // Error + } + } + + if (convert) { + // remove previous default(s) + for (let i = 0; i < defaults.length; i++) { + if (defaults[i]) { + ffmpegCommandInsert += `-disposition:s:${i} 0 `; + response.infoLog += `☒Subtitle stream 0:s:${i} was default but not in preferred language; removing disposition. \n`; + } + } + } + + // Convert file if convert variable is set to true. + if (convert === true) { + response.processFile = true; + response.preset = `, -map 0 ${ffmpegCommandInsert}-c copy -max_muxing_queue_size 9999`; + response.container = `.${file.container}`; + response.reQueueAfter = true; + } else { + response.processFile = false; + response.infoLog += "☑File doesn't contain subtitle tracks that require modification.\n"; + } + return response; + }; + module.exports.details = details; + module.exports.plugin = plugin; + \ No newline at end of file diff --git a/tests/Community/Tdarr_Plugin_gabehf_Make_First_Subtitle_In_Lang_Default.js b/tests/Community/Tdarr_Plugin_gabehf_Make_First_Subtitle_In_Lang_Default.js new file mode 100644 index 0000000..6169dd5 --- /dev/null +++ b/tests/Community/Tdarr_Plugin_gabehf_Make_First_Subtitle_In_Lang_Default.js @@ -0,0 +1,224 @@ +const run = require('../helpers/run'); +const _ = require('lodash'); + +const testFile = (d1, f1, d2, f2, d3, f3, d4, f4) => ({ + fileMedium: 'video', + container: 'mkv', + ffProbeData: { + streams: [ + { + codec_type: 'video', + }, + { + codec_type: 'audio', + }, + { + codec_type: 'audio', + }, + { + codec_type: 'subtitle', + tags: { + title: '', + language: 'eng', + }, + disposition: { + default: d1, + forced: f1, + }, + }, + { + codec_type: 'subtitle', + tags: { + title: 'Sings / Songs', + language: 'eng', + }, + disposition: { + default: d2, + forced: f2, + }, + }, + { + codec_type: 'subtitle', + tags: { + title: 'Full Dialogue', + language: 'fre', + }, + disposition: { + default: d3, + forced: f3, + }, + }, + { + codec_type: 'subtitle', + tags: { + title: 'Signs & Songs', + language: 'fre', + }, + disposition: { + default: d4, + forced: f4, + }, + }, + ], + }, + }); + +const tests = [ + // default input, no matches + { + input: { + file: _.cloneDeep(require('../sampleData/media/sampleH264_2.json')), + librarySettings: {}, + inputs: {}, + otherArguments: {}, + }, + output: { + processFile: false, + preset: '', + container: '.mkv', + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: false, + infoLog: "☑File doesn't contain subtitle tracks that require modification.\n" + }, + }, + // default input, match + { + input: { + file: _.cloneDeep(require('../sampleData/media/sampleH264_3.json')), + librarySettings: {}, + inputs: {}, + otherArguments: {}, + }, + output: { + processFile: true, + preset: ', -map 0 -disposition:s:0 default -c copy -max_muxing_queue_size 9999', + container: '.mkv', + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: true, + infoLog: "☒Subtitle stream 0:s:0 is the first track in preferred language and not currently default; setting as default. \n" + }, + }, + // custom input, match + { + input: { + file: _.cloneDeep(require('../sampleData/media/sampleH264_3.json')), + librarySettings: {}, + inputs: { + preferred_language: `fra,fre` + }, + otherArguments: {}, + }, + output: { + processFile: true, + preset: ', -map 0 -disposition:s:1 default -c copy -max_muxing_queue_size 9999', + container: '.mkv', + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: true, + infoLog: "☒Subtitle stream 0:s:1 is the first track in preferred language and not currently default; setting as default. \n" + }, + }, + // custom input, no matches + { + input: { + file: _.cloneDeep(require('../sampleData/media/sampleH264_3.json')), + librarySettings: {}, + inputs: { + preferred_language: `dut,ger` + }, + otherArguments: {}, + }, + output: { + processFile: false, + preset: '', + container: '.mkv', + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: false, + infoLog: "☑File doesn't contain subtitle tracks that require modification.\n" + }, + }, + // match, default set after + { + input: { + file: testFile(0,0, 0,0, 1,0, 1,0), + librarySettings: {}, + inputs: {}, + otherArguments: {}, + }, + output: { + processFile: true, + preset: ', -map 0 -disposition:s:0 default -disposition:s:2 0 -disposition:s:3 0 -c copy -max_muxing_queue_size 9999', + container: '.mkv', + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: true, + infoLog: "☒Subtitle stream 0:s:0 is the first track in preferred language and not currently default; setting as default. \n" + + `☒Subtitle stream 0:s:2 was default but not in preferred language; removing disposition. \n` + + `☒Subtitle stream 0:s:3 was default but not in preferred language; removing disposition. \n` + }, + }, + // match, default before + { + input: { + file: testFile(1,0, 1,0, 0,0, 0,0), + librarySettings: {}, + inputs: { + preferred_language: `fre` + }, + otherArguments: {}, + }, + output: { + processFile: true, + preset: ', -map 0 -disposition:s:2 default -disposition:s:0 0 -disposition:s:1 0 -c copy -max_muxing_queue_size 9999', + container: '.mkv', + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: true, + infoLog: "☒Subtitle stream 0:s:2 is the first track in preferred language and not currently default; setting as default. \n" + + `☒Subtitle stream 0:s:0 was default but not in preferred language; removing disposition. \n` + + `☒Subtitle stream 0:s:1 was default but not in preferred language; removing disposition. \n` + }, + }, + // language already has default track + { + input: { + file: testFile(0,0, 1,0, 0,0, 0,0), + librarySettings: {}, + inputs: {}, + otherArguments: {}, + }, + output: { + processFile: false, + preset: '', + container: '.mkv', + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: false, + infoLog: "☑File doesn't contain subtitle tracks that require modification.\n" + }, + }, + // language already has default track + { + input: { + file: testFile(0,0, 0,0, 0,0, 1,0), + librarySettings: {}, + inputs: { + preferred_language: 'fre', + }, + otherArguments: {}, + }, + output: { + processFile: false, + preset: '', + container: '.mkv', + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: false, + infoLog: "☑File doesn't contain subtitle tracks that require modification.\n" + }, + }, +] +void run(tests) \ No newline at end of file