Upload files to ''

This commit is contained in:
MrMeeb 2023-06-10 14:24:15 +00:00
parent cdd9983810
commit 543dd99587

View File

@ -0,0 +1,559 @@
const details = () => ({
id: 'Tdarr_Plugin_MM1_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: [],
});
// 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) => {
// Function variables
let audioIdx = -1;
let audioIdxTruehd = -1;
let trueHD = -1;
let trueHDi = -1;
let ac3Count = 0;
console.log(` === Running processAudio function === `)
// Go through all streams, hunting for TrueHD
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
) {
console.log(`Stream ${i} (audio stream ${audioIdxTruehd}) is probably a commentary track. Removing.`)
response.infoLog += `Stream ${i} (audio stream ${audioIdxTruehd}) is probably a commentary track. Removing.\n`
}
// 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:${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:${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:${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`
}
}
}
} catch (error) {
console.log(error)
}
}
};
// Logic for if no TrueHD track present
if (trueHD < 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
) {
console.log(`Stream ${i} (audio stream ${audioIdx}) is probably a commentary track. Leaving it out`)
response.infoLog += `Stream ${i} (audio stream ${audioIdx}) is probably a commentary track. Removing.\n`
}
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 or a desireable AC3 5.1 track exist. Selecting the first audio track and converting it to AC3.`)
response.infoLog += 'Neither a TrueHD track or 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: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: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:${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: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) => {
// 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') {
//console.log(`Stream ${i} is a subtitle stream`);
// Keep track of subtitle stream relative numbers
try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") {
subIdx++;
}
} catch (err) {}
//console.log(`language = ${file.ffProbeData.streams[i].tags.language.toLowerCase()}`)
// Remove any subtitles not in English or German
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
) {
console.log(`Stream ${i} (subtitle stream ${subIdx}) is for a commentary track. Removing.`)
response.infoLog += `Stream ${i} (subtitle stream ${subIdx}) is for a commentary track. Removing. \n`
ffmpegSubs += ` -map -0:s:${subIdx}`
}
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) => {
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 hevc_nvenc -b:v 0 -preset p7 -cq 1 -rc-lookahead 32 -bf 0`
}
};
// 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}${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;