const details = () => ({ id: 'Tdarr_Plugin_MM1_MrMeeb_Full_Stack', Stage: 'Pre-processing', Name: 'MrMeeb Full Stack Processing', Type: 'Video', Operation: 'Transcode', Description: 'Automatically removes TrueHD and replaces with a suitable AC3 5.1 track, either pre-existing or created.\n Removes non-English and non-German subtitles.\n Transcodes x264 content to HEVC using NVENC, with a focus on quality', Version: '0.1', Tags: 'pre-processing', Inputs: [ { name: 'process_video', type: 'boolean', defaultValue: true, inputUI: { type: 'dropdown', options: [ 'true', 'false', ], }, tooltip: `Select whether to process video, or just copy over`, }, { name: 'process_audio', type: 'boolean', defaultValue: true, inputUI: { type: 'dropdown', options: [ 'true', 'false', ], }, tooltip: `Select whether to process audio, or just copy over`, }, { name: 'process_subs', type: 'boolean', defaultValue: true, inputUI: { type: 'dropdown', options: [ 'true', 'false', ], }, tooltip: `Select whether to process subs, or just copy over`, }, { name: 'remove_commentary', type: 'boolean', defaultValue: true, inputUI: { type: 'dropdown', options: [ 'true', 'false', ], }, tooltip: `Select whether to remove commentary audio and subtitle tracks`, }, { name: 'crf', type: 'string', // set the data type of the input ('string', 'number', 'boolean') defaultValue: '19', // set the default value of the input incase the user enters no input inputUI: { type: 'text', // specify how the input UI will appear to the user ('text' or 'dropdown') }, tooltip: `Enter CRF value used for video transcoding.`, }, ], }); // eslint-disable-next-line no-unused-vars const plugin = (file, librarySettings, inputs, otherArguments) => { const lib = require('../methods/lib')(); // load default plugin inputs inputs = lib.loadDefaultValues(inputs, details); // Load response object const response = { processFile: false, // If set to false, the file will be skipped. Set to true to have the file transcoded. preset: '', // HandBrake/FFmpeg CLI arguments you'd like to use. // For FFmpeg, the input arguments come first followed by , followed by the output argument. // Examples // HandBrake // '-Z "Very Fast 1080p30"' // FFmpeg // '-sn -map_metadata -1 -c:v copy -c:a copy' container: '.mp4', // The container of the transcoded output file. handBrakeMode: false, // Set whether to use HandBrake or FFmpeg for transcoding FFmpegMode: false, infoLog: '', // This will be shown when the user clicks the 'i' (info) button on a file in the output queue if // it has been skipped. // Give reasons why it has been skipped ('File has no title metadata, File meets conditions!') // Optional (include together) //file, //removeFromDB: false, // Tell Tdarr to remove file from database if true //updateDB: false, // Change file object above and update database if true }; // Required global variables for functions let ffmpegAudioFirstTrack = ''; let ffmpegAudioOtherTracks = ''; let ffmpegSubs = ''; let ffmpegVideo = ''; // Defining functions const processAudio = (file, librarySettings, inputs, otherArguments) => { if (inputs.process_audio == false) { response.infoLog += `Processing audio set to skip. Copying all present tracks over.\n` } else { // Function variables let audioIdx = -1; let audioIdxTruehd = -1; let trueHD = -1; let trueHDi = -1; let audioIdxDtshdma = -1; let dtshdma = -1; let dtshdmai = -1; let ac3Count = 0; let dtsHandled = 0; console.log(` === Running processAudio function === `) // Go through all streams, hunting for TrueHD/DTS-HD MA for (let i = 0; i < file.ffProbeData.streams.length; i ++) { // Work with audio streams only if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio') { let MMCodec = file.ffProbeData.streams[i].codec_name.toUpperCase(); let MMChannelLayout = file.ffProbeData.streams[i].channel_layout.replace('(side)', ''); //console.log(`Stream ${i} is an audio stream`); // Keep track of audio stream relative numbers try { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { audioIdx++; } } catch (err) {} // Identify wanted tracks try { // Identify if stream is TrueHD if (file.ffProbeData.streams[i].codec_name.toLowerCase() === 'truehd') { console.log(`Stream ${i} (audio stream ${audioIdx}) is TrueHD. Commencing TrueHD handling process`); response.infoLog += `Stream ${i} (audio stream ${audioIdx}) is TrueHD. Commencing TrueHD handling process.\n` trueHD = audioIdx; trueHDi = i; let trueHDLang = file.ffProbeData.streams[i].tags.language let trueHDReplacementCount = 0 // Look for a suitable AC3 5.1 track to replace it for (let i = 0; i < file.ffProbeData.streams.length; i ++) { if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio') { audioIdxTruehd++; MMCodec = file.ffProbeData.streams[i].codec_name.toUpperCase(); MMChannelLayout = file.ffProbeData.streams[i].channel_layout.replace('(side)', ''); try { if ( (file.ffProbeData.streams[i].tags.title != undefined && file.ffProbeData.streams[i].tags.title.toLowerCase().includes("commentary") || file.ffProbeData.streams[i].disposition.comment == 1) && inputs.remove_commentary == true ) { console.log(`Stream ${i} (audio stream ${audioIdxTruehd}) is probably a commentary track. Selected to remove.`) response.infoLog += `Stream ${i} (audio stream ${audioIdxTruehd}) is probably a commentary track. Selected to remove.\n` } else if ( (file.ffProbeData.streams[i].tags.title != undefined && file.ffProbeData.streams[i].tags.title.toLowerCase().includes("commentary") || file.ffProbeData.streams[i].disposition.comment == 1) && inputs.remove_commentary == false ) { console.log(`Stream ${i} (audio stream ${audioIdxTruehd}) is probably a commentary track. Selected to keep.`) response.infoLog += `Stream ${i} (audio stream ${audioIdxTruehd}) is probably a commentary track. Selected to keep.\n` ffmpegAudioOtherTracks += ` -map 0:a:${audioIdxTruehd}` } // Identify if stream is AC3 5.1 else if ( file.ffProbeData.streams[i].codec_name.toLowerCase() === 'ac3' && file.ffProbeData.streams[i].channels === 6 && file.ffProbeData.streams[i].tags.language === trueHDLang ) { console.log(`Stream ${i} (audio stream ${audioIdxTruehd}) is AC3 5.1 and in matching language. Suitable replacement.`); console.log(`${MMCodec} <- Should be AC3`) response.infoLog += `Stream ${i} (audio stream ${audioIdxTruehd}) is AC3 5.1 and in matching language. Suitable replacement.\n` response.infoLog +=`${MMCodec} <- Should be AC3\n` trueHDReplacementCount++ if (trueHDReplacementCount <= 1) { ffmpegAudioFirstTrack = ` -map -0:a -map 0:a:${audioIdxTruehd} -metadata:s:a:0 "title=${MMCodec} - ${MMChannelLayout} - MM" -disposition:a:0 default` } else { console.log('More than 1 suitable AC3 5.1 track has been detected - something has probably gone wrong in detection of commentary tracks. The first found track will be kept') response.infoLog += 'More than 1 suitable AC3 5.1 track has been detected - something has probably gone wrong in detection of commentary tracks. The first found track will be kept\n' } } else if ( file.ffProbeData.streams[i].codec_name.toLowerCase() === 'ac3' && file.ffProbeData.streams[i].channels === 6 && file.ffProbeData.streams[i].tags.language !== trueHDLang && file.ffProbeData.streams[i].tags.language.toLowerCase() == 'eng' ) { console.log(`Stream ${i} (audio stream ${audioIdxTruehd}) is AC3 5.1. It does not match the native language of the movie, but is in English. Probably want to keep.`); response.infoLog += `Stream ${i} (audio stream ${audioIdxTruehd}) is AC3 5.1. It does not match the native language of the movie, but is in English. Probably want to keep.\n` ffmpegAudioOtherTracks += ` -map 0:a:${audioIdxTruehd}` } else if (file.ffProbeData.streams[i].codec_name.toLowerCase() !== 'truehd') { console.log(`Stream ${i} (audio stream ${audioIdxTruehd}) isn't AC3 5.1, and TrueHD is already available to create an AC3 5.1 track if not present. Removing.`) response.infoLog += `Stream ${i} (audio stream ${audioIdxTruehd}) isn't AC3 5.1, and TrueHD is already available to create an AC3 5.1 track if not present. Removing.\n` }; } catch (error) { } }; }; if (trueHDReplacementCount = 0) { console.log('A suitable TrueHD replacement track is not available. Creating my own.') //console.log(`${MMCodec} <- Should be AC3`) if (file.ffProbeData.streams[trueHDi].channels > 6) { response.infoLog += 'TrueHD track exists, but no AC3 compatibility track is present. Creating one, and downmixing to 6 channels.\n' ffmpegAudioFirstTrack = ` -map -0:a -map 0:a:${trueHD} -c:a:0 ac3 -b:a:0 640k -ac:a:0 6 -metadata:s:a:0 "title=AC3 - 5.1 - MM" -disposition:a:0 default` } else { response.infoLog += 'TrueHD track exists, but no AC3 compatibility track is present. Creating one.\n' ffmpegAudioFirstTrack = ` -map -0:a -map 0:a:${trueHD} -c:a:0 ac3 -b:a:0 640k -ac:a:0 ${file.ffProbeData.streams[trueHDi].channels} -metadata:s:a:0 "title=AC3 - 5.1 - MM" -disposition:a:0 default` } } } // Identify if stream is DTS-HD MA if (file.ffProbeData.streams[i].profile != undefined && file.ffProbeData.streams[i].profile.toLowerCase() === 'dts-hd ma') { // Check if DTS-HD MA has already been handled by a previous run // Assume that it will be the second stream (first audio stream) - it should be, if already handled MMChannelLayout = file.ffProbeData.streams[i].channel_layout.replace('(side)', ''); // Have to declare this here to make the if statement work. Leaving it in place further down as well if (file.ffProbeData.streams[i].tags.title === `DTS-HD MA - ${MMChannelLayout} - MM`) { console.log(`Stream ${i} (audio stream ${audioIdx}) is DTS-HD MA and has already been handled. Safe to assume this file has already been treated.`); response.infoLog += `Stream ${i} (audio stream ${audioIdx}) is DTS-HD MA and has already been handled. Safe to assume this file has already been treated.\n` // Mark DTS-HD MA handling process as complete causing everything else audio-related to be skipped dtsHandled = 1 } else { console.log(`Stream ${i} (audio stream ${audioIdx}) is DTS-HD MA and has not been handled. Commencing DTS-HD MA handling process`); response.infoLog += `Stream ${i} (audio stream ${audioIdx}) is DTS-HD MA. Commencing DTS-HD MA handling process.\n` }; dtshdma = audioIdx; // Index of DTS-HD MA track relative to other audio tracks dtshdmai = i; // Index of DTS-HD MA track within all tracks (audio, video, subs, etc) let dtshdmaLang = file.ffProbeData.streams[i].tags.language // Language of DTS-HD MA track let dtshdmaReplacementCount = 0 // Number of DTS-HD MA replacement candidates // Look if there is a suitable AC3 5.1 track to use alongside it for (let i = 0; i < file.ffProbeData.streams.length; i ++) { // Iterate through all streams if (dtsHandled == 0 && file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio') { // If the stream is an audio stream audioIdxDtshdma++; // Index of replacement track MMCodec = file.ffProbeData.streams[i].codec_name.toUpperCase(); MMChannelLayout = file.ffProbeData.streams[i].channel_layout.replace('(side)', ''); try { // Identify if stream is commentary track if ( (file.ffProbeData.streams[i].tags.title != undefined && file.ffProbeData.streams[i].tags.title.toLowerCase().includes("commentary") || file.ffProbeData.streams[i].disposition.comment == 1) && inputs.remove_commentary == true ) { console.log(`Stream ${i} (audio stream ${audioIdxDtshdma}) is probably a commentary track. Selected to remove.`) response.infoLog += `Stream ${i} (audio stream ${audioIdxDtshdma}) is probably a commentary track. Selected to remove.\n` } else if ( (file.ffProbeData.streams[i].tags.title != undefined && file.ffProbeData.streams[i].tags.title.toLowerCase().includes("commentary") || file.ffProbeData.streams[i].disposition.comment == 1) && inputs.remove_commentary == false ) { console.log(`Stream ${i} (audio stream ${audioIdxTruehd}) is probably a commentary track. Selected to keep.`) response.infoLog += `Stream ${i} (audio stream ${audioIdxTruehd}) is probably a commentary track. Selected to keep.\n` ffmpegAudioOtherTracks += ` -map 0:a:${audioIdxTruehd}` } // Identify if stream is AC3 5.1 else if ( file.ffProbeData.streams[i].codec_name.toLowerCase() === 'ac3' && // is codec AC3 file.ffProbeData.streams[i].channels === 6 && // does it have 6 channels (5.1) file.ffProbeData.streams[i].tags.language === dtshdmaLang // does it have the same language as the DTS-HD MA track ) { console.log(`Stream ${i} (audio stream ${audioIdxDtshdma}) is AC3 5.1 and in matching language. Keeping alongside the DTS-HD MA track.`); console.log(`${MMCodec} <- Should be AC3`) response.infoLog += `Stream ${i} (audio stream ${audioIdxDtshdma}) is AC3 5.1 and in matching language. Keeping alongside the DTS-HD MA track.\n` response.infoLog +=`${MMCodec} <- Should be AC3\n` dtshdmaReplacementCount++ // Add to the DTS-HD MA replacement count if (dtshdmaReplacementCount <= 1) { // If we found a single DTS-HD MA replacement... ffmpegAudioFirstTrack = ` -map -0:a -map 0:a:${dtshdma} -metadata:s:a:0 "title=DTS-HD MA - ${MMChannelLayout} - MM" -disposition:a:0 default -map 0:a:${audioIdxDtshdma} -metadata:s:a:1 "title=${MMCodec} - ${MMChannelLayout} - MM"` // Keep both the DTS-HD MA and AC3 tracks, label them } else { console.log('More than 1 suitable AC3 5.1 track has been detected - something has probably gone wrong in detection of commentary tracks. The first found track will be kept') response.infoLog += 'More than 1 suitable AC3 5.1 track has been detected - something has probably gone wrong in detection of commentary tracks. The first found track will be kept\n' } } else if ( file.ffProbeData.streams[i].codec_name.toLowerCase() === 'ac3' && // is codec AC3 file.ffProbeData.streams[i].channels === 6 && // does it have 6 channels (5.1) file.ffProbeData.streams[i].tags.language !== dtshdmaLang && // does it NOT match the language of the DTS-HD MA track file.ffProbeData.streams[i].tags.language.toLowerCase() == 'eng' // is the AC3 track in English ) { console.log(`Stream ${i} (audio stream ${audioIdxDtshdma}) is AC3 5.1. It does not match the native language of the movie, but is in English. Probably want to keep.`); response.infoLog += `Stream ${i} (audio stream ${audioIdxDtshdma}) is AC3 5.1. It does not match the native language of the movie, but is in English. Probably want to keep.\n` ffmpegAudioOtherTracks += ` -map 0:a:${audioIdxDtshdma}` // Add the track to the list of additional tracks } else if (file.ffProbeData.streams[i].codec_name.toLowerCase() !== 'dts') { // Remove any track that isn't AC3 since we already have DTS-HD MA to work with console.log(`Stream ${i} (audio stream ${audioIdxDtshdma}) isn't AC3 5.1, and DTS-HD MA is already available to create an AC3 5.1 track if not present. Removing.`) response.infoLog += `Stream ${i} (audio stream ${audioIdxDtshdma}) isn't AC3 5.1, and DTS-HD MA is already available to create an AC3 5.1 track if not present. Removing.\n` }; } catch (error) { } }; }; if (dtsHandled == 0 && dtshdmaReplacementCount == 0) { // If we didn't find a replacement candidate console.log('A suitable DTS-HD MA replacement track is not available. Creating my own.') //console.log(`${MMCodec} <- Should be AC3`) if (file.ffProbeData.streams[dtshdmai].channels > 6) { // If the DTS-HD MA track has more than 6 channels, downmix to 6 channels response.infoLog += 'DTS-HD MA track exists, but no AC3 compatibility track is present. Creating one, and downmixing to 6 channels.\n' ffmpegAudioFirstTrack = ` -map -0:a -map 0:a:${dtshdma} -metadata:s:a:0 "title=DTS-HD MA - ${MMChannelLayout} - MM" -disposition:a:0 default -map 0:a:${dtshdma} -c:a:1 ac3 -b:a:1 640k -ac:a:1 6 -metadata:s:a:1 "title=AC3 - 5.1 - MM"` } else { // Otherwise, create an AC3 track with the same channel layout response.infoLog += 'DTS-HD MA track exists, but no AC3 compatibility track is present. Creating one.\n' ffmpegAudioFirstTrack = ` -map -0:a -map 0:a:${dtshdma} -metadata:s:a:0 "title=DTS-HD MA - ${MMChannelLayout} - MM" -disposition:a:0 default -map 0:a:${dtshdma} -c:a:1 ac3 -b:a:1 640k -ac:a:1 ${file.ffProbeData.streams[dtshdmai].channels} -metadata:s:a:1 "title=AC3 - 5.1 - MM"` } } // Mark DTS-HD MA handling process as complete, skipping the logic for no THD/DTS-HD MA. Was already set if the run had completed before. dtsHandled = 1 } } catch (error) { console.log(error) } } }; // Logic for if no TrueHD/DTS-HD MA track present if (trueHD < 0 && dtsHandled == 0) { console.log('No TrueHD track is present in the file.') response.infoLog += `No TrueHD track is present.\n` audioIdx = -1 for (let i = 0; i < file.ffProbeData.streams.length; i ++) { // Work with audio streams only if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio') { //console.log(`Stream ${i} is an audio stream`); // Keep track of audio stream relative numbers try { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { audioIdx++; } } catch (err) {} try { // Try to identify commentary tracks if ( (file.ffProbeData.streams[i].tags.title != undefined && file.ffProbeData.streams[i].tags.title.toLowerCase().includes("commentary") || file.ffProbeData.streams[i].disposition.comment == 1) && inputs.remove_commentary == true ) { console.log(`Stream ${i} (audio stream ${audioIdx}) is probably a commentary track. Selected to remove`) response.infoLog += `Stream ${i} (audio stream ${audioIdx}) is probably a commentary track. Selected to remove.\n` } else if ( (file.ffProbeData.streams[i].tags.title != undefined && file.ffProbeData.streams[i].tags.title.toLowerCase().includes("commentary") || file.ffProbeData.streams[i].disposition.comment == 1) && inputs.remove_commentary == false ) { console.log(`Stream ${i} (audio stream ${audioIdx}) is probably a commentary track. Selected to keep.`) response.infoLog += `Stream ${i} (audio stream ${audioIdx}) is probably a commentary track. Selected to keep.\n` ffmpegAudioOtherTracks += ` -map 0:a:${audioIdx}` } else if ( file.ffProbeData.streams[i].codec_name.toLowerCase() === 'ac3' && file.ffProbeData.streams[i].channels == 6 ) { console.log(`Stream ${i} (audio stream ${audioIdx}) is an AC3 5.1 track`) response.infoLog += `Stream ${i} (audio stream ${audioIdx}) is an AC3 5.1 track.\n` ac3Count++ //console.log(`ac3Count = ${ac3Count}`) } //console.log(`codec_type = ${file.ffProbeData.streams[i].codec_name.toLowerCase()}`) //console.log(`channels = ${file.ffProbeData.streams[i].channels == 6}`) //console.log(`ac3Count = ${ac3Count}`) } catch (error) { } } } if (ac3Count == 0) { //LOGIC NEEDS ADDING FOR IF AN AC3 TRACK HAS BEEN CREATED WITH FEWER THAN 6 CHANNELS console.log(`Neither a TrueHD track nor a desireable AC3 5.1 track exist. Selecting the first audio track and converting it to AC3.`) response.infoLog += 'Neither a TrueHD track nor a desireable AC3 5.1 track exist. Selecting the first audio track and converting it to AC3.\n' if (file.ffProbeData.streams[1].codec_type.toLowerCase() === 'audio') { let MMCodec = file.ffProbeData.streams[1].codec_name.toUpperCase(); let MMChannelLayout = file.ffProbeData.streams[1].channel_layout.replace('(side)', ''); console.log(`Assuming stream 2 will be the best audio track available.`) console.log(`Stream 2 is ${file.ffProbeData.streams[1].codec_name} with ${file.ffProbeData.streams[1].channels} channels.`) response.infoLog += `Stream 2 is ${file.ffProbeData.streams[1].codec_name} with ${file.ffProbeData.streams[1].channels} channels.\n` if ( file.ffProbeData.streams[1].channels > 6 ) { ffmpegAudioFirstTrack = ` -map -0:a -map 0:a:0 -c:a:0 ac3 -b:a:0 640k -ac:a:0 6 -metadata:s:a:0 "title=AC3 - 5.1 - MM" -disposition:a:0 default` } else { ffmpegAudioFirstTrack = ` -map -0:a -map 0:a:0 -c:a:0 ac3 -b:a:0 640k -ac:a:0 ${file.ffProbeData.streams[1].channels} -metadata:s:a:0 "title=AC3 - ${MMChannelLayout} - MM" -disposition:a:0 default` } } else { console.log(`Stream 2 isn't an audio track. Taking no action.`) response.infoLog += `☒ Stream 2 isn't an audio track. Taking no action.\n` }; } if (ac3Count == 1) { audioIdx = -1; console.log(`Only 1 AC3 5.1 track present, checking to see if it's correctly labelled`) response.infoLog += `Only 1 AC3 5.1 track present, checking to see if it's correctly labelled.\n` for (let i = 0; i < file.ffProbeData.streams.length; i ++) { // Work with audio streams only if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio') { //console.log(`Stream ${i} is an audio stream`); let MMCodec = file.ffProbeData.streams[i].codec_name.toUpperCase(); let MMChannelLayout = file.ffProbeData.streams[i].channel_layout.replace('(side)', ''); // Keep track of audio stream relative numbers try { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { audioIdx++; //console.log(`audioIdx = ${audioIdx}`) } } catch (err) {} // Look only for AC3 5.1 streams (should only find 1) if ( file.ffProbeData.streams[i].codec_name.toLowerCase() == "ac3" && file.ffProbeData.streams[i].channels == 6 ) { // Checking if AC3 5.1 already default and labelled - sign the file has probably already been processed if ( file.ffProbeData.streams[i].disposition.default = 1 && file.ffProbeData.streams[i].tags.title === `${MMCodec} - ${MMChannelLayout} - MM` ) { console.log('Track is labelled correctly. No further work required.') response.infoLog += '☑ Track is labelled correctly. No further work required.\n' } // Checking if AC3 5.1 exists but not labelled correctly else if ( file.ffProbeData.streams[i].disposition.default != 1 || file.ffProbeData.streams[i].tags.title !== `${MMCodec} - ${MMChannelLayout} - MM` ) { console.log(`Stream ${i} (audio stream ${audioIdx}) is AC3 5.1, but not labelled correctly. Correcting.`) response.infoLog += `Stream ${i} (audio stream ${audioIdx}) is AC3 5.1, but not labelled correctly. Correcting.\n` ffmpegAudioFirstTrack = ` -map -0:a -map 0:a:${audioIdx} -metadata:s:a:0 "title=${MMCodec} - ${MMChannelLayout} - MM" -disposition:a:0 default` } } } } } if (ac3Count > 1) { console.log(`There is more than 1 AC3 5.1 track. This is probably due to it being a foreign-language film with an additional English dub.`) console.log(`Checking for signs that the first audio track has been processed`) console.log(`Assuming stream 2 is the first audio track`) response.infoLog += `There is more than 1 AC3 5.1 track. This is probably due to it being a foreign-language film with an additional English dub.\n Checking for signs that the first audio track has been processed.\n Assuming stream 2 is the first audio track.\n` if ( file.ffProbeData.streams[1].codec_type.toLowerCase() === 'audio' && file.ffProbeData.streams[1].codec_name.toLowerCase() === 'ac3' && file.ffProbeData.streams[1].tags.title != undefined && file.ffProbeData.streams[1].tags.title.includes("MM") ) { console.log(`First track is labelled by this plugin, and set as default - safe to assume this file has been processed. Taking no action.`) response.infoLog += `☑ First track is labelled by this plugin, and set as default - safe to assume this file has been processed. Taking no action.\n` } else { console.log(`First audio stream is AC3 5.1, but not labelled as expected. Resolving.`) response.infoLog += `First audio stream is AC3 5.1, but not labelled as expected. Resolving.\n` let MMCodec = file.ffProbeData.streams[1].codec_name.toUpperCase(); let MMChannelLayout = file.ffProbeData.streams[1].channel_layout.replace('(side)', ''); ffmpegAudioFirstTrack = ` -map -0:a -map 0:a:0 -metadata:s:a:0 "title=${MMCodec} - ${MMChannelLayout} - MM" -disposition:a:0 default` console.log(`Copying over other AC3 5.1 tracks`) audioIdx = 0 //Set to 0 since already accounted for track 1 for (let i = 2; i < file.ffProbeData.streams.length; i ++) { // Work with audio streams only if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio') { //console.log(`Stream ${i} is an audio stream`); // Keep track of audio stream relative numbers try { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { audioIdx++; //console.log(`audioIdx = ${audioIdx}`) } } catch (err) {} ffmpegAudioOtherTracks += ` -map 0:a:${audioIdxTruehd}` }; }; }; }; }; }; }; const processSubs = (file, librarySettings, inputs, otherArguments) => { if (inputs.process_subs == false) { response.infoLog += `Processing subs set to skip. Copying all present tracks over.\n` } else { // Function variables let subIdx = -1; console.log(` === Running processSubs function === `) // Go through all subtitles, removing non-English/German subs and commentary subs for (let i = 0; i < file.ffProbeData.streams.length; i ++) { // Work with subtitle streams only if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'subtitle') { // Keep track of subtitle stream relative numbers try { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") { subIdx++; } } catch (err) {} // Remove any subtitles with no language set if (file.ffProbeData.streams[i].tags.language == undefined) { console.log(`Stream ${i} (subtitle stream ${subIdx}) has no language. Removing.`) response.infoLog += `Stream ${i} (subtitle stream ${subIdx}) has no language. Removing. \n` ffmpegSubs += ` -map -0:s:${subIdx}` } // Remove any subtitles not in English or German else if ( file.ffProbeData.streams[i].tags.language.toLowerCase() !== "eng" && file.ffProbeData.streams[i].tags.language.toLowerCase() !== "ger" ) { console.log(`Stream ${i} (subtitle stream ${subIdx}) is not in a desired language. Removing.`) response.infoLog += `Stream ${i} (subtitle stream ${subIdx}) is not in a desired language. Removing. \n` ffmpegSubs += ` -map -0:s:${subIdx}` } // Remove any subtitles that are for commentary else if ( (file.ffProbeData.streams[i].tags.title != undefined && file.ffProbeData.streams[i].tags.title.toLowerCase().includes("commentary") || file.ffProbeData.streams[i].disposition.comment == 1) && inputs.remove_commentary == true ) { console.log(`Stream ${i} (subtitle stream ${subIdx}) is for a commentary track. Selected to remove.`) response.infoLog += `Stream ${i} (subtitle stream ${subIdx}) is for a commentary track. Selected to remove. \n` ffmpegSubs += ` -map -0:s:${subIdx}` } else if ( (file.ffProbeData.streams[i].tags.title != undefined && file.ffProbeData.streams[i].tags.title.toLowerCase().includes("commentary") || file.ffProbeData.streams[i].disposition.comment == 1) && inputs.remove_commentary == false ) { console.log(`Stream ${i} (subtitle stream ${subIdx}) is for a commentary track. Selected to keep.`) response.infoLog += `Stream ${i} (subtitle stream ${subIdx}) is for a commentary track. Selected to keep. \n` } else { console.log(`Stream ${i} (subtitle stream ${subIdx}) is wanted. Keeping.`) response.infoLog += `Stream ${i} (subtitle stream ${subIdx}) is wanted. Keeping. \n` } }; }; }; }; const processVideo = (file, librarySettings, inputs, otherArguments) => { if (inputs.process_video == false) { response.infoLog += `Processing video set to skip. Copying all present tracks over.\n` } else { console.log(` === Running processVideo function === `) // Check if video track is already HEVC if (file.ffProbeData.streams[0].codec_name.toLowerCase() === 'hevc') { console.log(`File is already HEVC. No action needed.`) response.infoLog += `☑ File is already HEVC. No action needed.\n` } else { console.log('File needs transcoding to HEVC. Converting now.') response.infoLog += `☒ File needs transcoding to HEVC.\n` ffmpegVideo = ` -c:v libx265 -pix_fmt yuv420p10le -preset slow -x265-params crf=${inputs.crf}:bframes=8:rc-lookahead=32:b-intra=1:aq-mode=3` } }; }; // Start running functions processAudio(file, librarySettings, inputs, otherArguments); processSubs(file, librarySettings, inputs, otherArguments); processVideo(file, librarySettings, inputs, otherArguments); if (ffmpegAudioFirstTrack.length > 0 || ffmpegAudioOtherTracks.length > 0 || ffmpegSubs.length > 0 || ffmpegVideo.length > 0) { response.infoLog += '☒ Changes are required! \n'; response.FFmpegMode = true; response.container = `.${file.container}`; response.preset = `,-c copy -map 0:v?${ffmpegVideo} -map 0:a?${ffmpegAudioFirstTrack}${ffmpegAudioOtherTracks} -map 0:s?${ffmpegSubs} -map 0:d? -max_muxing_queue_size 9999`; console.log(response.preset) response.processFile = true; return response; } if (ffmpegAudioFirstTrack.length == 0 && ffmpegAudioOtherTracks.length == 0 && ffmpegSubs.length == 0 && ffmpegVideo.length == 0) { response.infoLog += '☑ No changes are required \n'; response.processFile = false; return response; } }; module.exports.details = details; module.exports.plugin = plugin;