tdarr-plugins/Tdarr_Plugin_MM1_MrMeeb_Full_Stack.js

856 lines
36 KiB
JavaScript

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 <io>, followed by the output argument.
// Examples
// HandBrake
// '-Z "Very Fast 1080p30"'
// FFmpeg
// '-sn <io> -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;