make-only-subtitle-default
HaveAGitGat 6 years ago
parent d28272f6d4
commit 9c8ac98728

@ -0,0 +1,4 @@
node_modules/
.github/
# npx prettier@2.0.5 . --write

@ -1,178 +1,190 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_MC93_Migz1FFMPEG", id: "Tdarr_Plugin_MC93_Migz1FFMPEG",
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "Migz-Transcode Using Nvidia GPU & FFMPEG", Name: "Migz-Transcode Using Nvidia GPU & FFMPEG",
Type: "Video", Type: "Video",
Operation: "Transcode", Operation: "Transcode",
Description: `Files not in H265 will be transcoded into H265 using Nvidia GPU with ffmpeg, settings are dependant on file bitrate, working by the logic that H265 can support the same ammount of data at half the bitrate of H264. NVDEC & NVENC compatable GPU required. \n\n`, Description: `Files not in H265 will be transcoded into H265 using Nvidia GPU with ffmpeg, settings are dependant on file bitrate, working by the logic that H265 can support the same ammount of data at half the bitrate of H264. NVDEC & NVENC compatable GPU required. \n\n`,
Version: "2.4", Version: "2.4",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz1FFMPEG.js", Link:
Tags: 'pre-processing,ffmpeg,video only,nvenc h265,configurable', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz1FFMPEG.js",
Inputs: [{ Tags: "pre-processing,ffmpeg,video only,nvenc h265,configurable",
name: 'container', Inputs: [
tooltip: `Specify output container of file, ensure that all stream types you may have are supported by your chosen container. mkv is recommended. {
name: "container",
tooltip: `Specify output container of file, ensure that all stream types you may have are supported by your chosen container. mkv is recommended.
\\nExample:\\n \\nExample:\\n
mkv mkv
\\nExample:\\n \\nExample:\\n
mp4` mp4`,
},
{
}, name: "bitrate_cutoff",
{ tooltip: `Specify bitrate cutoff, files with a current bitrate lower then this will not be transcoded. Rate is in kbps. Leave empty to disable.
name: 'bitrate_cutoff',
tooltip: `Specify bitrate cutoff, files with a current bitrate lower then this will not be transcoded. Rate is in kbps. Leave empty to disable.
\\nExample:\\n \\nExample:\\n
6000 6000
\\nExample:\\n \\nExample:\\n
4000` 4000`,
}, },
{ {
name: 'enable_10bit', name: "enable_10bit",
tooltip: `Specify if output file should be 10bit. Default is false. tooltip: `Specify if output file should be 10bit. Default is false.
\\nExample:\\n \\nExample:\\n
true true
\\nExample:\\n \\nExample:\\n
false` false`,
}, },
] ],
} };
} }
function plugin(file, librarySettings, inputs) { function plugin(file, librarySettings, inputs) {
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: true, reQueueAfter: true,
infoLog: '' infoLog: "",
};
// Check if inputs.container has been configured. If it hasn't then exit plugin.
if (inputs.container == "") {
response.infoLog +=
"☒Container has not been configured within plugin settings, please configure required options. Skipping this plugin. \n";
response.processFile = false;
return response;
} else {
response.container = "." + inputs.container;
}
// Check if file is MKV, if so then add extra argument to drop data. MKV does not support data streams.
if (inputs.container == "mkv") {
extraArguments += "-map -0:d ";
}
// Check if file is a video. If it isn't then exit plugin.
if (file.fileMedium !== "video") {
response.processFile = false;
response.infoLog += "☒File is not a video. \n";
return response;
}
// Check if duration info is filled, if so times it by 0.0166667 to get time in minutes. If not filled then get duration of stream 0 and do the same.
if (typeof file.meta.Duration != "undefined") {
var duration = file.meta.Duration * 0.0166667;
} else {
var duration = file.ffProbeData.streams[0].duration * 0.0166667;
}
// Set up required variables.
var videoIdx = 0;
var extraArguments = "";
var bitrateSettings = "";
// Work out currentBitrate using "Bitrate = file size / (number of minutes * .0075)" - Used from here https://blog.frame.io/2017/03/06/calculate-video-bitrates/
var currentBitrate = ~~(file.file_size / (duration * 0.0075));
// Use the same calculation used for currentBitrate but divide it in half to get targetBitrate. Logic of h265 can be half the bitrate as h264 without losing quality.
var targetBitrate = ~~(file.file_size / (duration * 0.0075) / 2);
// Allow some leeway under and over the targetBitrate.
var minimumBitrate = ~~(targetBitrate * 0.7);
var maximumBitrate = ~~(targetBitrate * 1.3);
// If targetBitrate comes out as 0 then something has gone wrong and bitrates could not be calculcated. Cancel plugin completely.
if (targetBitrate == "0") {
response.processFile = false;
response.infoLog +=
"☒Target bitrate could not be calculated. Skipping this plugin. \n";
return response;
}
// Check if inputs.bitrate cutoff has something entered (Entered means user actually wants something to happen, empty would disable this).
if (inputs.bitrate_cutoff != "") {
// Checks if currentBitrate is below inputs.bitrate_cutoff, if so then cancel plugin without touching original files.
if (currentBitrate <= inputs.bitrate_cutoff) {
response.processFile = false;
response.infoLog += `☑Current bitrate is below configured bitrate cutoff of ${inputs.bitrate_cutoff}. Nothing to do, cancelling plugin. \n`;
return response;
} }
}
// Check if inputs.container has been configured. If it hasn't then exit plugin.
if (inputs.container == "") { // Check if 10bit variable is true.
response.infoLog += "☒Container has not been configured within plugin settings, please configure required options. Skipping this plugin. \n" if (inputs.enable_10bit == "true") {
response.processFile = false // If set to true then add 10bit argument
return response extraArguments += `-pix_fmt p010le `;
} else { }
response.container = '.' + inputs.container
} // Go through each stream in the file.
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
// Check if file is MKV, if so then add extra argument to drop data. MKV does not support data streams. // Check if stream is a video.
if (inputs.container == "mkv") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
extraArguments += "-map -0:d " // Check if codec of stream is mjpeg, if so then remove this "video" stream. mjpeg are usually imbedded pictures that can cause havoc with plugins.
if (file.ffProbeData.streams[i].codec_name == "mjpeg") {
extraArguments += `-map -v:${videoIdx} `;
}
// Check if codec of stream is hevc AND check if file.container matches inputs.container. If so nothing for plugin to do.
if (
file.ffProbeData.streams[i].codec_name == "hevc" &&
file.container == inputs.container
) {
response.processFile = false;
response.infoLog += `☑File is already hevc & in ${inputs.container}. \n`;
return response;
}
// Check if codec of stream is hevc AND check if file.container does NOT match inputs.container. If so remux file.
if (
file.ffProbeData.streams[i].codec_name == "hevc" &&
file.container != "${inputs.container}"
) {
response.infoLog += `☒File is hevc but is not in ${inputs.container} container. Remuxing. \n`;
response.preset = `, -map 0 -c copy ${extraArguments}`;
response.processFile = true;
return response;
}
// Increment videoIdx.
videoIdx++;
} }
}
// Check if file is a video. If it isn't then exit plugin.
if (file.fileMedium !== "video") { // Set bitrateSettings variable using bitrate information calulcated earlier.
response.processFile = false bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k -maxrate ${maximumBitrate}k -bufsize ${currentBitrate}k`;
response.infoLog += "☒File is not a video. \n" // Print to infoLog information around file & bitrate settings.
return response response.infoLog += `Container for output selected as ${
} inputs.container
}. \n Current bitrate = ${~~(
// Check if duration info is filled, if so times it by 0.0166667 to get time in minutes. If not filled then get duration of stream 0 and do the same. file.file_size /
if (typeof file.meta.Duration != 'undefined') { (duration * 0.0075)
var duration = (file.meta.Duration * 0.0166667) )} \n Bitrate settings: \nTarget = ${targetBitrate} \nMinimum = ${minimumBitrate} \nMaximum = ${maximumBitrate} \n`;
} else {
var duration = (file.ffProbeData.streams[0].duration * 0.0166667) // Codec will be checked so it can be transcoded correctly
} if (file.video_codec_name == "h263") {
response.preset = `-c:v h263_cuvid`;
// Set up required variables. } else if (file.video_codec_name == "h264") {
var videoIdx = 0 if (file.ffProbeData.streams[0].profile != "High 10") {
var extraArguments = "" //if a h264 coded video is not HDR
var bitrateSettings = "" response.preset = `-c:v h264_cuvid`;
// Work out currentBitrate using "Bitrate = file size / (number of minutes * .0075)" - Used from here https://blog.frame.io/2017/03/06/calculate-video-bitrates/
var currentBitrate = ~~(file.file_size / (duration * 0.0075))
// Use the same calculation used for currentBitrate but divide it in half to get targetBitrate. Logic of h265 can be half the bitrate as h264 without losing quality.
var targetBitrate = ~~((file.file_size / (duration * 0.0075)) / 2)
// Allow some leeway under and over the targetBitrate.
var minimumBitrate = ~~(targetBitrate * 0.7)
var maximumBitrate = ~~(targetBitrate * 1.3)
// If targetBitrate comes out as 0 then something has gone wrong and bitrates could not be calculcated. Cancel plugin completely.
if (targetBitrate == "0") {
response.processFile = false
response.infoLog += "☒Target bitrate could not be calculated. Skipping this plugin. \n"
return response
} }
} else if (file.video_codec_name == "mjpeg") {
// Check if inputs.bitrate cutoff has something entered (Entered means user actually wants something to happen, empty would disable this). response.preset = `c:v mjpeg_cuvid`;
if (inputs.bitrate_cutoff != "") { } else if (file.video_codec_name == "mpeg1") {
// Checks if currentBitrate is below inputs.bitrate_cutoff, if so then cancel plugin without touching original files. response.preset = `-c:v mpeg1_cuvid`;
if (currentBitrate <= inputs.bitrate_cutoff) { } else if (file.video_codec_name == "mpeg2") {
response.processFile = false response.preset = `-c:v mpeg2_cuvid`;
response.infoLog += `☑Current bitrate is below configured bitrate cutoff of ${inputs.bitrate_cutoff}. Nothing to do, cancelling plugin. \n` } else if (file.video_codec_name == "vc1") {
return response response.preset = `-c:v vc1_cuvid`;
} } else if (file.video_codec_name == "vp8") {
} response.preset = `-c:v vp8_cuvid`;
} else if (file.video_codec_name == "vp9") {
// Check if 10bit variable is true. response.preset = `-c:v vp9_cuvid`;
if (inputs.enable_10bit == "true") { }
// If set to true then add 10bit argument
extraArguments += `-pix_fmt p010le ` response.preset += `,-map 0 -c:v hevc_nvenc -rc:v vbr_hq -cq:v 19 ${bitrateSettings} -spatial_aq:v 1 -rc-lookahead:v 32 -c:a copy -c:s copy -max_muxing_queue_size 4096 ${extraArguments}`;
} response.processFile = true;
response.infoLog += `☒File is not hevc. Transcoding. \n`;
// Go through each stream in the file. return response;
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
// Check if stream is a video.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
// Check if codec of stream is mjpeg, if so then remove this "video" stream. mjpeg are usually imbedded pictures that can cause havoc with plugins.
if (file.ffProbeData.streams[i].codec_name == 'mjpeg') {
extraArguments += `-map -v:${videoIdx} `
}
// Check if codec of stream is hevc AND check if file.container matches inputs.container. If so nothing for plugin to do.
if (file.ffProbeData.streams[i].codec_name == 'hevc' && file.container == inputs.container) {
response.processFile = false
response.infoLog += `☑File is already hevc & in ${inputs.container}. \n`
return response
}
// Check if codec of stream is hevc AND check if file.container does NOT match inputs.container. If so remux file.
if (file.ffProbeData.streams[i].codec_name == 'hevc' && file.container != '${inputs.container}') {
response.infoLog += `☒File is hevc but is not in ${inputs.container} container. Remuxing. \n`
response.preset = `, -map 0 -c copy ${extraArguments}`
response.processFile = true;
return response
}
// Increment videoIdx.
videoIdx++
}
}
// Set bitrateSettings variable using bitrate information calulcated earlier.
bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k -maxrate ${maximumBitrate}k -bufsize ${currentBitrate}k`
// Print to infoLog information around file & bitrate settings.
response.infoLog += `Container for output selected as ${inputs.container}. \n Current bitrate = ${~~(file.file_size / (duration * 0.0075))} \n Bitrate settings: \nTarget = ${targetBitrate} \nMinimum = ${minimumBitrate} \nMaximum = ${maximumBitrate} \n`
// Codec will be checked so it can be transcoded correctly
if (file.video_codec_name == 'h263') {
response.preset = `-c:v h263_cuvid`
} else if (file.video_codec_name == 'h264') {
if (file.ffProbeData.streams[0].profile != 'High 10') { //if a h264 coded video is not HDR
response.preset = `-c:v h264_cuvid`
}
} else if (file.video_codec_name == 'mjpeg') {
response.preset = `c:v mjpeg_cuvid`
} else if (file.video_codec_name == 'mpeg1') {
response.preset = `-c:v mpeg1_cuvid`
} else if (file.video_codec_name == 'mpeg2') {
response.preset = `-c:v mpeg2_cuvid`
} else if (file.video_codec_name == 'vc1') {
response.preset = `-c:v vc1_cuvid`
} else if (file.video_codec_name == 'vp8') {
response.preset = `-c:v vp8_cuvid`
} else if (file.video_codec_name == 'vp9') {
response.preset = `-c:v vp9_cuvid`
}
response.preset += `,-map 0 -c:v hevc_nvenc -rc:v vbr_hq -cq:v 19 ${bitrateSettings} -spatial_aq:v 1 -rc-lookahead:v 32 -c:a copy -c:s copy -max_muxing_queue_size 4096 ${extraArguments}`
response.processFile = true
response.infoLog += `☒File is not hevc. Transcoding. \n`
return response
} }
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -1,157 +1,168 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_MC93_Migz1FFMPEG_CPU", id: "Tdarr_Plugin_MC93_Migz1FFMPEG_CPU",
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "Migz-Transcode Using CPU & FFMPEG", Name: "Migz-Transcode Using CPU & FFMPEG",
Type: "Video", Type: "Video",
Operation: "Transcode", Operation: "Transcode",
Description: `Files not in H265 will be transcoded into H265 using CPU with ffmpeg, settings are dependant on file bitrate, working by the logic that H265 can support the same ammount of data at half the bitrate of H264. \n\n`, Description: `Files not in H265 will be transcoded into H265 using CPU with ffmpeg, settings are dependant on file bitrate, working by the logic that H265 can support the same ammount of data at half the bitrate of H264. \n\n`,
Version: "1.3", Version: "1.3",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz1FFMPEG_CPU.js", Link:
Tags: 'pre-processing,ffmpeg,video only,configurable,h265', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz1FFMPEG_CPU.js",
Inputs: [{ Tags: "pre-processing,ffmpeg,video only,configurable,h265",
name: 'container', Inputs: [
tooltip: `Specify output container of file, ensure that all stream types you may have are supported by your chosen container. mkv is recommended. {
name: "container",
tooltip: `Specify output container of file, ensure that all stream types you may have are supported by your chosen container. mkv is recommended.
\\nExample:\\n \\nExample:\\n
mkv mkv
\\nExample:\\n \\nExample:\\n
mp4` mp4`,
},
{
}, name: "bitrate_cutoff",
{ tooltip: `Specify bitrate cutoff, files with a current bitrate lower then this will not be transcoded. Rate is in kbps. Leave empty to disable.
name: 'bitrate_cutoff',
tooltip: `Specify bitrate cutoff, files with a current bitrate lower then this will not be transcoded. Rate is in kbps. Leave empty to disable.
\\nExample:\\n \\nExample:\\n
6000 6000
\\nExample:\\n \\nExample:\\n
4000` 4000`,
}, },
{ {
name: 'enable_10bit', name: "enable_10bit",
tooltip: `Specify if output file should be 10bit. Default is false. tooltip: `Specify if output file should be 10bit. Default is false.
\\nExample:\\n \\nExample:\\n
true true
\\nExample:\\n \\nExample:\\n
false` false`,
}, },
] ],
} };
} }
function plugin(file, librarySettings, inputs) { function plugin(file, librarySettings, inputs) {
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: true, reQueueAfter: true,
infoLog: '' infoLog: "",
} };
// Check if inputs.container has been configured. If it hasn't then exit plugin. // Check if inputs.container has been configured. If it hasn't then exit plugin.
if (inputs.container == "") { if (inputs.container == "") {
response.infoLog += "☒Container has not been configured within plugin settings, please configure required options. Skipping this plugin. \n" response.infoLog +=
response.processFile = false "☒Container has not been configured within plugin settings, please configure required options. Skipping this plugin. \n";
return response response.processFile = false;
} else { return response;
response.container = '.' + inputs.container } else {
} response.container = "." + inputs.container;
}
// Check if file is MKV, if so then add extra argument to drop data. MKV does not support data streams.
if (inputs.container == "mkv") { // Check if file is MKV, if so then add extra argument to drop data. MKV does not support data streams.
extraArguments += "-map -0:d " if (inputs.container == "mkv") {
} extraArguments += "-map -0:d ";
}
// Check if file is a video. If it isn't then exit plugin.
if (file.fileMedium !== "video") { // Check if file is a video. If it isn't then exit plugin.
response.processFile = false if (file.fileMedium !== "video") {
response.infoLog += "☒File is not a video. \n" response.processFile = false;
return response response.infoLog += "☒File is not a video. \n";
return response;
}
// Check if duration info is filled, if so times it by 0.0166667 to get time in minutes. If not filled then get duration of stream 0 and do the same.
if (typeof file.meta.Duration != "undefined") {
var duration = file.meta.Duration * 0.0166667;
} else {
var duration = file.ffProbeData.streams[0].duration * 0.0166667;
}
// Set up required variables.
var videoIdx = -1;
var extraArguments = "";
var bitrateSettings = "";
// Work out currentBitrate using "Bitrate = file size / (number of minutes * .0075)" - Used from here https://blog.frame.io/2017/03/06/calculate-video-bitrates/
var currentBitrate = ~~(file.file_size / (duration * 0.0075));
// Use the same calculation used for currentBitrate but divide it in half to get targetBitrate. Logic of h265 can be half the bitrate as h264 without losing quality.
var targetBitrate = ~~(file.file_size / (duration * 0.0075) / 2);
// Allow some leeway under and over the targetBitrate.
var minimumBitrate = ~~(targetBitrate * 0.7);
var maximumBitrate = ~~(targetBitrate * 1.3);
// If targetBitrate comes out as 0 then something has gone wrong and bitrates could not be calculcated. Cancel plugin completely.
if (targetBitrate == "0") {
response.processFile = false;
response.infoLog +=
"☒Target bitrate could not be calculated. Skipping this plugin. \n";
return response;
}
// Check if inputs.bitrate cutoff has something entered (Entered means user actually wants something to happen, empty would disable this).
if (inputs.bitrate_cutoff != "") {
// Checks if currentBitrate is below inputs.bitrate_cutoff, if so then cancel plugin without touching original files.
if (currentBitrate <= inputs.bitrate_cutoff) {
response.processFile = false;
response.infoLog += `☑Current bitrate is below configured bitrate cutoff of ${inputs.bitrate_cutoff}. Nothing to do, cancelling plugin. \n`;
return response;
} }
}
// Check if duration info is filled, if so times it by 0.0166667 to get time in minutes. If not filled then get duration of stream 0 and do the same.
if (typeof file.meta.Duration != 'undefined') { // Check if 10bit variable is true.
var duration = (file.meta.Duration * 0.0166667) if (inputs.enable_10bit == "true") {
} else { // If set to true then add 10bit argument
var duration = (file.ffProbeData.streams[0].duration * 0.0166667) extraArguments += `-pix_fmt p010le `;
}
// Go through each stream in the file.
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
// Check if stream is a video.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
// Check if codec of stream is mjpeg, if so then remove this "video" stream. mjpeg are usually imbedded pictures that can cause havoc with plugins.
if (file.ffProbeData.streams[i].codec_name == "mjpeg") {
extraArguments += `-map -v:${videoIdx} `;
}
// Check if codec of stream is hevc AND check if file.container matches inputs.container. If so nothing for plugin to do.
if (
file.ffProbeData.streams[i].codec_name == "hevc" &&
file.container == inputs.container
) {
response.processFile = false;
response.infoLog += `☑File is already hevc & in ${inputs.container}. \n`;
return response;
}
// Check if codec of stream is hevc AND check if file.container does NOT match inputs.container. If so remux file.
if (
file.ffProbeData.streams[i].codec_name == "hevc" &&
file.container != "${inputs.container}"
) {
response.infoLog += `☒File is hevc but is not in ${inputs.container} container. Remuxing. \n`;
response.preset = `, -map 0 -c copy ${extraArguments}`;
response.processFile = true;
return response;
}
// Increment videoIdx.
videoIdx++;
} }
}
// Set up required variables.
var videoIdx = -1 // Set bitrateSettings variable using bitrate information calulcated earlier.
var extraArguments = "" bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k -maxrate ${maximumBitrate}k -bufsize ${currentBitrate}k`;
var bitrateSettings = "" // Print to infoLog information around file & bitrate settings.
// Work out currentBitrate using "Bitrate = file size / (number of minutes * .0075)" - Used from here https://blog.frame.io/2017/03/06/calculate-video-bitrates/ response.infoLog += `Container for output selected as ${
var currentBitrate = ~~(file.file_size / (duration * 0.0075)) inputs.container
// Use the same calculation used for currentBitrate but divide it in half to get targetBitrate. Logic of h265 can be half the bitrate as h264 without losing quality. }. \n Current bitrate = ${~~(
var targetBitrate = ~~((file.file_size / (duration * 0.0075)) / 2) file.file_size /
// Allow some leeway under and over the targetBitrate. (duration * 0.0075)
var minimumBitrate = ~~(targetBitrate * 0.7) )} \n Bitrate settings: \nTarget = ${targetBitrate} \nMinimum = ${minimumBitrate} \nMaximum = ${maximumBitrate} \n`;
var maximumBitrate = ~~(targetBitrate * 1.3)
response.preset += `,-map 0 -c:v libx265 ${bitrateSettings} -c:a copy -c:s copy -max_muxing_queue_size 4096 ${extraArguments}`;
// If targetBitrate comes out as 0 then something has gone wrong and bitrates could not be calculcated. Cancel plugin completely. response.processFile = true;
if (targetBitrate == "0") { response.infoLog += `☒File is not hevc. Transcoding. \n`;
response.processFile = false return response;
response.infoLog += "☒Target bitrate could not be calculated. Skipping this plugin. \n"
return response
}
// Check if inputs.bitrate cutoff has something entered (Entered means user actually wants something to happen, empty would disable this).
if (inputs.bitrate_cutoff != "") {
// Checks if currentBitrate is below inputs.bitrate_cutoff, if so then cancel plugin without touching original files.
if (currentBitrate <= inputs.bitrate_cutoff) {
response.processFile = false
response.infoLog += `☑Current bitrate is below configured bitrate cutoff of ${inputs.bitrate_cutoff}. Nothing to do, cancelling plugin. \n`
return response
}
}
// Check if 10bit variable is true.
if (inputs.enable_10bit == "true") {
// If set to true then add 10bit argument
extraArguments += `-pix_fmt p010le `
}
// Go through each stream in the file.
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
// Check if stream is a video.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
// Check if codec of stream is mjpeg, if so then remove this "video" stream. mjpeg are usually imbedded pictures that can cause havoc with plugins.
if (file.ffProbeData.streams[i].codec_name == 'mjpeg') {
extraArguments += `-map -v:${videoIdx} `
}
// Check if codec of stream is hevc AND check if file.container matches inputs.container. If so nothing for plugin to do.
if (file.ffProbeData.streams[i].codec_name == 'hevc' && file.container == inputs.container) {
response.processFile = false
response.infoLog += `☑File is already hevc & in ${inputs.container}. \n`
return response
}
// Check if codec of stream is hevc AND check if file.container does NOT match inputs.container. If so remux file.
if (file.ffProbeData.streams[i].codec_name == 'hevc' && file.container != '${inputs.container}') {
response.infoLog += `☒File is hevc but is not in ${inputs.container} container. Remuxing. \n`
response.preset = `, -map 0 -c copy ${extraArguments}`
response.processFile = true;
return response
}
// Increment videoIdx.
videoIdx++
}
}
// Set bitrateSettings variable using bitrate information calulcated earlier.
bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k -maxrate ${maximumBitrate}k -bufsize ${currentBitrate}k`
// Print to infoLog information around file & bitrate settings.
response.infoLog += `Container for output selected as ${inputs.container}. \n Current bitrate = ${~~(file.file_size / (duration * 0.0075))} \n Bitrate settings: \nTarget = ${targetBitrate} \nMinimum = ${minimumBitrate} \nMaximum = ${maximumBitrate} \n`
response.preset += `,-map 0 -c:v libx265 ${bitrateSettings} -c:a copy -c:s copy -max_muxing_queue_size 4096 ${extraArguments}`
response.processFile = true
response.infoLog += `☒File is not hevc. Transcoding. \n`
return response
} }
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -1,116 +1,125 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_MC93_Migz2CleanTitle", id: "Tdarr_Plugin_MC93_Migz2CleanTitle",
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "Migz-Clean title metadata", Name: "Migz-Clean title metadata",
Type: "Video", Type: "Video",
Operation: "Clean", Operation: "Clean",
Description: `This plugin removes title metadata from video/audio/subtitles, if it exists. Video checking is mandatory, audio and subtitles are optional.\n\n`, Description: `This plugin removes title metadata from video/audio/subtitles, if it exists. Video checking is mandatory, audio and subtitles are optional.\n\n`,
Version: "1.2", Version: "1.2",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz2CleanTitle.js", Link:
Tags: 'pre-processing,ffmpeg,configurable', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz2CleanTitle.js",
Inputs: [{ Tags: "pre-processing,ffmpeg,configurable",
name: 'clean_audio', Inputs: [
tooltip: `Specify if audio titles should be checked & cleaned. Optional. {
name: "clean_audio",
tooltip: `Specify if audio titles should be checked & cleaned. Optional.
\\nExample:\\n \\nExample:\\n
true true
\\nExample:\\n \\nExample:\\n
false` false`,
}, },
{ {
name: 'clean_subtitles', name: "clean_subtitles",
tooltip: `Specify if subtitle titles should be checked & cleaned. Optional. tooltip: `Specify if subtitle titles should be checked & cleaned. Optional.
\\nExample:\\n \\nExample:\\n
true true
\\nExample:\\n \\nExample:\\n
false` false`,
}, },
] ],
} };
} }
function plugin(file, librarySettings, inputs) { function plugin(file, librarySettings, inputs) {
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.' + file.container, container: "." + file.container,
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: false, reQueueAfter: false,
infoLog: '', infoLog: "",
};
} // Set up required variables.
var ffmpegCommandInsert = "";
var videoIdx = 0;
var audioIdx = 0;
var subtitleIdx = 0;
var convert = false;
// Set up required variables. // Check if file is a video. If it isn't then exit plugin.
var ffmpegCommandInsert = '' if (file.fileMedium !== "video") {
var videoIdx = 0 console.log("File is not video");
var audioIdx = 0 response.infoLog += "☒File is not video \n";
var subtitleIdx = 0 response.processFile = false;
var convert = false return response;
}
// Check if file is a video. If it isn't then exit plugin. // Check if overall file metadata title is not empty, if it's not empty set to "".
if (file.fileMedium !== "video") { if (typeof file.meta.Title != "undefined")
console.log("File is not video") try {
response.infoLog += "☒File is not video \n" ffmpegCommandInsert += ` -metadata title="" `;
response.processFile = false; convert = true;
return response
}
// Check if overall file metadata title is not empty, if it's not empty set to "".
if (typeof file.meta.Title != 'undefined') try {
ffmpegCommandInsert += ` -metadata title="" `
convert = true
} catch (err) {} } catch (err) {}
// Go through each stream in the file. // Go through each stream in the file.
for (var i = 0; i < file.ffProbeData.streams.length; i++) try { for (var i = 0; i < file.ffProbeData.streams.length; i++)
// Check if stream is a video. try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") { // Check if stream is a video.
// Check if stream title is not empty, if it's nto empty set to "". if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
if (typeof file.ffProbeData.streams[i].tags.title != 'undefined') { // Check if stream title is not empty, if it's nto empty set to "".
response.infoLog += `☒Video stream title is not empty, most likely junk metadata. Removing title from stream ${i} \n` if (typeof file.ffProbeData.streams[i].tags.title != "undefined") {
ffmpegCommandInsert += ` -metadata:s:v:${videoIdx} title="" ` response.infoLog += `☒Video stream title is not empty, most likely junk metadata. Removing title from stream ${i} \n`;
convert = true ffmpegCommandInsert += ` -metadata:s:v:${videoIdx} title="" `;
} convert = true;
// Increment videoIdx.
videoIdx++
} }
// Increment videoIdx.
videoIdx++;
}
// Check if title metadata of audio stream has more then 3 full stops. If so then it's likely to be junk metadata so remove. // Check if title metadata of audio stream has more then 3 full stops. If so then it's likely to be junk metadata so remove.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && inputs.clean_audio.toLowerCase() == "true") { if (
if (file.ffProbeData.streams[i].tags.title.split('.').length - 1 > 3) { file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" &&
response.infoLog += `☒More then 3 full stops detected in audio title, likely to be junk metadata. Removing title from stream ${i} \n` inputs.clean_audio.toLowerCase() == "true"
ffmpegCommandInsert += ` -metadata:s:a:${audioIdx} title="" ` ) {
convert = true if (file.ffProbeData.streams[i].tags.title.split(".").length - 1 > 3) {
} response.infoLog += `☒More then 3 full stops detected in audio title, likely to be junk metadata. Removing title from stream ${i} \n`;
// Increment audioIdx. ffmpegCommandInsert += ` -metadata:s:a:${audioIdx} title="" `;
audioIdx++ convert = true;
} }
// Increment audioIdx.
audioIdx++;
}
// Check if title metadata of subtitle stream has more then 3 full stops. If so then it's likely to be junk metadata so remove. // Check if title metadata of subtitle stream has more then 3 full stops. If so then it's likely to be junk metadata so remove.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" && inputs.clean_subtitles.toLowerCase() == "true") { if (
if (file.ffProbeData.streams[i].tags.title.split('.').length - 1 > 3) { file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" &&
response.infoLog += `☒More then 3 full stops detected in subtitle title, likely to be junk metadata. Removing title from stream ${i} \n` inputs.clean_subtitles.toLowerCase() == "true"
ffmpegCommandInsert += ` -metadata:s:s:${subtitleIdx} title="" ` ) {
convert = true if (file.ffProbeData.streams[i].tags.title.split(".").length - 1 > 3) {
} response.infoLog += `☒More then 3 full stops detected in subtitle title, likely to be junk metadata. Removing title from stream ${i} \n`;
// Increment subtitleIdx. ffmpegCommandInsert += ` -metadata:s:s:${subtitleIdx} title="" `;
subtitleIdx++ convert = true;
} }
// Increment subtitleIdx.
subtitleIdx++;
}
} catch (err) {} } catch (err) {}
// Convert file if convert variable is set to true. // Convert file if convert variable is set to true.
if (convert == true) { if (convert == true) {
response.infoLog += "☒File has title metadata. Removing \n" response.infoLog += "☒File has title metadata. Removing \n";
response.preset = `,${ffmpegCommandInsert} -c copy -map 0 -max_muxing_queue_size 4096` response.preset = `,${ffmpegCommandInsert} -c copy -map 0 -max_muxing_queue_size 4096`;
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
} else { } else {
response.infoLog += "☑File has no title metadata \n" response.infoLog += "☑File has no title metadata \n";
} }
return response return response;
} }
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -1,17 +1,19 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_MC93_Migz3CleanAudio", id: "Tdarr_Plugin_MC93_Migz3CleanAudio",
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "Migz-Clean audio streams", Name: "Migz-Clean audio streams",
Type: "Audio", Type: "Audio",
Operation: "Clean", Operation: "Clean",
Description: `This plugin keeps only specified language audio tracks & can tags those that have an unknown language. \n\n`, Description: `This plugin keeps only specified language audio tracks & can tags those that have an unknown language. \n\n`,
Version: "2.2", Version: "2.2",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz3CleanAudio.js", Link:
Tags: 'pre-processing,ffmpeg,audio only,configurable', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz3CleanAudio.js",
Inputs: [{ Tags: "pre-processing,ffmpeg,audio only,configurable",
name: 'language', Inputs: [
tooltip: `Specify language tag/s here for the audio tracks you'd like to keep, recommended to keep "und" as this stands for undertermined, some files may not have the language specified. Must follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes {
name: "language",
tooltip: `Specify language tag/s here for the audio tracks you'd like to keep, recommended to keep "und" as this stands for undertermined, some files may not have the language specified. Must follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
\\nExample:\\n \\nExample:\\n
eng eng
@ -19,169 +21,201 @@ function details() {
eng,und eng,und
\\nExample:\\n \\nExample:\\n
eng,und,jap` eng,und,jap`,
}, },
{ {
name: 'commentary', name: "commentary",
tooltip: `Specify if audio tracks that contain commentary/description should be removed. tooltip: `Specify if audio tracks that contain commentary/description should be removed.
\\nExample:\\n \\nExample:\\n
true true
\\nExample:\\n \\nExample:\\n
false` false`,
}, },
{ {
name: 'tag_language', name: "tag_language",
tooltip: `Specify a single language for audio tracks with no language or unknown language to be tagged with, leave empty to disable, you must have "und" in your list of languages to keep for this to function. Must follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes tooltip: `Specify a single language for audio tracks with no language or unknown language to be tagged with, leave empty to disable, you must have "und" in your list of languages to keep for this to function. Must follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
\\nExample:\\n \\nExample:\\n
eng eng
\\nExample:\\n \\nExample:\\n
por` por`,
}, },
{ {
name: 'tag_title', name: "tag_title",
tooltip: `Specify audio tracks with no title to be tagged with the number of channels they contain. Do NOT use this with mp4, as mp4 does not support title tags. tooltip: `Specify audio tracks with no title to be tagged with the number of channels they contain. Do NOT use this with mp4, as mp4 does not support title tags.
\\nExample:\\n \\nExample:\\n
true true
\\nExample:\\n \\nExample:\\n
false` false`,
}, },
] ],
} };
} }
function plugin(file, librarySettings, inputs) { function plugin(file, librarySettings, inputs) {
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.' + file.container, container: "." + file.container,
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: false, reQueueAfter: false,
infoLog: '', infoLog: "",
} };
// Check if file is a video. If it isn't then exit plugin. // Check if file is a video. If it isn't then exit plugin.
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video") console.log("File is not video");
response.infoLog += "☒File is not video \n" response.infoLog += "☒File is not video \n";
response.processFile = false; response.processFile = false;
return response return response;
} }
// Check if inputs.language has been configured. If it hasn't then exit plugin. // Check if inputs.language has been configured. If it hasn't then exit plugin.
if (inputs.language == "") { if (inputs.language == "") {
response.infoLog += "☒Language/s keep have not been configured within plugin settings, please configure required options. Skipping this plugin. \n" response.infoLog +=
response.processFile = false; "☒Language/s keep have not been configured within plugin settings, please configure required options. Skipping this plugin. \n";
return response response.processFile = false;
return response;
}
// Set up required variables.
var language = inputs.language.split(",");
var ffmpegCommandInsert = "";
var convert = false;
var audioIdx = 0;
var audioStreamsRemoved = 0;
var audioStreamCount = file.ffProbeData.streams.filter(
(row) => row.codec_type.toLowerCase() == "audio"
).length;
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
// Catch error here incase the language metadata is completely missing.
try {
// Check if stream is audio AND checks if the tracks language code does not match any of the languages entered in inputs.language.
if (
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" &&
language.indexOf(
file.ffProbeData.streams[i].tags.language.toLowerCase()
) === -1
) {
audioStreamsRemoved++;
ffmpegCommandInsert += `-map -0:a:${audioIdx} `;
response.infoLog += `☒Audio stream detected as being an unwanted language, removing. Audio stream 0:a:${audioIdx} - ${file.ffProbeData.streams[
i
].tags.language.toLowerCase()} \n`;
convert = true;
}
} catch (err) {}
// Catch error here incase the title metadata is completely missing.
try {
// Check if inputs.commentary is set to true AND if stream is audio AND then checks for stream titles with the following "commentary, description, sdh". Removing any streams that are applicable.
if (
inputs.commentary.toLowerCase() == "true" &&
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" &&
(file.ffProbeData.streams[i].tags.title
.toLowerCase()
.includes("commentary") ||
file.ffProbeData.streams[i].tags.title
.toLowerCase()
.includes("description") ||
file.ffProbeData.streams[i].tags.title.toLowerCase().includes("sdh"))
) {
audioStreamsRemoved++;
ffmpegCommandInsert += `-map -0:a:${audioIdx} `;
response.infoLog += `☒Audio stream detected as being Commentary or Description, removing. Audio stream 0:a:${audioIdx} - ${file.ffProbeData.streams[i].tags.title}. \n`;
convert = true;
}
} catch (err) {}
// Check if inputs.tag_language has something entered (Entered means user actually wants something to happen, empty would disable this) AND checks that stream is audio.
if (
inputs.tag_language != "" &&
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio"
) {
// Catch error here incase the metadata is completely missing.
try {
// Look for audio with "und" as metadata language.
if (
file.ffProbeData.streams[i].tags.language
.toLowerCase()
.includes("und")
) {
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} language=${inputs.tag_language} `;
response.infoLog += `☒Audio stream detected as having unknown language tagged, tagging as ${inputs.tag_language}. \n`;
convert = true;
}
} catch (err) {}
// Checks if the tags metadata is completely missing, if so this would cause playback to show language as "undefined". No catch error here otherwise it would never detect the metadata as missing.
if (typeof file.ffProbeData.streams[i].tags == "undefined") {
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} language=${inputs.tag_language} `;
response.infoLog += `☒Audio stream detected as having no language tagged, tagging as ${inputs.tag_language}. \n`;
convert = true;
}
// Checks if the tags.language metadata is completely missing, if so this would cause playback to show language as "undefined". No catch error here otherwise it would never detect the metadata as missing.
else {
if (typeof file.ffProbeData.streams[i].tags.language == "undefined") {
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} language=${inputs.tag_language} `;
response.infoLog += `☒Audio stream detected as having no language tagged, tagging as ${inputs.tag_language}. \n`;
convert = true;
}
}
} }
// Set up required variables. try {
var language = inputs.language.split(",") // Check if title metadata is missing from any streams AND inputs.tag_title set to true AND if stream type is audio. Add title to any applicable streams.
var ffmpegCommandInsert = '' if (
var convert = false typeof file.ffProbeData.streams[i].tags.title == "undefined" &&
var audioIdx = 0 inputs.tag_title.toLowerCase() == "true" &&
var audioStreamsRemoved = 0 file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio"
var audioStreamCount = file.ffProbeData.streams.filter(row => (row.codec_type.toLowerCase() == "audio")).length; ) {
if (file.ffProbeData.streams[i].channels == "8") {
for (var i = 0; i < file.ffProbeData.streams.length; i++) { ffmpegCommandInsert += `-metadata:s:a:${audioIdx} title="7.1" `;
response.infoLog += `☒Audio stream detected as 8 channel audio track with no title, tagging title. Audio stream 0:a:${audioIdx} tagged as "7.1" \n`;
// Catch error here incase the language metadata is completely missing. convert = true;
try {
// Check if stream is audio AND checks if the tracks language code does not match any of the languages entered in inputs.language.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && language.indexOf(file.ffProbeData.streams[i].tags.language.toLowerCase()) === -1) {
audioStreamsRemoved++
ffmpegCommandInsert += `-map -0:a:${audioIdx} `
response.infoLog += `☒Audio stream detected as being an unwanted language, removing. Audio stream 0:a:${audioIdx} - ${file.ffProbeData.streams[i].tags.language.toLowerCase()} \n`
convert = true
}
} catch (err) {}
// Catch error here incase the title metadata is completely missing.
try {
// Check if inputs.commentary is set to true AND if stream is audio AND then checks for stream titles with the following "commentary, description, sdh". Removing any streams that are applicable.
if (inputs.commentary.toLowerCase() == "true" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && (file.ffProbeData.streams[i].tags.title.toLowerCase().includes('commentary') || file.ffProbeData.streams[i].tags.title.toLowerCase().includes('description') || file.ffProbeData.streams[i].tags.title.toLowerCase().includes('sdh'))) {
audioStreamsRemoved++
ffmpegCommandInsert += `-map -0:a:${audioIdx} `
response.infoLog += `☒Audio stream detected as being Commentary or Description, removing. Audio stream 0:a:${audioIdx} - ${file.ffProbeData.streams[i].tags.title}. \n`
convert = true
}
} catch (err) {}
// Check if inputs.tag_language has something entered (Entered means user actually wants something to happen, empty would disable this) AND checks that stream is audio.
if (inputs.tag_language != "" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
// Catch error here incase the metadata is completely missing.
try {
// Look for audio with "und" as metadata language.
if (file.ffProbeData.streams[i].tags.language.toLowerCase().includes('und')) {
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} language=${inputs.tag_language} `
response.infoLog += `☒Audio stream detected as having unknown language tagged, tagging as ${inputs.tag_language}. \n`
convert = true
}
} catch (err) {}
// Checks if the tags metadata is completely missing, if so this would cause playback to show language as "undefined". No catch error here otherwise it would never detect the metadata as missing.
if (typeof file.ffProbeData.streams[i].tags == 'undefined') {
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} language=${inputs.tag_language} `
response.infoLog += `☒Audio stream detected as having no language tagged, tagging as ${inputs.tag_language}. \n`
convert = true
}
// Checks if the tags.language metadata is completely missing, if so this would cause playback to show language as "undefined". No catch error here otherwise it would never detect the metadata as missing.
else {
if (typeof file.ffProbeData.streams[i].tags.language == 'undefined') {
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} language=${inputs.tag_language} `
response.infoLog += `☒Audio stream detected as having no language tagged, tagging as ${inputs.tag_language}. \n`
convert = true
}
}
} }
if (file.ffProbeData.streams[i].channels == "6") {
try { ffmpegCommandInsert += `-metadata:s:a:${audioIdx} title="5.1" `;
// Check if title metadata is missing from any streams AND inputs.tag_title set to true AND if stream type is audio. Add title to any applicable streams. response.infoLog += `☒Audio stream detected as 6 channel audio track with no title, tagging title. Audio stream 0:a:${audioIdx} tagged as "5.1" \n`;
if (typeof file.ffProbeData.streams[i].tags.title == 'undefined' && inputs.tag_title.toLowerCase() == "true" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { convert = true;
if (file.ffProbeData.streams[i].channels == "8") {
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} title="7.1" `
response.infoLog += `☒Audio stream detected as 8 channel audio track with no title, tagging title. Audio stream 0:a:${audioIdx} tagged as "7.1" \n`
convert = true
}
if (file.ffProbeData.streams[i].channels == "6") {
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} title="5.1" `
response.infoLog += `☒Audio stream detected as 6 channel audio track with no title, tagging title. Audio stream 0:a:${audioIdx} tagged as "5.1" \n`
convert = true
}
if (file.ffProbeData.streams[i].channels == "2") {
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} title="2.0" `
response.infoLog += `☒Audio stream detected as 2 channel audio track with no title, tagging title. Audio stream 0:a:${audioIdx} tagged as "2.0" \n`
convert = true
}
}
} catch (err) {}
// Check if stream type is audio and increment audioIdx if true.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
audioIdx++
} }
} if (file.ffProbeData.streams[i].channels == "2") {
// Failsafe to cancel processing if all streams would be removed following this plugin. We don't want no audio. ffmpegCommandInsert += `-metadata:s:a:${audioIdx} title="2.0" `;
if (audioStreamsRemoved == audioStreamCount) { response.infoLog += `☒Audio stream detected as 2 channel audio track with no title, tagging title. Audio stream 0:a:${audioIdx} tagged as "2.0" \n`;
response.infoLog += "☒Cancelling plugin otherwise all audio tracks would be removed. \n" convert = true;
response.processFile = false }
return response }
} } catch (err) {}
// Convert file if convert variable is set to true. // Check if stream type is audio and increment audioIdx if true.
if (convert === true) { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
response.processFile = true audioIdx++;
response.preset = `, -map 0 ${ffmpegCommandInsert} -c copy -max_muxing_queue_size 4096`
response.container = '.' + file.container
response.reQueueAfter = true
} else {
response.processFile = false
response.infoLog += "☑File doesn't contain audio tracks which are unwanted or that require tagging.\n"
} }
return response }
// Failsafe to cancel processing if all streams would be removed following this plugin. We don't want no audio.
if (audioStreamsRemoved == audioStreamCount) {
response.infoLog +=
"☒Cancelling plugin otherwise all audio tracks would be removed. \n";
response.processFile = false;
return response;
}
// 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 4096`;
response.container = "." + file.container;
response.reQueueAfter = true;
} else {
response.processFile = false;
response.infoLog +=
"☑File doesn't contain audio tracks which are unwanted or that require tagging.\n";
}
return response;
} }
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -1,145 +1,172 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_MC93_Migz4CleanSubs", id: "Tdarr_Plugin_MC93_Migz4CleanSubs",
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "Migz-Clean subtitle streams", Name: "Migz-Clean subtitle streams",
Type: "subtitles", Type: "subtitles",
Operation: "Clean", Operation: "Clean",
Description: `This plugin keeps only specified language subtitle tracks & can tag those that have an unknown language. \n\n`, Description: `This plugin keeps only specified language subtitle tracks & can tag those that have an unknown language. \n\n`,
Version: "2.2", Version: "2.2",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz4CleanSubs.js", Link:
Tags: 'pre-processing,ffmpeg,subtitle only,configurable', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz4CleanSubs.js",
Inputs: [{ Tags: "pre-processing,ffmpeg,subtitle only,configurable",
name: 'language', Inputs: [
tooltip: `Specify language tag/s here for the subtitle tracks you'd like to keep. Must follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes {
name: "language",
tooltip: `Specify language tag/s here for the subtitle tracks you'd like to keep. Must follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
\\nExample:\\n \\nExample:\\n
eng eng
\\nExample:\\n \\nExample:\\n
eng,jap` eng,jap`,
}, },
{ {
name: 'commentary', name: "commentary",
tooltip: `Specify if subtitle tracks that contain commentary/description should be removed. tooltip: `Specify if subtitle tracks that contain commentary/description should be removed.
\\nExample:\\n \\nExample:\\n
true true
\\nExample:\\n \\nExample:\\n
false` false`,
}, },
{ {
name: 'tag_language', name: "tag_language",
tooltip: `Specify a single language for subtitle tracks with no language or unknown language to be tagged with, leave empty to disable. Must follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes tooltip: `Specify a single language for subtitle tracks with no language or unknown language to be tagged with, leave empty to disable. Must follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
\\nExample:\\n \\nExample:\\n
eng eng
\\nExample:\\n \\nExample:\\n
por` por`,
}, },
] ],
} };
} }
function plugin(file, librarySettings, inputs) { function plugin(file, librarySettings, inputs) {
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.' + file.container, container: "." + file.container,
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: false, reQueueAfter: false,
infoLog: '', infoLog: "",
} };
// Check if file is a video. If it isn't then exit plugin. // Check if file is a video. If it isn't then exit plugin.
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video") console.log("File is not video");
response.infoLog += "☒File is not video \n" response.infoLog += "☒File is not video \n";
response.processFile = false; response.processFile = false;
return response return response;
} }
// Check if inputs.language has been configured. If it hasn't then exit plugin. // Check if inputs.language has been configured. If it hasn't then exit plugin.
if (inputs.language == "") { if (inputs.language == "") {
response.infoLog += "☒Language/s keep have not been configured within plugin settings, please configure required options. Skipping this plugin. \n" response.infoLog +=
response.processFile = false; "☒Language/s keep have not been configured within plugin settings, please configure required options. Skipping this plugin. \n";
return response response.processFile = false;
} return response;
}
// Set up required variables. // Set up required variables.
var language = inputs.language.split(",") var language = inputs.language.split(",");
var ffmpegCommandInsert = '' var ffmpegCommandInsert = "";
var subtitleIdx = 0 var subtitleIdx = 0;
var convert = false var convert = false;
// Go through each stream in the file. // Go through each stream in the file.
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
// Catch error here incase the language metadata is completely missing.
try {
// Check if stream is subtitle AND checks if the tracks language code does not match any of the languages entered in inputs.language.
if (
file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" &&
language.indexOf(
file.ffProbeData.streams[i].tags.language.toLowerCase()
) === -1
) {
ffmpegCommandInsert += `-map -0:s:${subtitleIdx} `;
response.infoLog += `☒Subtitle stream detected as being an unwanted language, removing. Subtitle stream 0:s:${subtitleIdx} - ${file.ffProbeData.streams[
i
].tags.language.toLowerCase()} \n`;
convert = true;
}
} catch (err) {}
// Catch error here incase the language metadata is completely missing. // Catch error here incase the title metadata is completely missing.
try { try {
// Check if stream is subtitle AND checks if the tracks language code does not match any of the languages entered in inputs.language. // Check if inputs.commentary is set to true AND if stream is subtitle AND then checks for stream titles with the following "commentary, description, sdh". Removing any streams that are applicable.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" && language.indexOf(file.ffProbeData.streams[i].tags.language.toLowerCase()) === -1) { if (
ffmpegCommandInsert += `-map -0:s:${subtitleIdx} ` inputs.commentary.toLowerCase() == "true" &&
response.infoLog += `☒Subtitle stream detected as being an unwanted language, removing. Subtitle stream 0:s:${subtitleIdx} - ${file.ffProbeData.streams[i].tags.language.toLowerCase()} \n` file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" &&
convert = true (file.ffProbeData.streams[i].tags.title
} .toLowerCase()
} catch (err) {} .includes("commentary") ||
file.ffProbeData.streams[i].tags.title
.toLowerCase()
.includes("description") ||
file.ffProbeData.streams[i].tags.title.toLowerCase().includes("sdh"))
) {
ffmpegCommandInsert += `-map -0:s:${subtitleIdx} `;
response.infoLog += `☒Subtitle stream detected as being Commentary or Description, removing. Subtitle stream 0:s:${SubtitleIdx} - ${file.ffProbeData.streams[i].tags.title}. \n`;
convert = true;
}
} catch (err) {}
// Catch error here incase the title metadata is completely missing. // Check if inputs.tag_language has something entered (Entered means user actually wants something to happen, empty would disable this) AND checks that stream is subtitle.
try { if (
// Check if inputs.commentary is set to true AND if stream is subtitle AND then checks for stream titles with the following "commentary, description, sdh". Removing any streams that are applicable. inputs.tag_language != "" &&
if (inputs.commentary.toLowerCase() == "true" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" && (file.ffProbeData.streams[i].tags.title.toLowerCase().includes('commentary') || file.ffProbeData.streams[i].tags.title.toLowerCase().includes('description') || file.ffProbeData.streams[i].tags.title.toLowerCase().includes('sdh'))) { file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle"
ffmpegCommandInsert += `-map -0:s:${subtitleIdx} ` ) {
response.infoLog += `☒Subtitle stream detected as being Commentary or Description, removing. Subtitle stream 0:s:${SubtitleIdx} - ${file.ffProbeData.streams[i].tags.title}. \n` // Catch error here incase the metadata is completely missing.
convert = true try {
} // Look for subtitle with "und" as metadata language.
} catch (err) {} if (
file.ffProbeData.streams[i].tags.language
// Check if inputs.tag_language has something entered (Entered means user actually wants something to happen, empty would disable this) AND checks that stream is subtitle. .toLowerCase()
if (inputs.tag_language != "" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") { .includes("und")
// Catch error here incase the metadata is completely missing. ) {
try { ffmpegCommandInsert += `-metadata:s:s:${subtitleIdx} language=${inputs.tag_language} `;
// Look for subtitle with "und" as metadata language. response.infoLog += `☒Subtitle stream detected as having unknown language tagged, tagging as ${inputs.tag_language}. \n`;
if (file.ffProbeData.streams[i].tags.language.toLowerCase().includes('und')) { convert = true;
ffmpegCommandInsert += `-metadata:s:s:${subtitleIdx} language=${inputs.tag_language} `
response.infoLog += `☒Subtitle stream detected as having unknown language tagged, tagging as ${inputs.tag_language}. \n`
convert = true
}
} catch (err) {}
// Checks if the tags metadata is completely missing, if so this would cause playback to show language as "undefined". No catch error here otherwise it would never detect the metadata as missing.
if (typeof file.ffProbeData.streams[i].tags == 'undefined') {
ffmpegCommandInsert += `-metadata:s:s:${subtitleIdx} language=${inputs.tag_language} `
response.infoLog += `☒Subtitle stream detected as having no language tagged, tagging as ${inputs.tag_language}. \n`
convert = true
}
// Checks if the tags.language metadata is completely missing, if so this would cause playback to show language as "undefined". No catch error here otherwise it would never detect the metadata as missing.
else {
if (typeof file.ffProbeData.streams[i].tags.language == 'undefined') {
ffmpegCommandInsert += `-metadata:s:s:${subtitleIdx} language=${inputs.tag_language} `
response.infoLog += `☒Subtitle stream detected as having no language tagged, tagging as ${inputs.tag_language}. \n`
convert = true
}
}
} }
} catch (err) {}
// Check if stream type is subtitle and increment subtitleIdx if true. // Checks if the tags metadata is completely missing, if so this would cause playback to show language as "undefined". No catch error here otherwise it would never detect the metadata as missing.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") { if (typeof file.ffProbeData.streams[i].tags == "undefined") {
subtitleIdx++ ffmpegCommandInsert += `-metadata:s:s:${subtitleIdx} language=${inputs.tag_language} `;
response.infoLog += `☒Subtitle stream detected as having no language tagged, tagging as ${inputs.tag_language}. \n`;
convert = true;
}
// Checks if the tags.language metadata is completely missing, if so this would cause playback to show language as "undefined". No catch error here otherwise it would never detect the metadata as missing.
else {
if (typeof file.ffProbeData.streams[i].tags.language == "undefined") {
ffmpegCommandInsert += `-metadata:s:s:${subtitleIdx} language=${inputs.tag_language} `;
response.infoLog += `☒Subtitle stream detected as having no language tagged, tagging as ${inputs.tag_language}. \n`;
convert = true;
} }
}
} }
// Convert file if convert variable is set to true. // Check if stream type is subtitle and increment subtitleIdx if true.
if (convert === true) { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") {
response.processFile = true; subtitleIdx++;
response.preset = `, -map 0 ${ffmpegCommandInsert} -c copy -max_muxing_queue_size 4096`
response.container = '.' + file.container
response.reQueueAfter = true;
} else {
response.processFile = false;
response.infoLog += "☑File doesn't contain subtitle tracks which are unwanted or that require tagging.\n"
} }
return response }
// 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 4096`;
response.container = "." + file.container;
response.reQueueAfter = true;
} else {
response.processFile = false;
response.infoLog +=
"☑File doesn't contain subtitle tracks which are unwanted or that require tagging.\n";
}
return response;
} }
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -1,137 +1,151 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_MC93_Migz5ConvertAudio", id: "Tdarr_Plugin_MC93_Migz5ConvertAudio",
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "Migz-Convert audio streams", Name: "Migz-Convert audio streams",
Type: "Audio", Type: "Audio",
Operation: "Transcode", Operation: "Transcode",
Description: `This plugin can convert any 2.0 audio track/s to AAC and can create downmixed audio tracks. \n\n`, Description: `This plugin can convert any 2.0 audio track/s to AAC and can create downmixed audio tracks. \n\n`,
Version: "2.1", Version: "2.1",
Link: "", Link: "",
Tags: 'pre-processing,ffmpeg,audio only,configurable', Tags: "pre-processing,ffmpeg,audio only,configurable",
Inputs: [{ Inputs: [
name: 'aac_stereo', {
tooltip: `Specify if any 2.0 audio tracks should be converted to aac for maximum compatability with devices. Optional. name: "aac_stereo",
tooltip: `Specify if any 2.0 audio tracks should be converted to aac for maximum compatability with devices. Optional.
\\nExample:\\n \\nExample:\\n
true true
\\nExample:\\n \\nExample:\\n
false` false`,
}, },
{ {
name: 'downmix', name: "downmix",
tooltip: `Specify if downmixing should be used to create extra audio tracks. I.e if you have an 8ch but no 2ch or 6ch, create the missing audio tracks from the 8 ch. Likewise if you only have 6ch, create the missing 2ch from it. Optional. tooltip: `Specify if downmixing should be used to create extra audio tracks. I.e if you have an 8ch but no 2ch or 6ch, create the missing audio tracks from the 8 ch. Likewise if you only have 6ch, create the missing 2ch from it. Optional.
\\nExample:\\n \\nExample:\\n
true true
\\nExample:\\n \\nExample:\\n
false` false`,
}, },
] ],
} };
} }
function plugin(file, librarySettings, inputs) { function plugin(file, librarySettings, inputs) {
var response = { var response = {
processFile: false, processFile: false,
container: '.' + file.container, container: "." + file.container,
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: true, reQueueAfter: true,
infoLog: '', infoLog: "",
} };
// Check if both inputs.aac_stereo AND inputs.downmix have been left empty. If they have then exit plugin.
if (inputs && inputs.aac_stereo == "" && inputs.downmix == "") {
response.infoLog += "☒Neither aac_stereo or downmix options have been configured within plugin settings, please configure required options. Skipping this plugin. \n"
response.processFile = false
return response
}
// Check if file is a video. If it isn't then exit plugin.
if (file.fileMedium !== "video") {
console.log("File is not video")
response.infoLog += "☒File is not video. \n"
response.processFile = false;
return response
}
// Set up required variables. // Check if both inputs.aac_stereo AND inputs.downmix have been left empty. If they have then exit plugin.
var ffmpegCommandInsert = '' if (inputs && inputs.aac_stereo == "" && inputs.downmix == "") {
var audioIdx = 0 response.infoLog +=
var has2Channel = false "☒Neither aac_stereo or downmix options have been configured within plugin settings, please configure required options. Skipping this plugin. \n";
var has6Channel = false response.processFile = false;
var has8Channel = false return response;
var convert = false }
// Go through each stream in the file. // Check if file is a video. If it isn't then exit plugin.
for (var i = 0; i < file.ffProbeData.streams.length; i++) { if (file.fileMedium !== "video") {
try { console.log("File is not video");
// Go through all audio streams and check if 2,6 & 8 channel tracks exist or not. response.infoLog += "☒File is not video. \n";
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { response.processFile = false;
if (file.ffProbeData.streams[i].channels == "2") { return response;
has2Channel = true }
}
if (file.ffProbeData.streams[i].channels == "6") {
has6Channel = true
}
if (file.ffProbeData.streams[i].channels == "8") {
has8Channel = true
}
}
} catch (err) {}
}
// Go through each stream in the file. // Set up required variables.
for (var i = 0; i < file.ffProbeData.streams.length; i++) { var ffmpegCommandInsert = "";
// Check if stream is audio. var audioIdx = 0;
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { var has2Channel = false;
// Catch error here incase user left inputs.downmix empty. var has6Channel = false;
try { var has8Channel = false;
// Check if inputs.downmix is set to true. var convert = false;
if (inputs.downmix.toLowerCase() == "true") {
// Check if file has 8 channel audio but no 6 channel, if so then create extra downmix from the 8 channel.
if (has8Channel == true && has6Channel == false && file.ffProbeData.streams[i].channels == "8") {
ffmpegCommandInsert += `-map 0:${i} -c:a:${audioIdx} ac3 -ac 6 -metadata:s:a:${audioIdx} title="5.1 " `
response.infoLog += "☒Audio track is 8 channel, no 6 channel exists. Creating 6 channel from 8 channel. \n"
convert = true
}
// Check if file has 6 channel audio but no 2 channel, if so then create extra downmix from the 6 channel.
if (has6Channel == true && has2Channel == false && file.ffProbeData.streams[i].channels == "6") {
ffmpegCommandInsert += `-map 0:${i} -c:a:${audioIdx} aac -ac 2 -metadata:s:a:${audioIdx} title="2.0 " `
response.infoLog += "☒Audio track is 6 channel, no 2 channel exists. Creating 2 channel from 6 channel. \n"
convert = true
}
}
} catch (err) {}
// Catch error here incase user left inputs.downmix empty. // Go through each stream in the file.
try { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
// Check if inputs.aac_stereo is set to true. try {
if (inputs.aac_stereo.toLowerCase() == "true") { // Go through all audio streams and check if 2,6 & 8 channel tracks exist or not.
// Check if codec_name for stream is NOT aac AND check if channel ammount is 2. if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
if (file.ffProbeData.streams[i].codec_name != "aac" && file.ffProbeData.streams[i].channels == "2") { if (file.ffProbeData.streams[i].channels == "2") {
ffmpegCommandInsert += `-c:a:${audioIdx} aac ` has2Channel = true;
response.infoLog += "☒Audio track is 2 channel but is not AAC. Converting. \n" }
convert = true if (file.ffProbeData.streams[i].channels == "6") {
} has6Channel = true;
} }
} catch (err) {} if (file.ffProbeData.streams[i].channels == "8") {
audioIdx++ has8Channel = true;
} }
}
} catch (err) {}
}
} // Go through each stream in the file.
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
// Check if stream is audio.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
// Catch error here incase user left inputs.downmix empty.
try {
// Check if inputs.downmix is set to true.
if (inputs.downmix.toLowerCase() == "true") {
// Check if file has 8 channel audio but no 6 channel, if so then create extra downmix from the 8 channel.
if (
has8Channel == true &&
has6Channel == false &&
file.ffProbeData.streams[i].channels == "8"
) {
ffmpegCommandInsert += `-map 0:${i} -c:a:${audioIdx} ac3 -ac 6 -metadata:s:a:${audioIdx} title="5.1 " `;
response.infoLog +=
"☒Audio track is 8 channel, no 6 channel exists. Creating 6 channel from 8 channel. \n";
convert = true;
}
// Check if file has 6 channel audio but no 2 channel, if so then create extra downmix from the 6 channel.
if (
has6Channel == true &&
has2Channel == false &&
file.ffProbeData.streams[i].channels == "6"
) {
ffmpegCommandInsert += `-map 0:${i} -c:a:${audioIdx} aac -ac 2 -metadata:s:a:${audioIdx} title="2.0 " `;
response.infoLog +=
"☒Audio track is 6 channel, no 2 channel exists. Creating 2 channel from 6 channel. \n";
convert = true;
}
}
} catch (err) {}
// Convert file if convert variable is set to true. // Catch error here incase user left inputs.downmix empty.
if (convert == true) { try {
response.processFile = true; // Check if inputs.aac_stereo is set to true.
response.preset = `, -map 0 -c:v copy -c:a copy ${ffmpegCommandInsert} -strict -2 -c:s copy -max_muxing_queue_size 4096 ` if (inputs.aac_stereo.toLowerCase() == "true") {
} else { // Check if codec_name for stream is NOT aac AND check if channel ammount is 2.
response.infoLog += "☑File contains all required audio formats. \n" if (
response.processFile = false; file.ffProbeData.streams[i].codec_name != "aac" &&
file.ffProbeData.streams[i].channels == "2"
) {
ffmpegCommandInsert += `-c:a:${audioIdx} aac `;
response.infoLog +=
"☒Audio track is 2 channel but is not AAC. Converting. \n";
convert = true;
}
}
} catch (err) {}
audioIdx++;
} }
return response }
// Convert file if convert variable is set to true.
if (convert == true) {
response.processFile = true;
response.preset = `, -map 0 -c:v copy -c:a copy ${ffmpegCommandInsert} -strict -2 -c:s copy -max_muxing_queue_size 4096 `;
} else {
response.infoLog += "☑File contains all required audio formats. \n";
response.processFile = false;
}
return response;
} }
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -1,169 +1,187 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_MC93_Migz6OrderStreams", id: "Tdarr_Plugin_MC93_Migz6OrderStreams",
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "Migz-Order Streams", Name: "Migz-Order Streams",
Type: "Streams", Type: "Streams",
Operation: "Order", Operation: "Order",
Description: `Orders streams into Video first, then Audio (2ch, 6ch, 8ch) and finally Subtitles. \n\n`, Description: `Orders streams into Video first, then Audio (2ch, 6ch, 8ch) and finally Subtitles. \n\n`,
Version: "1.1", Version: "1.1",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz6OrderStreams.js", Link:
Tags: 'pre-processing,ffmpeg,' "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz6OrderStreams.js",
} Tags: "pre-processing,ffmpeg,",
};
} }
function plugin(file) { function plugin(file) {
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.' + file.container, container: "." + file.container,
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
infoLog: '', infoLog: "",
} };
// Set up required variables. // Set up required variables.
var ffmpegCommandInsert = '' var ffmpegCommandInsert = "";
var videoIdx = 0 var videoIdx = 0;
var audioIdx = 0 var audioIdx = 0;
var audio2Idx = 0 var audio2Idx = 0;
var audio6Idx = 0 var audio6Idx = 0;
var audio8Idx = 0 var audio8Idx = 0;
var subtitleIdx = 0 var subtitleIdx = 0;
var convert = false var convert = false;
// Go through each stream in the file. // Go through each stream in the file.
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
// Check if stream is video. // Check if stream is video.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
// Check if audioIdx or subtitleIdx do NOT equal 0, if they do then it means a audio or subtitle track has already appeared before the video track so file needs to be organized. // Check if audioIdx or subtitleIdx do NOT equal 0, if they do then it means a audio or subtitle track has already appeared before the video track so file needs to be organized.
if (audioIdx != "0" || subtitleIdx != "0") { if (audioIdx != "0" || subtitleIdx != "0") {
convert = true convert = true;
response.infoLog += "☒ Video not first. \n" response.infoLog += "☒ Video not first. \n";
} }
// Increment videoIdx. // Increment videoIdx.
videoIdx++ videoIdx++;
} }
// Check if stream is audio. // Check if stream is audio.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
// Check if subtitleIdx does NOT equal 0, if it does then it means a subtitle track has already appeared before an audio track so file needs to be organized. // Check if subtitleIdx does NOT equal 0, if it does then it means a subtitle track has already appeared before an audio track so file needs to be organized.
if (subtitleIdx != "0") { if (subtitleIdx != "0") {
convert = true convert = true;
response.infoLog += "☒ Audio not second. \n" response.infoLog += "☒ Audio not second. \n";
} }
// Increment audioIdx. // Increment audioIdx.
audioIdx++ audioIdx++;
// Check if audio track is 2 channel.
if (file.ffProbeData.streams[i].channels == "2") {
// Check if audio6Idx or audio8Idx do NOT equal 0, if they do then it means a 6 channel or 8 channel audio track has already appeared before the 2 channel audio track so file needs to be organized.
if (audio6Idx != "0" || audio8Idx != "0") {
convert = true
response.infoLog += "☒ Audio 2ch not first. \n"
}
// Increment audio2Idx.
audio2Idx++
}
// Check if audio track is 6 channel.
if (file.ffProbeData.streams[i].channels == "6") {
// Check if audio8Idx does NOT equal 0, if it does then it means a 8 channel audio track has already appeared before the 6 channel audio track so file needs to be organized.
if (audio8Idx != "0") {
convert = true
response.infoLog += "☒ Audio 6ch not second. \n"
}
// Increment audio6Idx.
audio6Idx++
}
// Check if audio track is 8 channel.
if (file.ffProbeData.streams[i].channels == "8") {
// Increment audio8Idx.
audio8Idx++
}
}
// Check if stream is subtitle. // Check if audio track is 2 channel.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") { if (file.ffProbeData.streams[i].channels == "2") {
// Increment subtitleIdx // Check if audio6Idx or audio8Idx do NOT equal 0, if they do then it means a 6 channel or 8 channel audio track has already appeared before the 2 channel audio track so file needs to be organized.
subtitleIdx++ if (audio6Idx != "0" || audio8Idx != "0") {
} convert = true;
} catch (err) {} response.infoLog += "☒ Audio 2ch not first. \n";
} }
// Increment audio2Idx.
audio2Idx++;
}
// Check if audio track is 6 channel.
if (file.ffProbeData.streams[i].channels == "6") {
// Check if audio8Idx does NOT equal 0, if it does then it means a 8 channel audio track has already appeared before the 6 channel audio track so file needs to be organized.
if (audio8Idx != "0") {
convert = true;
response.infoLog += "☒ Audio 6ch not second. \n";
}
// Increment audio6Idx.
audio6Idx++;
}
// Go through each stream in the file. // Check if audio track is 8 channel.
for (var i = 0; i < file.ffProbeData.streams.length; i++) { if (file.ffProbeData.streams[i].channels == "8") {
try { // Increment audio8Idx.
// Check if stream is video AND is not a mjpeg. audio8Idx++;
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video" && file.ffProbeData.streams[i].codec_name.toLowerCase() != "mjpeg") { }
ffmpegCommandInsert += `-map 0:${i} ` }
}
} catch (err) {}
}
// Go through each stream in the file. // Check if stream is subtitle.
for (var i = 0; i < file.ffProbeData.streams.length; i++) { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") {
try { // Increment subtitleIdx
// Check if stream is audio AND 2 channel. subtitleIdx++;
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].channels == "2") { }
ffmpegCommandInsert += `-map 0:${i} ` } catch (err) {}
} }
} catch (err) {}
}
// Go through each stream in the file. // Go through each stream in the file.
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
// Check if stream is audio AND 6 channel. // Check if stream is video AND is not a mjpeg.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].channels == "6") { if (
ffmpegCommandInsert += `-map 0:${i} ` file.ffProbeData.streams[i].codec_type.toLowerCase() == "video" &&
} file.ffProbeData.streams[i].codec_name.toLowerCase() != "mjpeg"
} catch (err) {} ) {
} ffmpegCommandInsert += `-map 0:${i} `;
}
} catch (err) {}
}
// Go through each stream in the file. // Go through each stream in the file.
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
// Check if stream is audio AND 8 channel. // Check if stream is audio AND 2 channel.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].channels == "8") { if (
ffmpegCommandInsert += `-map 0:${i} ` file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" &&
} file.ffProbeData.streams[i].channels == "2"
} catch (err) {} ) {
} ffmpegCommandInsert += `-map 0:${i} `;
}
} catch (err) {}
}
// Go through each stream in the file. // Go through each stream in the file.
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
// Check if stream is audio AND not 2, 6 or 8 channel. // Check if stream is audio AND 6 channel.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].channels != "2" && file.ffProbeData.streams[i].channels != "6" && file.ffProbeData.streams[i].channels != "8") { if (
ffmpegCommandInsert += `-map 0:${i} ` file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" &&
} file.ffProbeData.streams[i].channels == "6"
} catch (err) {} ) {
} ffmpegCommandInsert += `-map 0:${i} `;
}
} catch (err) {}
}
// Go through each stream in the file. // Go through each stream in the file.
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
// Check if stream is subtitle. // Check if stream is audio AND 8 channel.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") { if (
ffmpegCommandInsert += `-map 0:${i} ` file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" &&
} file.ffProbeData.streams[i].channels == "8"
} catch (err) {} ) {
} ffmpegCommandInsert += `-map 0:${i} `;
}
} catch (err) {}
}
// Convert file if convert variable is set to true. // Go through each stream in the file.
if (convert == true) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
response.processFile = true; try {
response.preset = `,${ffmpegCommandInsert} -c copy -max_muxing_queue_size 4096` // Check if stream is audio AND not 2, 6 or 8 channel.
response.reQueueAfter = true; if (
response.infoLog += "☒ Streams are out of order, reorganizing streams. Video, Audio, Subtitles. \n" file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" &&
} else { file.ffProbeData.streams[i].channels != "2" &&
response.infoLog += "☑ Streams are in expected order. \n " file.ffProbeData.streams[i].channels != "6" &&
response.processFile = false; file.ffProbeData.streams[i].channels != "8"
} ) {
return response ffmpegCommandInsert += `-map 0:${i} `;
}
} catch (err) {}
}
// Go through each stream in the file.
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try {
// Check if stream is subtitle.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") {
ffmpegCommandInsert += `-map 0:${i} `;
}
} catch (err) {}
}
// Convert file if convert variable is set to true.
if (convert == true) {
response.processFile = true;
response.preset = `,${ffmpegCommandInsert} -c copy -max_muxing_queue_size 4096`;
response.reQueueAfter = true;
response.infoLog +=
"☒ Streams are out of order, reorganizing streams. Video, Audio, Subtitles. \n";
} else {
response.infoLog += "☑ Streams are in expected order. \n ";
response.processFile = false;
}
return response;
} }
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -1,64 +1,69 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_MC93_MigzImageRemoval", id: "Tdarr_Plugin_MC93_MigzImageRemoval",
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "Migz-Remove image formats from file", Name: "Migz-Remove image formats from file",
Type: "Video", Type: "Video",
Operation: "Clean", Operation: "Clean",
Description: `Identify any unwanted image formats in the file and remove those streams. MJPEG & PNG \n\n`, Description: `Identify any unwanted image formats in the file and remove those streams. MJPEG & PNG \n\n`,
Version: "1.1", Version: "1.1",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_MigzImageRemoval.js", Link:
Tags: 'pre-processing,ffmpeg,video only' "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_MigzImageRemoval.js",
} Tags: "pre-processing,ffmpeg,video only",
};
} }
function plugin(file, librarySettings, inputs) { function plugin(file, librarySettings, inputs) {
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
handBrakeMode: false, handBrakeMode: false,
container: '.' + file.container, container: "." + file.container,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: true, reQueueAfter: true,
infoLog: '' infoLog: "",
} };
// Check if file is a video. If it isn't then exit plugin. // Check if file is a video. If it isn't then exit plugin.
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
response.processFile = false response.processFile = false;
response.infoLog += "☒File is not a video. \n" response.infoLog += "☒File is not a video. \n";
return response return response;
} }
// Set up required variables. // Set up required variables.
var videoIdx = 0 var videoIdx = 0;
var extraArguments = "" var extraArguments = "";
var convert = false var convert = false;
// Go through each stream in the file. // Go through each stream in the file.
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
// Check if stream is video. // Check if stream is video.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
// Check if stream codec is mjpeg or png. Remove if so. // Check if stream codec is mjpeg or png. Remove if so.
if (file.ffProbeData.streams[i].codec_name == 'mjpeg' || file.ffProbeData.streams[i].codec_name == 'png') { if (
convert = true file.ffProbeData.streams[i].codec_name == "mjpeg" ||
extraArguments += `-map -v:${videoIdx} ` file.ffProbeData.streams[i].codec_name == "png"
} ) {
// Increment videoIdx. convert = true;
videoIdx++ extraArguments += `-map -v:${videoIdx} `;
} }
// Increment videoIdx.
videoIdx++;
} }
}
// Convert file if convert variable is set to true. // Convert file if convert variable is set to true.
if (convert === true) { if (convert === true) {
response.preset += `,-map 0 -c copy -max_muxing_queue_size 4096 ${extraArguments}` response.preset += `,-map 0 -c copy -max_muxing_queue_size 4096 ${extraArguments}`;
response.infoLog += `☒File has image format stream, removing. \n` response.infoLog += `☒File has image format stream, removing. \n`;
response.processFile = true; response.processFile = true;
} else { } else {
response.processFile = false; response.processFile = false;
response.infoLog += "☑File doesn't contain any unwanted image format streams.\n" response.infoLog +=
} "☑File doesn't contain any unwanted image format streams.\n";
return response }
return response;
} }
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -1,84 +1,94 @@
module.exports.details = function details() { module.exports.details = function details() {
return { return {
id: "Tdarr_Plugin_MC93_MigzPlex_Autoscan", id: "Tdarr_Plugin_MC93_MigzPlex_Autoscan",
Stage: "Post-processing", Stage: "Post-processing",
Name: "Send request for file to be scanned by plex_autoscan.", Name: "Send request for file to be scanned by plex_autoscan.",
Type: "Video", Type: "Video",
Operation: "", Operation: "",
Description: `Send request for file to be scanned by plex_autoscan. https://github.com/l3uddz/plex_autoscan \n\n`, Description: `Send request for file to be scanned by plex_autoscan. https://github.com/l3uddz/plex_autoscan \n\n`,
Version: "1.1", Version: "1.1",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_MigzPlex_Autoscan.js", Link:
Tags: "3rd party,post-processing,configurable", "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_MigzPlex_Autoscan.js",
Tags: "3rd party,post-processing,configurable",
Inputs: [{ Inputs: [
name: 'autoscan_address', {
tooltip: ` name: "autoscan_address",
tooltip: `
Enter the IP address/URL for autoscan. Must include http(s):// Enter the IP address/URL for autoscan. Must include http(s)://
\\nExample:\\n \\nExample:\\n
http://192.168.0.10 http://192.168.0.10
\\nExample:\\n \\nExample:\\n
https://subdomain.domain.tld` https://subdomain.domain.tld`,
}, },
{ {
name: 'autoscan_port', name: "autoscan_port",
tooltip: ` tooltip: `
Enter the port Autoscan is using, default is 3468 Enter the port Autoscan is using, default is 3468
\\nExample:\\n \\nExample:\\n
3468` 3468`,
}, },
{ {
name: 'autoscan_passkey', name: "autoscan_passkey",
tooltip: ` tooltip: `
Enter the autoscan passkey. Enter the autoscan passkey.
\\nExample:\\n \\nExample:\\n
9c4b81fe234e4d6eb9011cefe514d915` 9c4b81fe234e4d6eb9011cefe514d915`,
}, },
] ],
} };
} };
module.exports.plugin = function plugin(file, librarySettings, inputs) { module.exports.plugin = function plugin(file, librarySettings, inputs) {
// Check if all inputs have been configured. If they haven't then exit plugin.
// Check if all inputs have been configured. If they haven't then exit plugin. if (
if (inputs && inputs.autoscan_address == "" && inputs.autoscan_port == "" && inputs.autoscan_passkey == "") { inputs &&
response.infoLog += "☒Autoscan options have not been configured, please configure all options. Skipping this plugin. \n" inputs.autoscan_address == "" &&
response.processFile = false; inputs.autoscan_port == "" &&
return response inputs.autoscan_passkey == ""
} ) {
response.infoLog +=
// Take variable inputs and turn them into read only variable "☒Autoscan options have not been configured, please configure all options. Skipping this plugin. \n";
const request = require('request') response.processFile = false;
const ADDRESS = inputs.autoscan_address return response;
const PORT = inputs.autoscan_port }
const PASSKEY = inputs.autoscan_passkey
// Set up required variables. // Take variable inputs and turn them into read only variable
var response = "" const request = require("request");
filepath = `${file.file}` const ADDRESS = inputs.autoscan_address;
const PORT = inputs.autoscan_port;
const PASSKEY = inputs.autoscan_passkey;
// Set content of request/post. // Set up required variables.
request.post({ var response = "";
headers: { filepath = `${file.file}`;
'content-type': 'application/json'
}, // Set content of request/post.
url: `${ADDRESS}:${PORT}/${PASSKEY}`, request.post(
form: { {
"eventType": "Manual", headers: {
"filepath": `${filepath}` "content-type": "application/json",
} },
}, (error, res, body) => { url: `${ADDRESS}:${PORT}/${PASSKEY}`,
if (error) { form: {
console.error(error) eventType: "Manual",
} filepath: `${filepath}`,
console.log(`statusCode: ${res.statusCode}`) },
console.log(body) },
}) (error, res, body) => {
if (error) {
console.error(error);
}
console.log(`statusCode: ${res.statusCode}`);
console.log(body);
}
);
console.log("request next") console.log("request next");
console.log(request.post) console.log(request.post);
} };

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_a37x_Drawmonster_MP4_No_Title_Meta", id: "Tdarr_Plugin_a37x_Drawmonster_MP4_No_Title_Meta",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,75 +7,55 @@ function details() {
Description: `[Contains built-in filter] This plugin removes metadata (if a title exists). The output container is mp4. \n\n Description: `[Contains built-in filter] This plugin removes metadata (if a title exists). The output container is mp4. \n\n
`, `,
Version: "1.00", Version: "1.00",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_a37x_Drawmonster_MP4_No_Title_Meta.js", Link:
Tags:'pre-processing,ffmpeg', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_a37x_Drawmonster_MP4_No_Title_Meta.js",
} Tags: "pre-processing,ffmpeg",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false,
preset: "",
container: ".mp4",
handBrakeMode: false,
FFmpegMode: false,
reQueueAfter: false,
infoLog: "",
};
processFile : false, response.FFmpegMode = true;
preset : '',
container : '.mp4',
handBrakeMode : false,
FFmpegMode : false,
reQueueAfter : false,
infoLog : '',
}
response.FFmpegMode = true
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else {
} else { var jsonString = JSON.stringify(file);
var jsonString = JSON.stringify(file)
///
///
if (file.meta.Title != undefined) {
response.infoLog += "☒File has title metadata \n";
/// response.preset = ",-map_metadata -1 -map 0 -c copy";
///
if(file.meta.Title != undefined ){
response.infoLog += "☒File has title metadata \n"
response.preset = ',-map_metadata -1 -map 0 -c copy'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
}else{ } else {
response.infoLog += "☑File has no title metadata \n" response.infoLog += "☑File has no title metadata \n";
} }
response.infoLog += "☑File meets conditions! \n"
return response
response.infoLog += "☑File meets conditions! \n";
return response;
} }
} }
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -1,138 +1,138 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_a8hc_HaveAGitGat_HandBrake_H264_VeryFast1080p30", id: "Tdarr_Plugin_a8hc_HaveAGitGat_HandBrake_H264_VeryFast1080p30",
Stage: "Pre-processing", Stage: "Pre-processing",
Name: Name:
"HaveAGitGat HandBrake VeryFast1080p30, No title meta, no subs, 192Kb AAC stereo,MP4 ", "HaveAGitGat HandBrake VeryFast1080p30, No title meta, no subs, 192Kb AAC stereo,MP4 ",
Type: "Video", Type: "Video",
Description: `[Contains built-in filter] This plugin transcodes into H264 using HandBrake's 'Very Fast 1080p30' preset if the file is not in H264 already. It removes subs, metadata (if a title exists) and adds a stereo 192kbit AAC track if an AAC track (any) doesn't exist. The output container is MP4. \n\n Description: `[Contains built-in filter] This plugin transcodes into H264 using HandBrake's 'Very Fast 1080p30' preset if the file is not in H264 already. It removes subs, metadata (if a title exists) and adds a stereo 192kbit AAC track if an AAC track (any) doesn't exist. The output container is MP4. \n\n
`, `,
Version: "1.00", Version: "1.00",
Link: Link:
"https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_a8hc_HaveAGitGat_HandBrake_H264_VeryFast1080p30.js", "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_a8hc_HaveAGitGat_HandBrake_H264_VeryFast1080p30.js",
Tags: "pre-processing,handbrake,ffmpeg,h264", Tags: "pre-processing,handbrake,ffmpeg,h264",
}; };
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false, processFile: false,
preset: "", preset: "",
container: ".mp4", container: ".mp4",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: false, reQueueAfter: false,
infoLog: "", infoLog: "",
}; };
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video"); console.log("File is not video");
response.infoLog += "☒File is not video \n"; response.infoLog += "☒File is not video \n";
response.processFile = false; response.processFile = false;
return response; return response;
} else { } else {
var jsonString = JSON.stringify(file); var jsonString = JSON.stringify(file);
var hasSubs = false; var hasSubs = false;
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
if ( if (
file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle"
) { ) {
hasSubs = true; hasSubs = true;
} }
} catch (err) {} } catch (err) {}
} }
if (file.ffProbeData.streams[0].codec_name != "h264") { if (file.ffProbeData.streams[0].codec_name != "h264") {
response.infoLog += "☒File is not in h264! \n"; response.infoLog += "☒File is not in h264! \n";
response.preset = '-Z "Very Fast 1080p30"'; response.preset = '-Z "Very Fast 1080p30"';
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.handBrakeMode = true; response.handBrakeMode = true;
return response; return response;
} else { } else {
response.infoLog += "☑File is already in h264! \n"; response.infoLog += "☑File is already in h264! \n";
} }
/// ///
if (hasSubs) { if (hasSubs) {
response.infoLog += "☒File has subs \n"; response.infoLog += "☒File has subs \n";
response.preset = ",-sn -map 0 -c copy"; response.preset = ",-sn -map 0 -c copy";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true; response.FFmpegMode = true;
return response; return response;
} else { } else {
response.infoLog += "☑File has no subs \n"; response.infoLog += "☑File has no subs \n";
} }
if ( if (
file.meta.Title != "undefined" && file.meta.Title != "undefined" &&
!jsonString.includes("aac") && !jsonString.includes("aac") &&
hasSubs hasSubs
) { ) {
response.infoLog += "☒File has title metadata and no aac and subs \n"; response.infoLog += "☒File has title metadata and no aac and subs \n";
response.preset = ",-map_metadata -1 -map 0 -c copy"; response.preset = ",-map_metadata -1 -map 0 -c copy";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true; response.FFmpegMode = true;
return response; return response;
} }
if (!jsonString.includes("aac") && hasSubs) { if (!jsonString.includes("aac") && hasSubs) {
response.infoLog += "☒File has no aac track and has subs \n"; response.infoLog += "☒File has no aac track and has subs \n";
response.preset = response.preset =
",-sn -map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 aac -b:a:0 192k -ac 2"; ",-sn -map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 aac -b:a:0 192k -ac 2";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true; response.FFmpegMode = true;
return response; return response;
} }
if (file.meta.Title != "undefined" && hasSubs) { if (file.meta.Title != "undefined" && hasSubs) {
response.infoLog += "☒File has title and has subs \n"; response.infoLog += "☒File has title and has subs \n";
response.preset = ",-sn -map_metadata -1 -map 0 -c copy"; response.preset = ",-sn -map_metadata -1 -map 0 -c copy";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true; response.FFmpegMode = true;
return response; return response;
} }
/// ///
if (file.meta.Title != undefined) { if (file.meta.Title != undefined) {
response.infoLog += "☒File has title metadata \n"; response.infoLog += "☒File has title metadata \n";
response.preset = ",-map_metadata -1 -map 0 -c copy"; response.preset = ",-map_metadata -1 -map 0 -c copy";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true; response.FFmpegMode = true;
return response; return response;
} else { } else {
response.infoLog += "☑File has no title metadata"; response.infoLog += "☑File has no title metadata";
} }
if (!jsonString.includes("aac")) { if (!jsonString.includes("aac")) {
response.infoLog += "☒File has no aac track \n"; response.infoLog += "☒File has no aac track \n";
response.preset = response.preset =
",-map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 aac -b:a:0 192k -ac 2"; ",-map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 aac -b:a:0 192k -ac 2";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true; response.FFmpegMode = true;
return response; return response;
} else { } else {
response.infoLog += "☑File has aac track \n"; response.infoLog += "☑File has aac track \n";
} }
response.infoLog += "☑File meets conditions! \n"; response.infoLog += "☑File meets conditions! \n";
return response; return response;
} }
} }
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -1,8 +1,4 @@
module.exports.details = function details() { module.exports.details = function details() {
return { return {
id: "Tdarr_Plugin_a9hd_FFMPEG_Transcode_Specific_Audio_Stream_Codecs", id: "Tdarr_Plugin_a9hd_FFMPEG_Transcode_Specific_Audio_Stream_Codecs",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -12,10 +8,10 @@ module.exports.details = function details() {
Description: `[TESTING][Contains built-in filter] Transcode audio streams with specific codecs into another codec. \n\n`, Description: `[TESTING][Contains built-in filter] Transcode audio streams with specific codecs into another codec. \n\n`,
Version: "1.00", Version: "1.00",
Link: "", Link: "",
Tags:'pre-processing,audio only,ffmpeg,configurable', Tags: "pre-processing,audio only,ffmpeg,configurable",
Inputs: [ Inputs: [
{ {
name: 'codecs_to_transcode', name: "codecs_to_transcode",
tooltip: `Specifiy the codecs which you'd like to transcode tooltip: `Specifiy the codecs which you'd like to transcode
\\nExample:\\n \\nExample:\\n
@ -30,10 +26,10 @@ module.exports.details = function details() {
` `,
}, },
{ {
name: 'codec', name: "codec",
tooltip: `Specify the codec you'd like to transcode into: tooltip: `Specify the codec you'd like to transcode into:
\\n aac \\n aac
@ -52,98 +48,74 @@ module.exports.details = function details() {
` `,
} },
] ],
} };
};
}
module.exports.plugin = function plugin(file, librarySettings, inputs) { module.exports.plugin = function plugin(file, librarySettings, inputs) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mp4', container: ".mp4",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: false, reQueueAfter: false,
infoLog: '', infoLog: "",
};
}
if (inputs.codecs_to_transcode === undefined if (inputs.codecs_to_transcode === undefined || inputs.codec === undefined) {
|| inputs.codec === undefined response.processFile = false;
) { response.infoLog += "☒ Inputs not entered! \n";
return response;
response.processFile = false
response.infoLog += "☒ Inputs not entered! \n"
return response
} }
var encoder = inputs.codec;
var encoder = inputs.codec if (encoder == "mp3") {
encoder = `libmp3lame`;
if (encoder == 'mp3') { } else if (encoder == "dts") {
encoder = `libmp3lame` encoder = `dca`;
} else if (encoder == 'dts') {
encoder = `dca`
} }
var codecs_to_transcode = inputs.codecs_to_transcode.split(",");
var hasStreamsToTranscode = false;
var ffmpegCommand = `, -c copy -map 0:v `;
var codecs_to_transcode = inputs.codecs_to_transcode.split(',')
var hasStreamsToTranscode = false
var ffmpegCommand = `, -c copy -map 0:v `
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
if (
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" &&
file.ffProbeData.streams[i].codec_name && file.ffProbeData.streams[i].codec_name &&
codecs_to_transcode.includes(file.ffProbeData.streams[i].codec_name.toLowerCase()) codecs_to_transcode.includes(
file.ffProbeData.streams[i].codec_name.toLowerCase()
)
) { ) {
ffmpegCommand += ` -map 0:${i} -c:${i} ${encoder} `;
ffmpegCommand += ` -map 0:${i} -c:${i} ${encoder} ` hasStreamsToTranscode = true;
hasStreamsToTranscode = true
} }
} }
ffmpegCommand += ` -map 0:s? -map 0:d? `;
ffmpegCommand += ` -map 0:s? -map 0:d? ` console.log;
console.log
if (hasStreamsToTranscode == false) { if (hasStreamsToTranscode == false) {
response.processFile = false;
response.processFile = false response.infoLog +=
response.infoLog += "☑ File does not have any streams that need to be transcoded! \n" "☑ File does not have any streams that need to be transcoded! \n";
return response return response;
} else { } else {
response.processFile = true; response.processFile = true;
response.preset = ffmpegCommand response.preset = ffmpegCommand;
response.container = '.' + file.container response.container = "." + file.container;
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += `☒ File has streams which aren't in desired codec! \n` response.infoLog += `☒ File has streams which aren't in desired codec! \n`;
return response return response;
} }
} };

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_b38x_Nosirus_h265_aac_no_meta", id: "Tdarr_Plugin_b38x_Nosirus_h265_aac_no_meta",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,121 +7,98 @@ function details() {
Description: `[Contains built-in filter] If the file is not in h265 it will be trancoded into h265 with FFmpeg using the following command '-e x265 -q 22 --encoder-preset slow --all-audio --all-subtitles copy:aac -E fdk_aac -Q 4 -x aq-mode=3'. If no aac, aac track will be added. Subtitles are kept. Metadata is removed.\n\n Description: `[Contains built-in filter] If the file is not in h265 it will be trancoded into h265 with FFmpeg using the following command '-e x265 -q 22 --encoder-preset slow --all-audio --all-subtitles copy:aac -E fdk_aac -Q 4 -x aq-mode=3'. If no aac, aac track will be added. Subtitles are kept. Metadata is removed.\n\n
`, `,
Version: "1.01", Version: "1.01",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_b38x_Nosirus_h265_aac_no_meta.js", Link:
Tags:'pre-processing,ffmpeg,h265,', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_b38x_Nosirus_h265_aac_no_meta.js",
} Tags: "pre-processing,ffmpeg,h265,",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mp4', container: ".mp4",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: false, reQueueAfter: false,
infoLog: '', infoLog: "",
};
}
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
if (file.ffProbeData.streams[0].codec_name != "hevc") {
if(file.ffProbeData.streams[0].codec_name != 'hevc'){
response.processFile = true; response.processFile = true;
response.preset = ', -map 0 -c copy -c:v:0 libx265 -preset:v slow -pix_fmt yuv420p10le -x265-params "crf=22:aq-mode=3"' response.preset =
response.container = '.mkv' ', -map 0 -c copy -c:v:0 libx265 -preset:v slow -pix_fmt yuv420p10le -x265-params "crf=22:aq-mode=3"';
response.FFmpegMode = true response.container = ".mkv";
response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File is not in hevc! \n" response.infoLog += "☒File is not in hevc! \n";
return response return response;
} else {
}else{ response.infoLog += "☑File is already in hevc! \n";
response.infoLog += "☑File is already in hevc! \n" }
}
var audioIdx = -1 var audioIdx = -1;
var ffmpegCommandInsert = '' var ffmpegCommandInsert = "";
var hasnonAACTrack = false var hasnonAACTrack = false;
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
audioIdx++ audioIdx++;
} }
} catch (err) { } } catch (err) {}
try { try {
if (file.ffProbeData.streams[i].codec_name !== 'aac' && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" ) { if (
ffmpegCommandInsert += ` -c:a:${audioIdx} aac -vbr 4 ` file.ffProbeData.streams[i].codec_name !== "aac" &&
hasnonAACTrack = true file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio"
) {
ffmpegCommandInsert += ` -c:a:${audioIdx} aac -vbr 4 `;
hasnonAACTrack = true;
} }
} catch (err) { } } catch (err) {}
} }
var ffmpegCommand = `,-map 0 -c:v copy -c:a copy ${ffmpegCommandInsert} -c:s copy -c:d copy` var ffmpegCommand = `,-map 0 -c:v copy -c:a copy ${ffmpegCommandInsert} -c:s copy -c:d copy`;
if (hasnonAACTrack == true) { if (hasnonAACTrack == true) {
response.processFile = true; response.processFile = true;
response.preset = ffmpegCommand response.preset = ffmpegCommand;
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒ File has audio which is not in aac! \n" response.infoLog += "☒ File has audio which is not in aac! \n";
return response return response;
} else { } else {
response.infoLog += "☑ All audio streams are in aac! \n" response.infoLog += "☑ All audio streams are in aac! \n";
} }
if (file.meta.Title != undefined) { if (file.meta.Title != undefined) {
response.infoLog += "☒File has title metadata \n";
response.infoLog += "☒File has title metadata \n" response.preset =
response.preset = ',-metadata title="" -metadata comment="" -map 0 -c copy' ',-metadata title="" -metadata comment="" -map 0 -c copy';
response.container = '.mkv' response.container = ".mkv";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} else { } else {
response.infoLog += "☑File has no title metadata \n" response.infoLog += "☑File has no title metadata \n";
} }
response.infoLog += "☑File meets conditions! \n" response.infoLog += "☑File meets conditions! \n";
return response return response;
} }
} }

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_b39x_the1poet_surround_sound_to_ac3", id: "Tdarr_Plugin_b39x_the1poet_surround_sound_to_ac3",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,92 +7,73 @@ function details() {
Description: `[Contains built-in filter] If the file has surround sound tracks not in ac3, they will be converted to ac3. \n\n Description: `[Contains built-in filter] If the file has surround sound tracks not in ac3, they will be converted to ac3. \n\n
`, `,
Version: "1.00", Version: "1.00",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_b39x_the1poet_surround_sound_to_ac3.js", Link:
Tags:'pre-processing,ffmpeg,audio only,', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_b39x_the1poet_surround_sound_to_ac3.js",
} Tags: "pre-processing,ffmpeg,audio only,",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mp4', container: ".mp4",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: false, reQueueAfter: false,
infoLog: '', infoLog: "",
};
}
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
var audioIdx = -1;
var ffmpegCommandInsert = "";
var audioIdx = -1 var hasnonAC3SurroundTrack = false;
var ffmpegCommandInsert = ''
var hasnonAC3SurroundTrack = false
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
audioIdx++ audioIdx++;
} }
} catch (err) { } } catch (err) {}
try { try {
if ( file.ffProbeData.streams[i].channels >= 6 && file.ffProbeData.streams[i].codec_name !== 'ac3' && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" ) { if (
ffmpegCommandInsert += ` -c:a:${audioIdx} ac3 ` file.ffProbeData.streams[i].channels >= 6 &&
hasnonAC3SurroundTrack = true file.ffProbeData.streams[i].codec_name !== "ac3" &&
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio"
) {
ffmpegCommandInsert += ` -c:a:${audioIdx} ac3 `;
hasnonAC3SurroundTrack = true;
} }
} catch (err) { } } catch (err) {}
} }
var ffmpegCommand = `,-map 0 -c:v copy -c:a copy ${ffmpegCommandInsert} -c:s copy -c:d copy` var ffmpegCommand = `,-map 0 -c:v copy -c:a copy ${ffmpegCommandInsert} -c:s copy -c:d copy`;
if (hasnonAC3SurroundTrack == true) { if (hasnonAC3SurroundTrack == true) {
response.processFile = true; response.processFile = true;
response.preset = ffmpegCommand response.preset = ffmpegCommand;
response.container = '.' + file.container response.container = "." + file.container;
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒ File has surround audio which is not in ac3! \n" response.infoLog += "☒ File has surround audio which is not in ac3! \n";
return response return response;
} else { } else {
response.infoLog += "☑ All surround audio streams are in aac! \n" response.infoLog += "☑ All surround audio streams are in aac! \n";
} }
response.infoLog += "☑File meets conditions! \n";
return response;
response.infoLog += "☑File meets conditions! \n"
return response
} }
} }

@ -1,20 +1,20 @@
module.exports.details = function details() { module.exports.details = function details() {
return {
return { id: "Tdarr_Plugin_c0r1_SetDefaultAudioStream",
id: "Tdarr_Plugin_c0r1_SetDefaultAudioStream", Stage: "Pre-processing",
Stage: "Pre-processing", Name: "Set Default Audio Stream (Based On Channel Count)",
Name: "Set Default Audio Stream (Based On Channel Count)", Type: "Audio",
Type: "Audio", Operation: "Transcode",
Operation: "Transcode", Description: `This plugin will set an audio channel (2.0, 5.1, 7.1) to default and remove default from all other audio streams \n\n`,
Description: `This plugin will set an audio channel (2.0, 5.1, 7.1) to default and remove default from all other audio streams \n\n`, Version: "0.1.0a",
Version: "0.1.0a", Link:
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_c0r1_SetDefaultAudioStream.js", "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_c0r1_SetDefaultAudioStream.js",
Tags:"audio only,ffmpeg,configurable", Tags: "audio only,ffmpeg,configurable",
Inputs: [ Inputs: [
{ {
name: 'channels', name: "channels",
tooltip: `Desired audio channel number. tooltip: `Desired audio channel number.
\\nExample:\\n \\nExample:\\n
@ -26,84 +26,86 @@ module.exports.details = function details() {
\\nExample:\\n \\nExample:\\n
8` 8`,
}, },
] ],
};
} };
}
module.exports.plugin = function plugin(file, librarySettings, inputs) { module.exports.plugin = function plugin(file, librarySettings, inputs) {
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.' + file.container, container: "." + file.container,
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
infoLog: '', infoLog: "",
} };
var shouldProcess = false var shouldProcess = false;
var defaultAudioStreams = 0 var defaultAudioStreams = 0;
var matchingAudioStreams = 0 var matchingAudioStreams = 0;
var defaultSet = false var defaultSet = false;
var ffmpegCommandInsert = '' var ffmpegCommandInsert = "";
// Check if default audio stream matches user's channel selection
// Check if default audio stream matches user's channel selection for (var i = 0; i < file.ffProbeData.streams.length; i++) {
for (var i = 0; i < file.ffProbeData.streams.length; i++) { if (
if(file.ffProbeData.streams[i].codec_type.toLowerCase() === "audio" && file.ffProbeData.streams[i].codec_type.toLowerCase() === "audio" &&
file.ffProbeData.streams[i].channels == inputs.channels) file.ffProbeData.streams[i].channels == inputs.channels
{ ) {
matchingAudioStreams++ matchingAudioStreams++;
if(file.ffProbeData.streams[i].disposition.default === 1){ if (file.ffProbeData.streams[i].disposition.default === 1) {
defaultAudioStreams++; defaultAudioStreams++;
} }
}
} }
}
// build command
for (var i = 0; i < file.ffProbeData.streams.length; i++) { // build command
if(file.ffProbeData.streams[i].codec_type.toLowerCase() === "audio") for (var i = 0; i < file.ffProbeData.streams.length; i++) {
{ if (file.ffProbeData.streams[i].codec_type.toLowerCase() === "audio") {
if(file.ffProbeData.streams[i].channels == inputs.channels) if (file.ffProbeData.streams[i].channels == inputs.channels) {
{ if (!defaultSet) {
if(!defaultSet){ ffmpegCommandInsert += `-disposition:${i} default `;
ffmpegCommandInsert += `-disposition:${i} default ` defaultSet = true;
defaultSet = true } else {
} else { ffmpegCommandInsert += `-disposition:${i} 0 `;
ffmpegCommandInsert += `-disposition:${i} 0 `
}
} else {
ffmpegCommandInsert += `-disposition:${i} 0 `
}
} }
} else {
ffmpegCommandInsert += `-disposition:${i} 0 `;
}
} }
}
// Only process when there is a matching stream and
// when there is either no default or more than 1 default stream set // Only process when there is a matching stream and
if(matchingAudioStreams >= 1 && defaultAudioStreams !== 1) { // when there is either no default or more than 1 default stream set
shouldProcess = true; if (matchingAudioStreams >= 1 && defaultAudioStreams !== 1) {
response.infoLog += "☒ Matching audio stream is not set to default. \n" shouldProcess = true;
} response.infoLog += "☒ Matching audio stream is not set to default. \n";
}
if (shouldProcess) {
response.processFile = true; if (shouldProcess) {
response.reQueueAfter = true; response.processFile = true;
response.preset = `,-map 0 -c copy ${ffmpegCommandInsert}`; response.reQueueAfter = true;
response.infoLog += "☒ Setting " + inputs.channels + " channel matching audio stream to default. Remove default from all other audio streams \n" response.preset = `,-map 0 -c copy ${ffmpegCommandInsert}`;
response.infoLog +=
"☒ Setting " +
inputs.channels +
" channel matching audio stream to default. Remove default from all other audio streams \n";
} else {
if (matchingAudioStreams < 1) {
response.infoLog +=
"☑ No " + inputs.channels + " channel audio stream exists. \n ";
} else if (defaultAudioStreams === 1) {
response.infoLog +=
"☑ Default " +
inputs.channels +
" channel audio stream already exists. \n ";
} else { } else {
if(matchingAudioStreams < 1){ response.infoLog += "☑ Unexpected: Did not process \n ";
response.infoLog += "☑ No " + inputs.channels + " channel audio stream exists. \n "
} else if (defaultAudioStreams === 1){
response.infoLog += "☑ Default " + inputs.channels + " channel audio stream already exists. \n "
} else {
response.infoLog += "☑ Unexpected: Did not process \n "
}
response.processFile = false;
} }
return response
} response.processFile = false;
}
return response;
};

@ -4,189 +4,193 @@ function details() {
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "Tiered FFMPEG NVENC settings depending on resolution", Name: "Tiered FFMPEG NVENC settings depending on resolution",
Type: "Video", Type: "Video",
Operation:"Transcode", Operation: "Transcode",
Description: `[Contains built-in filter] This plugin uses different FFMPEG NVENC transcoding settings for 480p,576p,720p,1080p and 4KUHD. If files are not in hevc they will be transcoded. The output container is mkv. \n\n`, Description: `[Contains built-in filter] This plugin uses different FFMPEG NVENC transcoding settings for 480p,576p,720p,1080p and 4KUHD. If files are not in hevc they will be transcoded. The output container is mkv. \n\n`,
Version: "1.09", Version: "1.09",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_d5d3_iiDrakeii_FFMPEG_NVENC_Tiered_MKV.js", Link:
Tags:'pre-processing,ffmpeg,video only,nvenc h265', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_d5d3_iiDrakeii_FFMPEG_NVENC_Tiered_MKV.js",
} Tags: "pre-processing,ffmpeg,video only,nvenc h265",
};
} }
function plugin(file) { function plugin(file) {
var transcode = 0; //if this var changes to 1 the file will be transcoded var transcode = 0; //if this var changes to 1 the file will be transcoded
var bitrateprobe = 0; //bitrate from ffprobe var bitrateprobe = 0; //bitrate from ffprobe
var bitratetarget = 0; var bitratetarget = 0;
var bitratemax = 0; var bitratemax = 0;
var bitratecheck = 0; var bitratecheck = 0;
var subcli = `-c:s copy`; var subcli = `-c:s copy`;
var maxmux = ''; var maxmux = "";
var map = '-map 0' var map = "-map 0";
//default values that will be returned //default values that will be returned
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mkv', container: ".mkv",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: true, reQueueAfter: true,
infoLog: '', infoLog: "",
maxmux: false, maxmux: false,
} };
//check if the file is a video, if not the function will be stopped immediately //check if the file is a video, if not the function will be stopped immediately
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
response.processFile = false response.processFile = false;
response.infoLog += "☒File is not a video! \n" response.infoLog += "☒File is not a video! \n";
return response return response;
} } else {
else { bitrateprobe = file.ffProbeData.streams[0].bit_rate;
bitrateprobe = file.ffProbeData.streams[0].bit_rate response.infoLog += "☑File is a video! \n";
response.infoLog += "☑File is a video! \n"
} }
//check if the file is already hevc, it will not be transcoded if true and the function will be stopped immediately //check if the file is already hevc, it will not be transcoded if true and the function will be stopped immediately
if (file.ffProbeData.streams[0].codec_name == 'hevc') { if (file.ffProbeData.streams[0].codec_name == "hevc") {
response.processFile = false response.processFile = false;
response.infoLog += "☑File is already in hevc! \n" response.infoLog += "☑File is already in hevc! \n";
return response return response;
}
//codec will be checked so it can be transcoded correctly
if (file.video_codec_name == 'h263') {
response.preset = `-c:v h263_cuvid`
} }
else if (file.video_codec_name == 'h264') {
if (file.ffProbeData.streams[0].profile != 'High 10') { //Remove HW Decoding for High 10 Profile //codec will be checked so it can be transcoded correctly
response.preset = `-c:v h264_cuvid` if (file.video_codec_name == "h263") {
response.preset = `-c:v h263_cuvid`;
} else if (file.video_codec_name == "h264") {
if (file.ffProbeData.streams[0].profile != "High 10") {
//Remove HW Decoding for High 10 Profile
response.preset = `-c:v h264_cuvid`;
} }
} else if (file.video_codec_name == "mjpeg") {
response.preset = `c:v mjpeg_cuvid`;
} else if (file.video_codec_name == "mpeg1") {
response.preset = `-c:v mpeg1_cuvid`;
} else if (file.video_codec_name == "mpeg2") {
response.preset = `-c:v mpeg2_cuvid`;
}
// skipping this one because it's empty
// else if (file.video_codec_name == 'mpeg4') {
// response.preset = ``
// }
else if (file.video_codec_name == "vc1") {
response.preset = `-c:v vc1_cuvid`;
} else if (file.video_codec_name == "vp8") {
response.preset = `-c:v vp8_cuvid`;
} else if (file.video_codec_name == "vp9") {
response.preset = `-c:v vp9_cuvid`;
} }
else if (file.video_codec_name == 'mjpeg') {
response.preset = `c:v mjpeg_cuvid` //Set Subtitle Var before adding encode cli
}
else if (file.video_codec_name == 'mpeg1') {
response.preset = `-c:v mpeg1_cuvid`
}
else if (file.video_codec_name == 'mpeg2') {
response.preset = `-c:v mpeg2_cuvid`
}
// skipping this one because it's empty
// else if (file.video_codec_name == 'mpeg4') {
// response.preset = ``
// }
else if (file.video_codec_name == 'vc1') {
response.preset = `-c:v vc1_cuvid`
}
else if (file.video_codec_name == 'vp8') {
response.preset = `-c:v vp8_cuvid`
}
else if (file.video_codec_name == 'vp9') {
response.preset = `-c:v vp9_cuvid`
}
//Set Subtitle Var before adding encode cli
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
if (file.ffProbeData.streams[i].codec_name.toLowerCase() == "mov_text" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" ) { if (
subcli = `-c:s srt` file.ffProbeData.streams[i].codec_name.toLowerCase() == "mov_text" &&
} file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle"
} ) {
catch (err) { } subcli = `-c:s srt`;
//mitigate TrueHD audio causing Too many packets error }
try { } catch (err) {}
if (file.ffProbeData.streams[i].codec_name.toLowerCase() == "truehd" || (file.ffProbeData.streams[i].codec_name.toLowerCase() == "dts" && file.ffProbeData.streams[i].profile.toLowerCase() == "dts-hd ma") || file.ffProbeData.streams[i].codec_name.toLowerCase() == "aac" && file.ffProbeData.streams[i].sample_rate.toLowerCase() == "44100" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" ) { //mitigate TrueHD audio causing Too many packets error
maxmux = ` -max_muxing_queue_size 9999` try {
} if (
} file.ffProbeData.streams[i].codec_name.toLowerCase() == "truehd" ||
catch (err) { } (file.ffProbeData.streams[i].codec_name.toLowerCase() == "dts" &&
//mitigate errors due to embeded pictures file.ffProbeData.streams[i].profile.toLowerCase() == "dts-hd ma") ||
try { (file.ffProbeData.streams[i].codec_name.toLowerCase() == "aac" &&
if ((file.ffProbeData.streams[i].codec_name.toLowerCase() == "png" || file.ffProbeData.streams[i].codec_name.toLowerCase() == "bmp" || file.ffProbeData.streams[i].codec_name.toLowerCase() == "mjpeg") && file.ffProbeData.streams[i].codec_type.toLowerCase() == "video" ) { file.ffProbeData.streams[i].sample_rate.toLowerCase() == "44100" &&
map = `-map 0:v:0 -map 0:a -map 0:s?` file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio")
} ) {
} maxmux = ` -max_muxing_queue_size 9999`;
catch (err) { } }
} } catch (err) {}
//file will be encoded if the resolution is 480p or 576p //mitigate errors due to embeded pictures
//codec will be checked so it can be transcoded correctly try {
if (file.video_resolution === "480p" || file.video_resolution === "576p" ) { if (
bitratecheck = 1000000; (file.ffProbeData.streams[i].codec_name.toLowerCase() == "png" ||
if(bitrateprobe != null && bitrateprobe < bitratecheck) { file.ffProbeData.streams[i].codec_name.toLowerCase() == "bmp" ||
bitratetarget = parseInt((bitrateprobe * .8) / 1000); // Lower Bitrate to 60% of original and convert to KB file.ffProbeData.streams[i].codec_name.toLowerCase() == "mjpeg") &&
bitratemax = bitratetarget + 500; // Set max bitrate to 6MB Higher file.ffProbeData.streams[i].codec_type.toLowerCase() == "video"
} ) {
else { map = `-map 0:v:0 -map 0:a -map 0:s?`;
bitratetarget = 1000; }
bitratemax = 1500; } catch (err) {}
}
//file will be encoded if the resolution is 480p or 576p
//codec will be checked so it can be transcoded correctly
if (file.video_resolution === "480p" || file.video_resolution === "576p") {
bitratecheck = 1000000;
if (bitrateprobe != null && bitrateprobe < bitratecheck) {
bitratetarget = parseInt((bitrateprobe * 0.8) / 1000); // Lower Bitrate to 60% of original and convert to KB
bitratemax = bitratetarget + 500; // Set max bitrate to 6MB Higher
} else {
bitratetarget = 1000;
bitratemax = 1500;
} }
response.preset += `,${map} -dn -c:v hevc_nvenc -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 29 -b:v ${bitratetarget}k -maxrate:v 1500k -preset slow -rc-lookahead 32 -spatial_aq:v 1 -aq-strength:v 8 -a53cc 0 -c:a copy ${subcli}${maxmux}`; response.preset += `,${map} -dn -c:v hevc_nvenc -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 29 -b:v ${bitratetarget}k -maxrate:v 1500k -preset slow -rc-lookahead 32 -spatial_aq:v 1 -aq-strength:v 8 -a53cc 0 -c:a copy ${subcli}${maxmux}`;
transcode = 1; transcode = 1;
} }
//file will be encoded if the resolution is 720p //file will be encoded if the resolution is 720p
//codec will be checked so it can be transcoded correctly //codec will be checked so it can be transcoded correctly
if(file.video_resolution === "720p") { if (file.video_resolution === "720p") {
bitratecheck = 2000000; bitratecheck = 2000000;
if(bitrateprobe != null && bitrateprobe < bitratecheck) { if (bitrateprobe != null && bitrateprobe < bitratecheck) {
bitratetarget = parseInt((bitrateprobe * .8) / 1000); // Lower Bitrate to 60% of original and convert to KB bitratetarget = parseInt((bitrateprobe * 0.8) / 1000); // Lower Bitrate to 60% of original and convert to KB
bitratemax = bitratetarget + 2000; // Set max bitrate to 6MB Higher bitratemax = bitratetarget + 2000; // Set max bitrate to 6MB Higher
} } else {
else { bitratetarget = 2000;
bitratetarget = 2000; bitratemax = 4000;
bitratemax = 4000;
} }
response.preset += `,${map} -dn -c:v hevc_nvenc -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 30 -b:v ${bitratetarget}k -maxrate:v ${bitratemax}k -preset slow -rc-lookahead 32 -spatial_aq:v 1 -aq-strength:v 8 -a53cc 0 -c:a copy ${subcli}${maxmux}`; response.preset += `,${map} -dn -c:v hevc_nvenc -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 30 -b:v ${bitratetarget}k -maxrate:v ${bitratemax}k -preset slow -rc-lookahead 32 -spatial_aq:v 1 -aq-strength:v 8 -a53cc 0 -c:a copy ${subcli}${maxmux}`;
transcode = 1; transcode = 1;
} }
//file will be encoded if the resolution is 1080p //file will be encoded if the resolution is 1080p
//codec will be checked so it can be transcoded correctly //codec will be checked so it can be transcoded correctly
if(file.video_resolution === "1080p") { if (file.video_resolution === "1080p") {
bitratecheck = 2500000; bitratecheck = 2500000;
if(bitrateprobe != null && bitrateprobe < bitratecheck) { if (bitrateprobe != null && bitrateprobe < bitratecheck) {
bitratetarget = parseInt((bitrateprobe * .8) / 1000); // Lower Bitrate to 60% of original and convert to KB bitratetarget = parseInt((bitrateprobe * 0.8) / 1000); // Lower Bitrate to 60% of original and convert to KB
bitratemax = bitratetarget + 2500; // Set max bitrate to 6MB Higher bitratemax = bitratetarget + 2500; // Set max bitrate to 6MB Higher
} } else {
else { bitratetarget = 2500;
bitratetarget = 2500; bitratemax = 5000;
bitratemax = 5000;
} }
response.preset += `,${map} -dn -c:v hevc_nvenc -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:V 31 -b:v ${bitratetarget}k -maxrate:v ${bitratemax}k -preset slow -rc-lookahead 32 -spatial_aq:v 1 -aq-strength:v 8 -a53cc 0 -c:a copy ${subcli}${maxmux}`; response.preset += `,${map} -dn -c:v hevc_nvenc -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:V 31 -b:v ${bitratetarget}k -maxrate:v ${bitratemax}k -preset slow -rc-lookahead 32 -spatial_aq:v 1 -aq-strength:v 8 -a53cc 0 -c:a copy ${subcli}${maxmux}`;
transcode = 1; transcode = 1;
} }
//file will be encoded if the resolution is 4K //file will be encoded if the resolution is 4K
//codec will be checked so it can be transcoded correctly //codec will be checked so it can be transcoded correctly
if(file.video_resolution === "4KUHD") { if (file.video_resolution === "4KUHD") {
bitratecheck = 14000000; bitratecheck = 14000000;
if(bitrateprobe != null && bitrateprobe < bitratecheck) { if (bitrateprobe != null && bitrateprobe < bitratecheck) {
bitratetarget = parseInt((bitrateprobe * .7) / 1000); // Lower Bitrate to 60% of original and convert to KB bitratetarget = parseInt((bitrateprobe * 0.7) / 1000); // Lower Bitrate to 60% of original and convert to KB
bitratemax = bitratetarget + 6000; // Set max bitrate to 6MB Higher bitratemax = bitratetarget + 6000; // Set max bitrate to 6MB Higher
} else {
bitratetarget = 14000;
bitratemax = 20000;
} }
else { response.preset += `,${map} -dn -c:v hevc_nvenc -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 31 -b:v ${bitratetarget}k -maxrate:v ${bitratemax}k -preset slow -rc-lookahead 32 -spatial_aq:v 1 -aq-strength:v 8 -a53cc 0 -c:a copy ${subcli}${maxmux}`;
bitratetarget = 14000; transcode = 1;
bitratemax = 20000;
}
response.preset += `,${map} -dn -c:v hevc_nvenc -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 31 -b:v ${bitratetarget}k -maxrate:v ${bitratemax}k -preset slow -rc-lookahead 32 -spatial_aq:v 1 -aq-strength:v 8 -a53cc 0 -c:a copy ${subcli}${maxmux}`;
transcode = 1;
} }
//check if the file is eligible for transcoding //check if the file is eligible for transcoding
//if true the neccessary response values will be changed //if true the neccessary response values will be changed
if (transcode == 1) { if (transcode == 1) {
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += `☒File is ${file.video_resolution}!\n` response.infoLog += `☒File is ${file.video_resolution}!\n`;
response.infoLog += `☒File is not hevc!\n` response.infoLog += `☒File is not hevc!\n`;
response.infoLog += `☒File bitrate is ${parseInt(bitrateprobe / 1000)}kb!\n` response.infoLog += `☒File bitrate is ${parseInt(
if(bitrateprobe < bitratecheck) { bitrateprobe / 1000
response.infoLog += `File bitrate is LOWER than the Default Target Bitrate!\n` )}kb!\n`;
} if (bitrateprobe < bitratecheck) {
else { response.infoLog += `File bitrate is LOWER than the Default Target Bitrate!\n`;
response.infoLog += `File bitrate is HIGHER than the Default Target Bitrate!\n` } else {
} response.infoLog += `File bitrate is HIGHER than the Default Target Bitrate!\n`;
response.infoLog += `☒Target Bitrate set to ${bitratetarget}kb!\n` }
response.infoLog += `File is being transcoded!\n` response.infoLog += `☒Target Bitrate set to ${bitratetarget}kb!\n`;
} response.infoLog += `File is being transcoded!\n`;
return response
} }
return response;
}
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -4,75 +4,75 @@ function details() {
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "Mjpeg Stream False Not A Video Fixer", Name: "Mjpeg Stream False Not A Video Fixer",
Type: "Video", Type: "Video",
Operation:"", Operation: "",
Description: `Checks if file is not a video file due to Mjpeg stream. Removes Mjpeg Stream \n\n`, Description: `Checks if file is not a video file due to Mjpeg stream. Removes Mjpeg Stream \n\n`,
Version: "1.00", Version: "1.00",
Tags:'pre-processing,ffmpeg,' Tags: "pre-processing,ffmpeg,",
} };
} }
function plugin(file) { function plugin(file) {
var transcode = 0; //if this var changes to 1 the file will be transcoded var transcode = 0; //if this var changes to 1 the file will be transcoded
//default values that will be returned //default values that will be returned
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mp4', container: ".mp4",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: true, reQueueAfter: true,
infoLog: '' infoLog: "",
} };
response.container = '.' + file.container response.container = "." + file.container;
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
//check for mjpeg streams and set the preset if mjpeg streams are found //check for mjpeg streams and set the preset if mjpeg streams are found
try { try {
if ((file.ffProbeData.streams[i].codec_name.toLowerCase() == "mjpeg") && file.ffProbeData.streams[i].codec_type.toLowerCase() == "video" ) { if (
response.preset = `,-map 0 -map -0:v:1 -c:v copy -c:a copy -c:s copy` file.ffProbeData.streams[i].codec_name.toLowerCase() == "mjpeg" &&
response.infoLog = "☒File is not a video but has Mjpeg Stream! \n" file.ffProbeData.streams[i].codec_type.toLowerCase() == "video"
} ) {
} response.preset = `,-map 0 -map -0:v:1 -c:v copy -c:a copy -c:s copy`;
catch (err) { } response.infoLog = "☒File is not a video but has Mjpeg Stream! \n";
}
} catch (err) {}
} }
//If preset is not set check if file is video and stop (reque if it is a video) //If preset is not set check if file is video and stop (reque if it is a video)
if (response.preset != `,-map 0 -map -0:v:1 -c:v copy -c:a copy -c:s copy`) { if (response.preset != `,-map 0 -map -0:v:1 -c:v copy -c:a copy -c:s copy`) {
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video!") console.log("File is not video!");
response.infoLog += " File is not video\n" response.infoLog += " File is not video\n";
response.processFile = false; response.processFile = false;
return response return response;
} } else {
else { response.infoLog += "☑File is a video Without Mjpeg! \n";
response.infoLog += "☑File is a video Without Mjpeg! \n" response.processFile = false;
response.processFile = false response.reQueueAfter = true;
response.reQueueAfter = true return response;
return response }
}
} }
//Process mjpeg removal if video found to not be a video and have mjpeg stream //Process mjpeg removal if video found to not be a video and have mjpeg stream
else { else {
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
transcode = 1 transcode = 1;
} } else {
else { response.infoLog += "☑File is a video With Mjpeg! \n";
response.infoLog += "☑File is a video With Mjpeg! \n" response.processFile = false;
response.processFile = false response.reQueueAfter = true;
response.reQueueAfter = true return response;
return response }
} }
} //check if the file is eligible for transcoding
//check if the file is eligible for transcoding //if true the neccessary response values will be changed
//if true the neccessary response values will be changed
if (transcode == 1) { if (transcode == 1) {
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += `Mjpeg Stream is being removed!\n` response.infoLog += `Mjpeg Stream is being removed!\n`;
} }
return response return response;
} }
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -2,15 +2,17 @@ function details() {
return { return {
id: "Tdarr_Plugin_da11_Dallas_FFmpeg_Presets_H264_MP4", id: "Tdarr_Plugin_da11_Dallas_FFmpeg_Presets_H264_MP4",
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "Dallas FFmpeg h264 mp4. Video: h264/mp4, Subs: Convert to mov_text or drop, Audio: aac", Name:
"Dallas FFmpeg h264 mp4. Video: h264/mp4, Subs: Convert to mov_text or drop, Audio: aac",
Type: "Video", Type: "Video",
Description: `This plugin transcodes into H264 with an MP4 container using the FFmpeg preset you select (slow,medium,fast,veryfast). It maintains all compatible subtitles and audio tracks. Drops picture tracks such as mjpeg\n\n`, Description: `This plugin transcodes into H264 with an MP4 container using the FFmpeg preset you select (slow,medium,fast,veryfast). It maintains all compatible subtitles and audio tracks. Drops picture tracks such as mjpeg\n\n`,
Version: "1.00", Version: "1.00",
Link: "https://github.com/JackDallas/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_da11_Dallas_FFmpeg_Presets_H264_MP4.js", Link:
Tags:'pre-processing,ffmpeg,h264,video only,configurable', "https://github.com/JackDallas/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_da11_Dallas_FFmpeg_Presets_H264_MP4.js",
Tags: "pre-processing,ffmpeg,h264,video only,configurable",
Inputs: [ Inputs: [
{ {
name: 'FFmpeg_preset', name: "FFmpeg_preset",
tooltip: `Select the FFmpeg preset you wish to use,(slow,medium,fast,veryfast). tooltip: `Select the FFmpeg preset you wish to use,(slow,medium,fast,veryfast).
\\nExample:\\n \\nExample:\\n
@ -23,24 +25,21 @@ function details() {
fast fast
\\nExample:\\n \\nExample:\\n
veryfast` veryfast`,
} },
] ],
}; };
} }
const presets = [ const presets = ["slow", "medium", "fast", "veryfast"];
"slow", "medium", "fast", "veryfast"
];
// Normalizes the preset or if invalid returns null // Normalizes the preset or if invalid returns null
function getPreset(preset) { function getPreset(preset) {
if (!preset) if (!preset) return null;
return null;
preset = preset.toLowerCase(); preset = preset.toLowerCase();
// Strip Spaces // Strip Spaces
preset = preset.replace(/\s+/g, ''); preset = preset.replace(/\s+/g, "");
if (presets.includes(preset)) { if (presets.includes(preset)) {
return preset; return preset;
@ -55,16 +54,16 @@ const BAD = false;
function plugin(file, librarySettings, inputs) { function plugin(file, librarySettings, inputs) {
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mp4', container: ".mp4",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: false, reQueueAfter: false,
infoLog: '', infoLog: "",
addInfo(status, info) { addInfo(status, info) {
this.infoLog += (status ? "☑" : "☒") + " " + info + "\n"; this.infoLog += (status ? "☑" : "☒") + " " + info + "\n";
} },
} };
// Check the file is a video // Check the file is a video
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
@ -78,12 +77,15 @@ function plugin(file, librarySettings, inputs) {
let preset = getPreset(inputs.FFmpeg_preset); let preset = getPreset(inputs.FFmpeg_preset);
if (preset === null) { if (preset === null) {
response.addInfo(BAD, `Invalid Preset, \"${inputs.FFmpeg_preset}\" please select from (slow,medium,fast,veryfast)`); response.addInfo(
BAD,
`Invalid Preset, \"${inputs.FFmpeg_preset}\" please select from (slow,medium,fast,veryfast)`
);
throw `Error: Invalid Preset, \"${inputs.FFmpeg_preset}\" please select from (slow,medium,fast,veryfast) \n` throw `Error: Invalid Preset, \"${inputs.FFmpeg_preset}\" please select from (slow,medium,fast,veryfast) \n`;
} }
var jsonString = JSON.stringify(file) var jsonString = JSON.stringify(file);
var hasSubs = false; var hasSubs = false;
var hasBadSubs = false; var hasBadSubs = false;
@ -94,12 +96,15 @@ function plugin(file, librarySettings, inputs) {
try { try {
let streamData = file.ffProbeData.streams[i]; let streamData = file.ffProbeData.streams[i];
if (streamData.codec_type.toLowerCase() == "subtitle") { if (streamData.codec_type.toLowerCase() == "subtitle") {
if (streamData.codec_name === "hdmv_pgs_subtitle" || streamData.codec_name === "dvd_subtitle") { if (
streamData.codec_name === "hdmv_pgs_subtitle" ||
streamData.codec_name === "dvd_subtitle"
) {
hasBadSubs = true; hasBadSubs = true;
// Drop incompatible subs // Drop incompatible subs
subMap += " -map -0:" + streamData.index + " "; subMap += " -map -0:" + streamData.index + " ";
} else if (streamData.codec_name != "mov_text") { } else if (streamData.codec_name != "mov_text") {
hasSubs = true hasSubs = true;
// Keep compatible subs // Keep compatible subs
subMap += " -map 0:" + streamData.index + " "; subMap += " -map 0:" + streamData.index + " ";
} }
@ -112,9 +117,13 @@ function plugin(file, librarySettings, inputs) {
if (hasBadSubs) if (hasBadSubs)
response.addInfo(BAD, "File contains unsupported sub(s), dropping these!"); response.addInfo(BAD, "File contains unsupported sub(s), dropping these!");
if (file.ffProbeData.streams[0].codec_name != 'h264') { if (file.ffProbeData.streams[0].codec_name != "h264") {
response.addInfo(BAD, "File is not in h264!"); response.addInfo(BAD, "File is not in h264!");
response.preset = ', -map_metadata -1 -map 0:V ' + subMap + ' -map 0:a -c:v libx264 -preset medium -c:a aac -strict -2 ' + subType; response.preset =
", -map_metadata -1 -map 0:V " +
subMap +
" -map 0:a -c:v libx264 -preset medium -c:a aac -strict -2 " +
subType;
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true; response.FFmpegMode = true;
@ -123,18 +132,26 @@ function plugin(file, librarySettings, inputs) {
response.addInfo(GOOD, "File is already in h264!"); response.addInfo(GOOD, "File is already in h264!");
} }
if ((file.meta.Title != undefined) && !jsonString.includes("aac") && hasSubs) { if (file.meta.Title != undefined && !jsonString.includes("aac") && hasSubs) {
response.addInfo(BAD, "File has title metadata and no aac and subs"); response.addInfo(BAD, "File has title metadata and no aac and subs");
response.preset = ', -map_metadata -1 -map 0:v ' + subMap + ' -map 0:a -c:v copy -c:a aac -strict -2 ' + subType; response.preset =
", -map_metadata -1 -map 0:v " +
subMap +
" -map 0:a -c:v copy -c:a aac -strict -2 " +
subType;
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true; response.FFmpegMode = true;
return response return response;
} }
if (!jsonString.includes("aac") && hasSubs) { if (!jsonString.includes("aac") && hasSubs) {
response.addInfo(BAD, "File has no aac track and has subs"); response.addInfo(BAD, "File has no aac track and has subs");
response.preset = ', -map 0:v ' + subMap + ' -map 0:a -c:v copy -c:a aac -strict -2 ' + subType; response.preset =
", -map 0:v " +
subMap +
" -map 0:a -c:v copy -c:a aac -strict -2 " +
subType;
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true; response.FFmpegMode = true;
@ -143,7 +160,11 @@ function plugin(file, librarySettings, inputs) {
if (file.meta.Title != undefined && hasSubs) { if (file.meta.Title != undefined && hasSubs) {
response.addInfo(BAD, "File has title and has subs"); response.addInfo(BAD, "File has title and has subs");
response.preset = ', -map_metadata -1 -map 0:v ' + subMap + ' -map 0:a -c:v copy -c:a copy ' + subType; response.preset =
", -map_metadata -1 -map 0:v " +
subMap +
" -map 0:a -c:v copy -c:a copy " +
subType;
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true; response.FFmpegMode = true;
@ -152,7 +173,11 @@ function plugin(file, librarySettings, inputs) {
if (file.meta.Title != undefined) { if (file.meta.Title != undefined) {
response.addInfo(BAD, "File has title metadata"); response.addInfo(BAD, "File has title metadata");
response.preset = ', -map_metadata -1 -map 0:v ' + subMap + ' -map 0:a -c:v copy -c:a copy ' + subType; response.preset =
", -map_metadata -1 -map 0:v " +
subMap +
" -map 0:a -c:v copy -c:a copy " +
subType;
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true; response.FFmpegMode = true;
@ -163,7 +188,11 @@ function plugin(file, librarySettings, inputs) {
if (!jsonString.includes("aac")) { if (!jsonString.includes("aac")) {
response.addInfo(BAD, "File has no aac track"); response.addInfo(BAD, "File has no aac track");
response.preset = ', -map 0:v ' + subMap + ' -map 0:a -c:v copy -c:a aac -strict -2 ' + subType; response.preset =
", -map 0:v " +
subMap +
" -map 0:a -c:v copy -c:a aac -strict -2 " +
subType;
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true; response.FFmpegMode = true;
@ -178,16 +207,17 @@ function plugin(file, librarySettings, inputs) {
} else { } else {
response.addInfo(BAD, "File has compatible subs, copying..."); response.addInfo(BAD, "File has compatible subs, copying...");
} }
response.preset = ', -map 0:v ' + subMap + ' -map 0:a -c:v copy -c:a copy ' + subType; response.preset =
", -map 0:v " + subMap + " -map 0:a -c:v copy -c:a copy " + subType;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} else { } else {
response.addInfo(GOOD, "File has no/compatible subs"); response.addInfo(GOOD, "File has no/compatible subs");
} }
response.addInfo(GOOD, "File meets conditions!"); response.addInfo(GOOD, "File meets conditions!");
return response return response;
} }
module.exports.details = details; module.exports.details = details;

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_e3jc_Tharic_H.264_MKV_480p30_No_Subs_No_Title_Meta", id: "Tdarr_Plugin_e3jc_Tharic_H.264_MKV_480p30_No_Subs_No_Title_Meta",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,156 +7,123 @@ function details() {
Description: `[Contains built-in filter] This plugin removes subs, metadata (if a title exists) and makes sure the video is h264 480p mkv. \n\n Description: `[Contains built-in filter] This plugin removes subs, metadata (if a title exists) and makes sure the video is h264 480p mkv. \n\n
`, `,
Version: "1.00", Version: "1.00",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_e3jc_Tharic_H.264_MKV_480p30_No_Subs_No_Title_Meta.js", Link:
Tags:'pre-processing,handbrake,ffmpeg,h264' "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_e3jc_Tharic_H.264_MKV_480p30_No_Subs_No_Title_Meta.js",
} Tags: "pre-processing,handbrake,ffmpeg,h264",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false,
preset: "",
container: ".mp4",
handBrakeMode: false,
FFmpegMode: false,
reQueueAfter: false,
infoLog: "",
};
processFile : false, response.FFmpegMode = true;
preset : '',
container : '.mp4',
handBrakeMode : false,
FFmpegMode : false,
reQueueAfter : false,
infoLog : '',
}
response.FFmpegMode = true
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else {
} else { var jsonString = JSON.stringify(file);
var jsonString = JSON.stringify(file) var hasSubs = false;
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try {
var hasSubs = false if (
for (var i = 0; i < file.ffProbeData.streams.length; i++) { file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle"
) {
try { hasSubs = true;
}
if(file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle"){ } catch (err) {}
}
hasSubs = true
//
}
} catch (err) { } if (
} file.ffProbeData.streams[0].codec_name != "h264" ||
file.ffProbeData.streams[0].width > 720 ||
file.ffProbeData.streams[0].height > 480
// ) {
if(file.ffProbeData.streams[0].codec_name != 'h264' || file.ffProbeData.streams[0].width > 720 || file.ffProbeData.streams[0].height > 480 ){
response.processFile = true; response.processFile = true;
response.preset = '-Z "H.264 MKV 480p30"' response.preset = '-Z "H.264 MKV 480p30"';
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode =true response.handBrakeMode = true;
response.FFmpegMode = false response.FFmpegMode = false;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File is not h264 480p! \n" response.infoLog += "☒File is not h264 480p! \n";
return response return response;
}else{ } else {
response.infoLog += "☑File is h264 480p! \n";
response.infoLog += "☑File is h264 480p! \n" }
//
}
// if (file.meta.Title != "undefined" && hasSubs) {
if(file.meta.Title != "undefined" && hasSubs){
response.processFile = true; response.processFile = true;
response.preset = ',-sn -map_metadata -1 -map 0 -c copy' response.preset = ",-sn -map_metadata -1 -map 0 -c copy";
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode =false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File has title and has subs \n" response.infoLog += "☒File has title and has subs \n";
return response return response;
}else{ } else {
response.infoLog += "☑File has no title and has no subs \n" response.infoLog += "☑File has no title and has no subs \n";
}
}
if(file.meta.Title != undefined ){
if (file.meta.Title != undefined) {
response.processFile = true; response.processFile = true;
response.preset = ',-map_metadata -1 -map 0 -c copy' response.preset = ",-map_metadata -1 -map 0 -c copy";
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode =false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File has title metadata \n" response.infoLog += "☒File has title metadata \n";
return response return response;
} else {
response.infoLog += "☑File has no title metadata \n";
}else{ }
response.infoLog += "☑File has no title metadata \n"
}
if(hasSubs){
if (hasSubs) {
response.processFile = true; response.processFile = true;
response.preset = ',-sn -map 0 -c copy' response.preset = ",-sn -map 0 -c copy";
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode =false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File has subs \n" response.infoLog += "☒File has subs \n";
return response return response;
} else {
}else{ response.infoLog += "☑File has no subs \n";
response.infoLog += "☑File has no subs \n" }
}
if( file.container != 'mkv'){
if (file.container != "mkv") {
response.processFile = true; response.processFile = true;
response.preset = ', -map 0 -c copy' response.preset = ", -map 0 -c copy";
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode =false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File is not in mkv container! \n" response.infoLog += "☒File is not in mkv container! \n";
return response return response;
} else {
response.infoLog += "☑File is in mkv container! \n";
}else{ }
response.infoLog += "☑File is in mkv container! \n"
}
response.processFile = false;
response.infoLog += "☑File meets conditions! \n"
return response
response.processFile = false;
response.infoLog += "☑File meets conditions! \n";
return response;
} }
} }

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_e3jd_Tharic_H.264_MKV_720p30_No_Subs_No_Title_Meta", id: "Tdarr_Plugin_e3jd_Tharic_H.264_MKV_720p30_No_Subs_No_Title_Meta",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,156 +7,123 @@ function details() {
Description: `[Contains built-in filter] This plugin removes subs, metadata (if a title exists) and makes sure the video is h264 720p mkv. \n\n Description: `[Contains built-in filter] This plugin removes subs, metadata (if a title exists) and makes sure the video is h264 720p mkv. \n\n
`, `,
Version: "1.00", Version: "1.00",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_e3jd_Tharic_H.264_MKV_720p30_No_Subs_No_Title_Meta.js", Link:
Tags:'pre-processing,handbrake,ffmpeg,h264' "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_e3jd_Tharic_H.264_MKV_720p30_No_Subs_No_Title_Meta.js",
} Tags: "pre-processing,handbrake,ffmpeg,h264",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false,
preset: "",
container: ".mp4",
handBrakeMode: false,
FFmpegMode: false,
reQueueAfter: false,
infoLog: "",
};
processFile : false, response.FFmpegMode = true;
preset : '',
container : '.mp4',
handBrakeMode : false,
FFmpegMode : false,
reQueueAfter : false,
infoLog : '',
}
response.FFmpegMode = true
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else {
} else { var jsonString = JSON.stringify(file);
var jsonString = JSON.stringify(file) var hasSubs = false;
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try {
var hasSubs = false if (
for (var i = 0; i < file.ffProbeData.streams.length; i++) { file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle"
) {
try { hasSubs = true;
}
if(file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle"){ } catch (err) {}
}
hasSubs = true
//
}
} catch (err) { } if (
} file.ffProbeData.streams[0].codec_name != "h264" ||
file.ffProbeData.streams[0].width > 1280 ||
file.ffProbeData.streams[0].height > 720
// ) {
if(file.ffProbeData.streams[0].codec_name != 'h264' || file.ffProbeData.streams[0].width > 1280 || file.ffProbeData.streams[0].height > 720 ){
response.processFile = true; response.processFile = true;
response.preset = '-Z "H.264 MKV 720p30"' response.preset = '-Z "H.264 MKV 720p30"';
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode =true response.handBrakeMode = true;
response.FFmpegMode = false response.FFmpegMode = false;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File is not h264 720p! \n" response.infoLog += "☒File is not h264 720p! \n";
return response return response;
}else{ } else {
response.infoLog += "☑File is h264 720p! \n";
response.infoLog += "☑File is h264 720p! \n" }
//
}
// if (file.meta.Title != "undefined" && hasSubs) {
if(file.meta.Title != "undefined" && hasSubs){
response.processFile = true; response.processFile = true;
response.preset = ',-sn -map_metadata -1 -map 0 -c copy' response.preset = ",-sn -map_metadata -1 -map 0 -c copy";
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode =false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File has title and has subs \n" response.infoLog += "☒File has title and has subs \n";
return response return response;
}else{ } else {
response.infoLog += "☑File has no title and has no subs \n" response.infoLog += "☑File has no title and has no subs \n";
}
}
if(file.meta.Title != undefined ){
if (file.meta.Title != undefined) {
response.processFile = true; response.processFile = true;
response.preset = ',-map_metadata -1 -map 0 -c copy' response.preset = ",-map_metadata -1 -map 0 -c copy";
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode =false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File has title metadata \n" response.infoLog += "☒File has title metadata \n";
return response return response;
} else {
response.infoLog += "☑File has no title metadata \n";
}else{ }
response.infoLog += "☑File has no title metadata \n"
}
if(hasSubs){
if (hasSubs) {
response.processFile = true; response.processFile = true;
response.preset = ',-sn -map 0 -c copy' response.preset = ",-sn -map 0 -c copy";
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode =false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File has subs \n" response.infoLog += "☒File has subs \n";
return response return response;
} else {
}else{ response.infoLog += "☑File has no subs \n";
response.infoLog += "☑File has no subs \n" }
}
if( file.container != 'mkv'){
if (file.container != "mkv") {
response.processFile = true; response.processFile = true;
response.preset = ', -map 0 -c copy' response.preset = ", -map 0 -c copy";
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode =false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File is not in mkv container! \n" response.infoLog += "☒File is not in mkv container! \n";
return response return response;
} else {
response.infoLog += "☑File is in mkv container! \n";
}else{ }
response.infoLog += "☑File is in mkv container! \n"
}
response.processFile = false;
response.infoLog += "☑File meets conditions! \n"
return response
response.processFile = false;
response.infoLog += "☑File meets conditions! \n";
return response;
} }
} }

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_e3je_Tharic_H.264_MKV_1080p30_No_Subs_No_Title_Meta", id: "Tdarr_Plugin_e3je_Tharic_H.264_MKV_1080p30_No_Subs_No_Title_Meta",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,156 +7,123 @@ function details() {
Description: `[Contains built-in filter] This plugin removes subs, metadata (if a title exists) and makes sure the video is h264 1080p mkv. \n\n Description: `[Contains built-in filter] This plugin removes subs, metadata (if a title exists) and makes sure the video is h264 1080p mkv. \n\n
`, `,
Version: "1.00", Version: "1.00",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_e3je_Tharic_H.264_MKV_1080p30_No_Subs_No_Title_Meta.js", Link:
Tags:'pre-processing,handbrake,ffmpeg,h264' "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_e3je_Tharic_H.264_MKV_1080p30_No_Subs_No_Title_Meta.js",
} Tags: "pre-processing,handbrake,ffmpeg,h264",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false,
preset: "",
container: ".mp4",
handBrakeMode: false,
FFmpegMode: false,
reQueueAfter: false,
infoLog: "",
};
processFile : false, response.FFmpegMode = true;
preset : '',
container : '.mp4',
handBrakeMode : false,
FFmpegMode : false,
reQueueAfter : false,
infoLog : '',
}
response.FFmpegMode = true
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else {
} else { var jsonString = JSON.stringify(file);
var jsonString = JSON.stringify(file) var hasSubs = false;
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try {
var hasSubs = false if (
for (var i = 0; i < file.ffProbeData.streams.length; i++) { file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle"
) {
try { hasSubs = true;
}
if(file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle"){ } catch (err) {}
}
hasSubs = true
//
}
} catch (err) { } if (
} file.ffProbeData.streams[0].codec_name != "h264" ||
file.ffProbeData.streams[0].width > 1920 ||
file.ffProbeData.streams[0].height > 1080
// ) {
if(file.ffProbeData.streams[0].codec_name != 'h264' || file.ffProbeData.streams[0].width > 1920 || file.ffProbeData.streams[0].height > 1080 ){
response.processFile = true; response.processFile = true;
response.preset = '-Z "H.264 MKV 1080p30"' response.preset = '-Z "H.264 MKV 1080p30"';
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode =true response.handBrakeMode = true;
response.FFmpegMode = false response.FFmpegMode = false;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File is not h264 1080p! \n" response.infoLog += "☒File is not h264 1080p! \n";
return response return response;
}else{ } else {
response.infoLog += "☑File is h264 1080p!";
response.infoLog += "☑File is h264 1080p!" }
//
}
// if (file.meta.Title != "undefined" && hasSubs) {
if(file.meta.Title != "undefined" && hasSubs){
response.processFile = true; response.processFile = true;
response.preset = ',-sn -map_metadata -1 -map 0 -c copy' response.preset = ",-sn -map_metadata -1 -map 0 -c copy";
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode =false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File has title and has subs \n" response.infoLog += "☒File has title and has subs \n";
return response return response;
}else{ } else {
response.infoLog += "☑File has no title and has no subs \n" response.infoLog += "☑File has no title and has no subs \n";
}
}
if(file.meta.Title != undefined ){
if (file.meta.Title != undefined) {
response.processFile = true; response.processFile = true;
response.preset = ',-map_metadata -1 -map 0 -c copy' response.preset = ",-map_metadata -1 -map 0 -c copy";
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode =false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File has title metadata \n" response.infoLog += "☒File has title metadata \n";
return response return response;
} else {
response.infoLog += "☑File has no title metadata \n";
}else{ }
response.infoLog += "☑File has no title metadata \n"
}
if(hasSubs){
if (hasSubs) {
response.processFile = true; response.processFile = true;
response.preset = ',-sn -map 0 -c copy' response.preset = ",-sn -map 0 -c copy";
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode =false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File has subs \n" response.infoLog += "☒File has subs \n";
return response return response;
} else {
}else{ response.infoLog += "☑File has no subs \n";
response.infoLog += "☑File has no subs \n" }
}
if( file.container != 'mkv'){
if (file.container != "mkv") {
response.processFile = true; response.processFile = true;
response.preset = ', -map 0 -c copy' response.preset = ", -map 0 -c copy";
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode =false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File is not in mkv container! \n" response.infoLog += "☒File is not in mkv container! \n";
return response return response;
} else {
response.infoLog += "☑File is in mkv container! \n";
}else{ }
response.infoLog += "☑File is in mkv container! \n"
}
response.processFile = false;
response.infoLog += "☑File meets conditions! \n"
return response
response.processFile = false;
response.infoLog += "☑File meets conditions! \n";
return response;
} }
} }

@ -1,143 +1,154 @@
const fs = require('fs'); const fs = require("fs");
const execSync = require('child_process').execSync; const execSync = require("child_process").execSync;
function details() { function details() {
return { return {
id: "Tdarr_Plugin_e5c3_CnT_Add_Subtitles", id: "Tdarr_Plugin_e5c3_CnT_Add_Subtitles",
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "Add subtitles to MKV files", Name: "Add subtitles to MKV files",
Type: "Video", Type: "Video",
Operation:"Remux", Operation: "Remux",
Description: `This plugin will check for subtitles, they should be named according to the ISO 639-2 language code.\nA subtitle could look like this: eng.srt\n If there are subtitles found they will be added with FFMPEG, if there are no subs of that language found.\n On first run node module iso-639-2 will be installed in the documents folder.\n Created by @control#0405`, Description: `This plugin will check for subtitles, they should be named according to the ISO 639-2 language code.\nA subtitle could look like this: eng.srt\n If there are subtitles found they will be added with FFMPEG, if there are no subs of that language found.\n On first run node module iso-639-2 will be installed in the documents folder.\n Created by @control#0405`,
Version: "1.3", Version: "1.3",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_e5c3_CnT_Add_Subtitles.js", Link:
Tags:'pre-processing,ffmpeg,subtitle only,configurable', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_e5c3_CnT_Add_Subtitles.js",
Inputs: [ Tags: "pre-processing,ffmpeg,subtitle only,configurable",
{ Inputs: [
name: 'install_packages', {
tooltip: `Please change this to "yes", it allows the plugin to install the required nodemodule. (iso-639-2) \\nExample:\\n yes` name: "install_packages",
}, tooltip: `Please change this to "yes", it allows the plugin to install the required nodemodule. (iso-639-2) \\nExample:\\n yes`,
{ },
name: 'container', {
tooltip: `Enter the output container of the new file.\\n Default: .mkv\\nExample:\\n.mkv` name: "container",
}, tooltip: `Enter the output container of the new file.\\n Default: .mkv\\nExample:\\n.mkv`,
] },
} ],
};
} }
function plugin(file, librarySettings, inputs, otherArguments) { function plugin(file, librarySettings, inputs, otherArguments) {
//default response //default response
var response = { var response = {
processFile: false, processFile: false,
preset: `,`, preset: `,`,
container: '.mkv', container: ".mkv",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: false, reQueueAfter: false,
infoLog: `Searching new subtitles...\n`, infoLog: `Searching new subtitles...\n`,
} };
if (inputs.container !== undefined) {
response.container = inputs.container;
console.log(`Changed container to: ` + inputs.container);
}
if (inputs.install_packages == "yes") { if (inputs.container !== undefined) {
if (!fs.existsSync(`${otherArguments.homePath}/Tdarr/node_modules/iso-639-2`)) { response.container = inputs.container;
execSync(`cd ${otherArguments.homePath}/Tdarr \n npm install iso-639-2`); console.log(`Changed container to: ` + inputs.container);
} }
} else {
response.infoLog = `Please take a look at the input options\n A extra nodemodule is required.` if (inputs.install_packages == "yes") {
return response; if (
!fs.existsSync(`${otherArguments.homePath}/Tdarr/node_modules/iso-639-2`)
) {
execSync(`cd ${otherArguments.homePath}/Tdarr \n npm install iso-639-2`);
} }
} else {
response.infoLog = `Please take a look at the input options\n A extra nodemodule is required.`;
return response;
}
if (fs.existsSync(`/home/Tdarr/Documents/Tdarr/node_modules/iso-639-2`)) { if (fs.existsSync(`/home/Tdarr/Documents/Tdarr/node_modules/iso-639-2`)) {
var iso6392 = require('/home/Tdarr/Documents/Tdarr/node_modules/iso-639-2'); var iso6392 = require("/home/Tdarr/Documents/Tdarr/node_modules/iso-639-2");
} else {
response.infoLog += `Nodemodule iso-639-2 isn't installed!\nTry Again`;
return response;
}
var i = 0; //int for counting lang[position]
var found_subtitle_stream = 0;
var sub = 0; //becomes first subtitle stream
var lang = iso6392; //languages to check against
var path = file.meta.Directory; //path of media folder
var exist = 0; //if the language exists should be added this becomes 1
var new_subs = 0; //count the new subs
var added_subs = 0; //counts the amount of subs that have been mapped
var preset_import = "";
var preset_meta = "";
//find first subtitle stream
while (found_subtitle_stream == 0 && sub < file.ffProbeData.streams.length) {
if (file.ffProbeData.streams[sub].codec_type.toLowerCase() == "subtitle") {
found_subtitle_stream = 1;
} else { } else {
response.infoLog += `Nodemodule iso-639-2 isn't installed!\nTry Again` sub++;
return response;
} }
}
var i = 0; //int for counting lang[position] response.infoLog += `Path: ${path}\n`;
var found_subtitle_stream = 0; for (i = 0; i < lang.length; i++) {
var sub = 0; //becomes first subtitle stream //check if srt file exists in folder
var lang = iso6392; //languages to check against if (fs.existsSync(`${path}/${lang[i].iso6392B}.srt`)) {
var path = file.meta.Directory; //path of media folder response.infoLog += `Found subtitle ${lang[i].name}.srt\n`;
var exist = 0; //if the language exists should be added this becomes 1
var new_subs = 0 //count the new subs if (found_subtitle_stream == 1) {
var added_subs = 0; //counts the amount of subs that have been mapped //check if language already exists
var preset_import = ''; for (
var preset_meta = ''; sub_stream = sub;
sub_stream < file.ffProbeData.streams.length;
//find first subtitle stream sub_stream++
while (found_subtitle_stream == 0 && sub < file.ffProbeData.streams.length) { ) {
if (file.ffProbeData.streams[sub].codec_type.toLowerCase() == "subtitle") { //response.infoLog += `does ${lang[i].name} exist in stream ${sub_stream}?\n`
found_subtitle_stream = 1; if (file.ffProbeData.streams[sub_stream].tags.language) {
} else { if (
sub++; file.ffProbeData.streams[
} sub_stream
} ].tags.language.toLowerCase() == lang[i].iso6392B
) {
response.infoLog += `Path: ${path}\n`; //response.infoLog += `YES\n`
for (i = 0; i < lang.length; i++) { exist = 1;
//check if srt file exists in folder response.infoLog += `Language already exists in stream ${sub_stream}\n It will not be added\n`;
if (fs.existsSync(`${path}/${lang[i].iso6392B}.srt`)) {
response.infoLog += `Found subtitle ${lang[i].name}.srt\n`;
if (found_subtitle_stream == 1) {
//check if language already exists
for (sub_stream = sub; sub_stream < file.ffProbeData.streams.length; sub_stream++) {
//response.infoLog += `does ${lang[i].name} exist in stream ${sub_stream}?\n`
if (file.ffProbeData.streams[sub_stream].tags.language) {
if (file.ffProbeData.streams[sub_stream].tags.language.toLowerCase() == lang[i].iso6392B) {
//response.infoLog += `YES\n`
exist = 1;
response.infoLog += `Language already exists in stream ${sub_stream}\n It will not be added\n`;
}
}
}
} else {
exist = 0;
}
//add if it hasn't found the language
if (exist != 1) {
preset_import += ` -sub_charenc "UTF-8" -f srt -i "${path}/${lang[i].iso6392B}.srt"`;
preset_meta += ` -metadata:s:s:${new_subs} language=${lang[i].iso6392B}`;
new_subs++;
} }
} }
//else { }
// response.infoLog += `did not find sub ${lang[i].iso6392B}.srt\n` } else {
//}
exist = 0; exist = 0;
} }
response.preset += ` ${preset_import}${preset_meta} -map 0:v -map 0:a` //add if it hasn't found the language
if (exist != 1) {
//map new subs preset_import += ` -sub_charenc "UTF-8" -f srt -i "${path}/${lang[i].iso6392B}.srt"`;
while (added_subs < new_subs) { preset_meta += ` -metadata:s:s:${new_subs} language=${lang[i].iso6392B}`;
added_subs++; new_subs++;
response.preset += ` -map ${added_subs}:s`; }
} }
//else {
// response.infoLog += `did not find sub ${lang[i].iso6392B}.srt\n`
//}
exist = 0;
}
//if new subs have been found they will be added response.preset += ` ${preset_import}${preset_meta} -map 0:v -map 0:a`;
if (new_subs > 0) {
response.FFmpegMode = true; //map new subs
response.processFile = true; while (added_subs < new_subs) {
response.reQueueAfter = true; added_subs++;
if (found_subtitle_stream == 1) { response.preset += ` -map ${added_subs}:s`;
response.preset += ` -map 0:s `; }
}
response.preset += ` -c copy`; //if new subs have been found they will be added
response.infoLog += `${new_subs} new subs will be added\n`; if (new_subs > 0) {
} else { response.FFmpegMode = true;
response.infoLog += `No new subtitle languages were found\n`; response.processFile = true;
response.reQueueAfter = true;
if (found_subtitle_stream == 1) {
response.preset += ` -map 0:s `;
} }
response.preset += ` -c copy`;
response.infoLog += `${new_subs} new subs will be added\n`;
} else {
response.infoLog += `No new subtitle languages were found\n`;
}
//response.infoLog += `The ffmpeg string is: ${response.preset}\n` //response.infoLog += `The ffmpeg string is: ${response.preset}\n`
return response return response;
} }
module.exports.details = details; module.exports.details = details;

@ -1,137 +1,168 @@
const exec = require('child_process').exec; const exec = require("child_process").exec;
const fs = require('fs'); const fs = require("fs");
function details() { function details() {
return { return {
id: "Tdarr_Plugin_e5c3_CnT_Keep_Preferred_Audio", id: "Tdarr_Plugin_e5c3_CnT_Keep_Preferred_Audio",
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "Keep Preffered Audio", Name: "Keep Preffered Audio",
Type: "Audio", Type: "Audio",
Operation:"Remove Audio", Operation: "Remove Audio",
Description: "Plugin that checks for unwanted audio, per 1.104 beta you can change the languages yourself from within Tdarr!\nUntill you enter a value it keep english tracks by default.\nUndefined languages are kept to prevent videos without sound.\nIf you would like to keep track of the languages you have for each file you can use the 'special' option.\nCreated by @control#0405", Description:
Version: "1.2", "Plugin that checks for unwanted audio, per 1.104 beta you can change the languages yourself from within Tdarr!\nUntill you enter a value it keep english tracks by default.\nUndefined languages are kept to prevent videos without sound.\nIf you would like to keep track of the languages you have for each file you can use the 'special' option.\nCreated by @control#0405",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_e5c3_CnT_Keep_Preferred_Audio.js", Version: "1.2",
Tags: 'pre-processing,ffmpeg,configurable,audio only', Link:
Inputs: [ "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_e5c3_CnT_Keep_Preferred_Audio.js",
{ Tags: "pre-processing,ffmpeg,configurable,audio only",
name: 'languages', Inputs: [
tooltip: `Desired Languages you would like to keep, language format has to be according to the iso-639-2 standard: https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes\\nExample:\\eng,dut` {
}, name: "languages",
{ tooltip: `Desired Languages you would like to keep, language format has to be according to the iso-639-2 standard: https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes\\nExample:\\eng,dut`,
name: 'special', },
tooltip: `This is if you want a specific language to be logged to a file in your Tdarr documents folder.\\nIt will add the name of the file that is being processed if this language(s) has been found.\\nThe file is created the first time it finds a file with the language.\\nThe languages don't have to be in "languages".\\nExample:\\eng,dut` {
}, name: "special",
{ tooltip: `This is if you want a specific language to be logged to a file in your Tdarr documents folder.\\nIt will add the name of the file that is being processed if this language(s) has been found.\\nThe file is created the first time it finds a file with the language.\\nThe languages don't have to be in "languages".\\nExample:\\eng,dut`,
name: 'container', },
tooltip: `Enter the output container of the new file.\\n Default: .mkv\\nExample:\\n.mkv` {
}, name: "container",
] tooltip: `Enter the output container of the new file.\\n Default: .mkv\\nExample:\\n.mkv`,
} },
],
};
} }
function plugin(file, librarySettings, inputs, otherArguments) { function plugin(file, librarySettings, inputs, otherArguments) {
if (inputs.languages == "" || typeof inputs.special == 'undefined') { if (inputs.languages == "" || typeof inputs.special == "undefined") {
var languages = ["eng", "en"]; //these languages should be kept, named according to ISO 639-2 language scheme var languages = ["eng", "en"]; //these languages should be kept, named according to ISO 639-2 language scheme
} else { } else {
var languages = inputs.languages.toLowerCase().split(','); //these languages should be kept, named according to ISO 639-2 language scheme var languages = inputs.languages.toLowerCase().split(","); //these languages should be kept, named according to ISO 639-2 language scheme
} }
if (inputs.special == "" || typeof inputs.special == 'undefined') { if (inputs.special == "" || typeof inputs.special == "undefined") {
var special = ``; var special = ``;
} else { } else {
var special = inputs.special.toLowerCase().split(','); var special = inputs.special.toLowerCase().split(",");
} }
if (languages.length >= special.length) { if (languages.length >= special.length) {
var length = languages.length; var length = languages.length;
} else { } else {
var length = special.length; var length = special.length;
} }
console.log(languages); console.log(languages);
var transcode = 0; //if this becomes '1' it will be transcoded var transcode = 0; //if this becomes '1' it will be transcoded
var sourcename = file.meta.FileName.substring(0, file.meta.FileName.lastIndexOf(".")); //filename without extension var sourcename = file.meta.FileName.substring(
var specialcheck = ``; //contains the txt string if special language was found 0,
var wanted = 0; file.meta.FileName.lastIndexOf(".")
var audio = 0; ); //filename without extension
var specialcheck = ``; //contains the txt string if special language was found
//default response var wanted = 0;
var response = { var audio = 0;
processFile: false,
preset: `, -map 0:v`,
container: '.mkv',
handBrakeMode: false,
FFmpegMode: false,
reQueueAfter: false,
infoLog: 'Removing unwanted audio...\n',
};
if (inputs.container !== undefined) { //default response
response.container = inputs.container; var response = {
console.log(`Container was set to: ` + inputs.container); processFile: false,
} preset: `, -map 0:v`,
container: ".mkv",
handBrakeMode: false,
FFmpegMode: false,
reQueueAfter: false,
infoLog: "Removing unwanted audio...\n",
};
for (i = 0; i < file.ffProbeData.streams.length; i++) { if (inputs.container !== undefined) {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { response.container = inputs.container;
//check for non-english tracks console.log(`Container was set to: ` + inputs.container);
console.log(`Audio track ${i}`); }
console.log("type: " + typeof file.ffProbeData.streams[i].tags);
if (typeof file.ffProbeData.streams[i].tags !== 'undefined' || file.ffProbeData.streams[i].tags) {
console.log("Type: " + typeof file.ffProbeData.streams[i].tags.language)
if (typeof file.ffProbeData.streams[i].tags.language !== 'undefined' || file.ffProbeData.streams[i].tags.language) {
for (l = 0; l < length; l++) {
if (file.ffProbeData.streams[i].tags.language == special[l]) {
if (!fs.existsSync(otherArguments.homePath + `/Tdarr/special_audio_${special[l]}.txt`)) { //create txt file if it doesn't exist yet
exec(`echo "${sourcename}" >> ${otherArguments.homePath}/Tdarr/special_audio_${special[l]}.txt`); //first file will be added and file is created
console.log(`added to txt: ` + sourcename);
} else {
specialcheck = fs.readFileSync(otherArguments.homePath + `/Tdarr/special_audio_${special[l]}.txt`).toString(); //create string from existing file
if (!specialcheck.includes(sourcename)) { //only add the filename if it wasn't added already
exec(`echo "${sourcename}" >> ${otherArguments.homePath}/Tdarr/special_audio_${special[l]}.txt`);
console.log(`added to txt: ` + sourcename);
}
}
response.preset += ` -map 0:${i}`; for (i = 0; i < file.ffProbeData.streams.length; i++) {
response.infoLog += `Found special ${special[l]}: ${i}\n`; if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
wanted++; //check for non-english tracks
break; console.log(`Audio track ${i}`);
} else if (file.ffProbeData.streams[i].tags.language == languages[l]) { console.log("type: " + typeof file.ffProbeData.streams[i].tags);
response.preset += ` -map 0:${i}`; if (
response.infoLog += `Found wanted ${languages[l]}: ${i}\n`; typeof file.ffProbeData.streams[i].tags !== "undefined" ||
wanted++; file.ffProbeData.streams[i].tags
break; ) {
} else if (i == length-1) { console.log(
response.infoLog += `Found unwanted: ${file.ffProbeData.streams[i].tags.language}: ${i}\n`; "Type: " + typeof file.ffProbeData.streams[i].tags.language
} );
} if (
} else { typeof file.ffProbeData.streams[i].tags.language !== "undefined" ||
response.preset += ` -map 0:${i}`; file.ffProbeData.streams[i].tags.language
response.infoLog += `Added undefined: ${i}\n`; ) {
wanted++; for (l = 0; l < length; l++) {
if (file.ffProbeData.streams[i].tags.language == special[l]) {
if (
!fs.existsSync(
otherArguments.homePath +
`/Tdarr/special_audio_${special[l]}.txt`
)
) {
//create txt file if it doesn't exist yet
exec(
`echo "${sourcename}" >> ${otherArguments.homePath}/Tdarr/special_audio_${special[l]}.txt`
); //first file will be added and file is created
console.log(`added to txt: ` + sourcename);
} else {
specialcheck = fs
.readFileSync(
otherArguments.homePath +
`/Tdarr/special_audio_${special[l]}.txt`
)
.toString(); //create string from existing file
if (!specialcheck.includes(sourcename)) {
//only add the filename if it wasn't added already
exec(
`echo "${sourcename}" >> ${otherArguments.homePath}/Tdarr/special_audio_${special[l]}.txt`
);
console.log(`added to txt: ` + sourcename);
} }
} else { }
response.preset += ` -map 0:${i}`;
response.infoLog += `Added undefined: ${i}\n`;
wanted++;
}
audio++; response.preset += ` -map 0:${i}`;
response.infoLog += `Found special ${special[l]}: ${i}\n`;
wanted++;
break;
} else if (
file.ffProbeData.streams[i].tags.language == languages[l]
) {
response.preset += ` -map 0:${i}`;
response.infoLog += `Found wanted ${languages[l]}: ${i}\n`;
wanted++;
break;
} else if (i == length - 1) {
response.infoLog += `Found unwanted: ${file.ffProbeData.streams[i].tags.language}: ${i}\n`;
}
}
} else {
response.preset += ` -map 0:${i}`;
response.infoLog += `Added undefined: ${i}\n`;
wanted++;
} }
} } else {
response.preset += ` -map 0:${i}`;
response.infoLog += `Added undefined: ${i}\n`;
wanted++;
}
if (audio > wanted && wanted > 0) { audio++;
transcode = 1;
} }
}
if (transcode == 1) { if (audio > wanted && wanted > 0) {
response.infoLog += `Found unwanted audio\nIt will be removed\n`; transcode = 1;
response.processFile = true; }
response.FFmpegMode = true;
response.preset += ` -map 0:s? -c copy`; if (transcode == 1) {
response.reQueueAfter = true; response.infoLog += `Found unwanted audio\nIt will be removed\n`;
} else { response.processFile = true;
response.infoLog += `No unwanted audio found!\n`; response.FFmpegMode = true;
} response.preset += ` -map 0:s? -c copy`;
response.reQueueAfter = true;
} else {
response.infoLog += `No unwanted audio found!\n`;
}
return response return response;
} }
module.exports.details = details; module.exports.details = details;

@ -1,395 +1,451 @@
const fs = require('fs'); const fs = require("fs");
const execSync = require('child_process').execSync; const execSync = require("child_process").execSync;
function details() { function details() {
return { return {
id: "Tdarr_Plugin_e5c3_CnT_Remove_Letterbox", id: "Tdarr_Plugin_e5c3_CnT_Remove_Letterbox",
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "Remove letterbox", Name: "Remove letterbox",
Type: "Video", Type: "Video",
Operation:"Transcode", Operation: "Transcode",
Description: `Uses iiDrakeii's filter, and crops video files when letterboxing is detected.\nThis uses the FFMPEG NVENC transcoding(hw).\nIf a file is 4K it will be scaled down to 1080p.\nNow with user definable bitrates!(since 1.104 beta)\nCreated by @control#0405`, Description: `Uses iiDrakeii's filter, and crops video files when letterboxing is detected.\nThis uses the FFMPEG NVENC transcoding(hw).\nIf a file is 4K it will be scaled down to 1080p.\nNow with user definable bitrates!(since 1.104 beta)\nCreated by @control#0405`,
Version: "1.3", Version: "1.3",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_e5c3_CnT_Remove_Letterbox.js", Link:
Tags: 'pre-processing,ffmpeg,nvenc h265,configurable,h265,video only', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_e5c3_CnT_Remove_Letterbox.js",
Inputs: [ Tags: "pre-processing,ffmpeg,nvenc h265,configurable,h265,video only",
{ Inputs: [
name: 'bitrate', {
tooltip: `Desired bitrate for a 1080p video, minimum transcode size is based of this too!\\n 720p will be half of 1080p, 480p will be half of 720p.\\nThe default is '3000', this value is based of movies.\\nI would suggest 1500-2000 for series.\\nExample:\\n3000` name: "bitrate",
}, tooltip: `Desired bitrate for a 1080p video, minimum transcode size is based of this too!\\n 720p will be half of 1080p, 480p will be half of 720p.\\nThe default is '3000', this value is based of movies.\\nI would suggest 1500-2000 for series.\\nExample:\\n3000`,
{ },
name: 'container', {
tooltip: `Enter the output container of the new file.\\n Default: .mkv\\nExample:\\n.mkv` name: "container",
}, tooltip: `Enter the output container of the new file.\\n Default: .mkv\\nExample:\\n.mkv`,
] },
} ],
};
} }
function plugin(file, librarySettings, inputs, otherArguments) { function plugin(file, librarySettings, inputs, otherArguments) {
if (inputs.bitrate == "" || inputs.bitrate == 'undefined') { if (inputs.bitrate == "" || inputs.bitrate == "undefined") {
var min_bitrate = 6600; var min_bitrate = 6600;
var avg_rate = 3000; var avg_rate = 3000;
var max_rate = 6000; var max_rate = 6000;
} else {
var min_bitrate = inputs.bitrate * 2.2;
var avg_rate = inputs.bitrate;
var max_rate = inputs.bitrate * 2;
}
//default values that will be returned
var response = {
processFile: false,
preset: "",
container: ".mkv",
handBrakeMode: false,
FFmpegMode: true,
reQueueAfter: true,
infoLog: "",
};
if (inputs.container !== undefined) {
response.container = inputs.container;
console.log(`Container was set to: ` + inputs.container);
}
var source = file.meta.SourceFile; //source file
var stats = fs.statSync(source);
var size = stats["size"] / 1000000000;
size = size.toFixed(2);
var decoder = decoder_string(file); //decoder, before the input
var encoder = encoder_string_full(
highres(file),
crop_decider(file, generate_crop_values(file, otherArguments).crop_height)
.crop,
encoder_string(file, avg_rate, max_rate, response.container)
); //encoder
var process = 0; //decides if it should be processed
var returns = {
create_crop: generate_crop_values(file, otherArguments),
crop: crop_decider(
file,
generate_crop_values(file, otherArguments).crop_height
),
size: size_check(file, min_bitrate),
};
var log = {
size: returns.size.log,
hevc: ``,
resolution: ``,
crop: returns.crop.log,
createcrop: returns.create_crop.log,
};
//filters
if (size_check(file, min_bitrate).size == 1) {
if (hevc(file) == 1) {
log.hevc = `☑ - Video is not HEVC \n`;
process = 1;
} else { } else {
var min_bitrate = inputs.bitrate*2.2; log.hevc += "☒ - File is already in HEVC \n";
var avg_rate = inputs.bitrate;
var max_rate = inputs.bitrate*2;
}
//default values that will be returned
var response = {
processFile: false,
preset: '',
container: '.mkv',
handBrakeMode: false,
FFmpegMode: true,
reQueueAfter: true,
infoLog: ''
}
if (inputs.container !== undefined) {
response.container = inputs.container;
console.log(`Container was set to: ` + inputs.container);
} }
var source = file.meta.SourceFile; //source file if (highres(file) == 1) {
var stats = fs.statSync(source); process = 1;
var size = stats["size"]/1000000000; log.resolution += `☑ - Resolution > 1080p.\n File will be transcoded to 1080p \n`;
size = size.toFixed(2); } else {
var decoder = decoder_string(file); //decoder, before the input log.resolution += `☒ - Resolution <= 1080p \n`;
var encoder = encoder_string_full(highres(file), crop_decider(file, generate_crop_values(file, otherArguments).crop_height).crop, encoder_string(file, avg_rate, max_rate, response.container)); //encoder
var process = 0; //decides if it should be processed
var returns = {
create_crop: generate_crop_values(file, otherArguments),
crop: crop_decider(file, generate_crop_values(file, otherArguments).crop_height),
size: size_check(file, min_bitrate)
}
var log = {
size: returns.size.log,
hevc: ``,
resolution: ``,
crop: returns.crop.log,
createcrop: returns.create_crop.log
}
//filters
if (size_check(file, min_bitrate).size == 1) {
if (hevc(file) == 1) {
log.hevc = `☑ - Video is not HEVC \n`;
process = 1;
} else {
log.hevc += "☒ - File is already in HEVC \n"
}
if (highres(file) == 1) {
process = 1;
log.resolution += `☑ - Resolution > 1080p.\n File will be transcoded to 1080p \n`;
} else {
log.resolution += `☒ - Resolution <= 1080p \n`;
}
if (crop_decider(file, generate_crop_values(file, otherArguments).crop_height).crop != "0") {
process = 1;
}
} }
response.infoLog += log.createcrop + if (
log.crop + crop_decider(file, generate_crop_values(file, otherArguments).crop_height)
log.resolution + .crop != "0"
log.size + ) {
log.hevc; process = 1;
response.preset = `${decoder}, -map 0:v:0 -map 0:a -map 0:s? ${encoder}`
//change response
if (process == 1) {
response.processFile = true;
response.infoLog += `File will be processed\n`;
} else if (file.forceProcessing === true) {
response.processFile = true;
response.infoLog += `Force processing!\n`;
} else {
response.infoLog += `Processing not necessary\n`;
} }
}
return response;
response.infoLog +=
log.createcrop + log.crop + log.resolution + log.size + log.hevc;
response.preset = `${decoder}, -map 0:v:0 -map 0:a -map 0:s? ${encoder}`;
//change response
if (process == 1) {
response.processFile = true;
response.infoLog += `File will be processed\n`;
} else if (file.forceProcessing === true) {
response.processFile = true;
response.infoLog += `Force processing!\n`;
} else {
response.infoLog += `Processing not necessary\n`;
}
return response;
} }
function highres(file) { function highres(file) {
//if file is larger than 1080p it should be transcoded //if file is larger than 1080p it should be transcoded
if (file.meta.ImageWidth > 1920) { if (file.meta.ImageWidth > 1920) {
return 1; return 1;
} else { } else {
return 0; return 0;
} }
} }
function generate_crop_values(file, otherArguments) { function generate_crop_values(file, otherArguments) {
var source = file.meta.SourceFile; //source file var source = file.meta.SourceFile; //source file
var dir = file.meta.Directory; //source directory var dir = file.meta.Directory; //source directory
var sourcename = file.meta.FileName.substring(0, file.meta.FileName.lastIndexOf(".")); //filename without extension var sourcename = file.meta.FileName.substring(
var cropfile = `${dir}/${sourcename}.txt`; //location and name of the crop file 0,
var returns = { file.meta.FileName.lastIndexOf(".")
crop_height: 0, //return value for this function, required for crop_decider ); //filename without extension
log: `` var cropfile = `${dir}/${sourcename}.txt`; //location and name of the crop file
} var returns = {
crop_height: 0, //return value for this function, required for crop_decider
//create crop value log: ``,
if (!fs.existsSync(`${cropfile}`)) { };
returns.log += `Creating crop values...\n`;
execSync(`${otherArguments.ffmpegPath} -ss 300 -i \"${source}\" -frames:v 240 -vf cropdetect -f null - 2>&1 | awk \'/crop/ { print $NF }\' | tail -240 > \"${cropfile}\"`); //create crop value
execSync(`${otherArguments.ffmpegPath} -ss 1200 -i \"${source}\" -frames:v 240 -vf cropdetect -f null - 2>&1 | awk \'/crop/ { print $NF }\' | tail -240 >> \"${cropfile}\"`); if (!fs.existsSync(`${cropfile}`)) {
} else { returns.log += `Creating crop values...\n`;
returns.log += `Crop values already exist\n`; execSync(
} `${otherArguments.ffmpegPath} -ss 300 -i \"${source}\" -frames:v 240 -vf cropdetect -f null - 2>&1 | awk \'/crop/ { print $NF }\' | tail -240 > \"${cropfile}\"`
);
//get data from copvalue.txt execSync(
var data = fs.readFileSync(`${cropfile}`).toString().split("\n"); //full data from cropvalue.txt `${otherArguments.ffmpegPath} -ss 1200 -i \"${source}\" -frames:v 240 -vf cropdetect -f null - 2>&1 | awk \'/crop/ { print $NF }\' | tail -240 >> \"${cropfile}\"`
);
//get height of the supposed cropped video } else {
//var crop_height = parseInt(data[0].substring(10, 14)); returns.log += `Crop values already exist\n`;
for (var c = 0; c < data.length; c++) { }
crop = data[c].split(":");
crop_height = Math.abs(parseInt(crop[1])); //get data from copvalue.txt
if (crop_height > returns.crop_height) { var data = fs.readFileSync(`${cropfile}`).toString().split("\n"); //full data from cropvalue.txt
returns.crop_height = crop_height;
returns.log += `New cropheight: ${crop_height}\n`; //get height of the supposed cropped video
} //var crop_height = parseInt(data[0].substring(10, 14));
for (var c = 0; c < data.length; c++) {
crop = data[c].split(":");
crop_height = Math.abs(parseInt(crop[1]));
if (crop_height > returns.crop_height) {
returns.crop_height = crop_height;
returns.log += `New cropheight: ${crop_height}\n`;
} }
return returns; }
return returns;
} }
function hevc(file) { function hevc(file) {
//check if the file is already hevc, it will not be transcoded if true //check if the file is already hevc, it will not be transcoded if true
if (file.ffProbeData.streams[0].codec_name) { if (file.ffProbeData.streams[0].codec_name) {
if ("hevc".toLowerCase().includes(file.ffProbeData.streams[0].codec_name.toLowerCase())) { if (
return 0; "hevc"
} else { .toLowerCase()
return 1; .includes(file.ffProbeData.streams[0].codec_name.toLowerCase())
} ) {
return 0;
} else {
return 1;
} }
}
} }
function decoder_string(file) { function decoder_string(file) {
var decoder = ``; //decoder, before the input var decoder = ``; //decoder, before the input
//use the correct decoder //use the correct decoder
if (file.video_codec_name == 'h263') { if (file.video_codec_name == "h263") {
decoder = `-c:v h263_cuvid` decoder = `-c:v h263_cuvid`;
} else if (file.video_codec_name == "h264") {
if (file.ffProbeData.streams[0].profile != "High 10") {
//Remove HW Decoding for High 10 Profile
decoder = `-c:v h264_cuvid`;
} }
else if (file.video_codec_name == 'h264') { } else if (file.video_codec_name == "mjpeg") {
if (file.ffProbeData.streams[0].profile != 'High 10') { //Remove HW Decoding for High 10 Profile decoder = `c:v mjpeg_cuvid`;
decoder = `-c:v h264_cuvid` } else if (file.video_codec_name == "mpeg1") {
} decoder = `-c:v mpeg1_cuvid`;
} } else if (file.video_codec_name == "mpeg2") {
else if (file.video_codec_name == 'mjpeg') { decoder = `-c:v mpeg2_cuvid`;
decoder = `c:v mjpeg_cuvid` } else if (file.video_codec_name == "vc1") {
} decoder = `-c:v vc1_cuvid`;
else if (file.video_codec_name == 'mpeg1') { } else if (file.video_codec_name == "vp8") {
decoder = `-c:v mpeg1_cuvid` decoder = `-c:v vp8_cuvid`;
} } else if (file.video_codec_name == "vp9") {
else if (file.video_codec_name == 'mpeg2') { decoder = `-c:v vp9_cuvid`;
decoder = `-c:v mpeg2_cuvid` }
}
else if (file.video_codec_name == 'vc1') { return decoder;
decoder = `-c:v vc1_cuvid`
}
else if (file.video_codec_name == 'vp8') {
decoder = `-c:v vp8_cuvid`
}
else if (file.video_codec_name == 'vp9') {
decoder = `-c:v vp9_cuvid`
}
return decoder;
} }
function crop_decider(file, crop_height) { function crop_decider(file, crop_height) {
var returns = { var returns = {
crop: `0`, //sets the crop filter crop: `0`, //sets the crop filter
log: ``, log: ``,
};
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
if (file.ffProbeData.streams[i].width !== undefined) {
var imageWidth = file.ffProbeData.streams[i].width;
var imageHeight = file.ffProbeData.streams[i].height;
break;
} }
}
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
if (file.ffProbeData.streams[i].width !== undefined) { var min_crop = parseInt(imageHeight * 0.98); //if the crop value is larger than this the file won't be cropped
var imageWidth = file.ffProbeData.streams[i].width;
var imageHeight = file.ffProbeData.streams[i].height; //tree for resolution : quality
break; if (imageWidth >= 1300) {
} //file will be encoded if the resolution is 1080p, or greater (it will be downscaled)
//crop only if it is a larger crop than 1%;
if (crop_height < min_crop) {
var crop_hdis = parseInt((imageHeight - crop_height) / 2);
if (crop_height >= 790) {
returns.crop = `-filter:0 crop=${imageWidth}:${crop_height}:0:${crop_hdis}`;
returns.log += `☑ - crop is larger than 1%\n`;
}
} else {
returns.log += `☒ - Crop is not necessary\n`;
} }
} else if (imageWidth < 1300 && file.meta.ImageWidth >= 770) {
var min_crop = parseInt(imageHeight*.98); //if the crop value is larger than this the file won't be cropped //crop only if it is a larger crop than 1%;
if (crop_height < min_crop) {
//tree for resolution : quality var crop_hdis = parseInt((imageHeight - crop_height) / 2);
if (imageWidth >= 1300) { //file will be encoded if the resolution is 1080p, or greater (it will be downscaled) if (crop_height >= 530) {
//crop only if it is a larger crop than 1%; returns.crop = `-filter:0 crop=${imageWidth}:${crop_height}:0:${crop_hdis}`;
if (crop_height < min_crop) { returns.log += `☑ - crop is larger than 1%\n`;
var crop_hdis = parseInt((imageHeight-crop_height)/2); }
if (crop_height >= 790) { } else {
returns.crop = `-filter:0 crop=${imageWidth}:${crop_height}:0:${crop_hdis}`; returns.log += `☒ - Crop is not necessary\n`;
returns.log += `☑ - crop is larger than 1%\n`;
}
} else {
returns.log += `☒ - Crop is not necessary\n`;
}
} else if(imageWidth < 1300 && file.meta.ImageWidth >= 770) {
//crop only if it is a larger crop than 1%;
if (crop_height < min_crop) {
var crop_hdis = parseInt((imageHeight-crop_height)/2);
if (crop_height >= 530) {
returns.crop = `-filter:0 crop=${imageWidth}:${crop_height}:0:${crop_hdis}`;
returns.log += `☑ - crop is larger than 1%\n`;
}
} else {
returns.log += `☒ - Crop is not necessary\n`;
}
} else if(imageWidth < 770) { //file won't be cropped at this resolution
returns.log += `No crop: Resolution < 720p\n`;
} }
} else if (imageWidth < 770) {
//file won't be cropped at this resolution
returns.log += `No crop: Resolution < 720p\n`;
}
return returns; return returns;
} }
function size_check(file, min_bitrate) { function size_check(file, min_bitrate) {
var duration = file.meta.Duration; //duration of video in seconds var duration = file.meta.Duration; //duration of video in seconds
var source = file.meta.SourceFile; //source file var source = file.meta.SourceFile; //source file
var stats = fs.statSync(source); var stats = fs.statSync(source);
var size = stats["size"]/1000000000; var size = stats["size"] / 1000000000;
size = size.toFixed(2); size = size.toFixed(2);
var returns = { var returns = {
size: 0, size: 0,
log: `` log: ``,
} };
//tree for resolution : quality //tree for resolution : quality
if (file.video_resolution === "1080p" || file.video_resolution === "4KUHD") { //file will be encoded if the resolution is 1080p, or greater (it will be downscaled) if (file.video_resolution === "1080p" || file.video_resolution === "4KUHD") {
var min_transcode_size = (min_bitrate * duration * 0.125)/1000000; //minimum size in GB for transcode //file will be encoded if the resolution is 1080p, or greater (it will be downscaled)
min_transcode_size = min_transcode_size.toFixed(2); var min_transcode_size = (min_bitrate * duration * 0.125) / 1000000; //minimum size in GB for transcode
min_transcode_size = min_transcode_size.toFixed(2);
//check if file is large enough for transcode
if (size >= (min_bitrate * duration * 0.125)/1000000) { //check if file is large enough for transcode
returns.log += `☑ - ${size}GB > ${min_transcode_size}GB\n`; if (size >= (min_bitrate * duration * 0.125) / 1000000) {
returns.size = 1; returns.log += `☑ - ${size}GB > ${min_transcode_size}GB\n`;
} else { returns.size = 1;
returns.log += `☒ - ${size}GB < ${min_transcode_size}GB\n`; } else {
} returns.log += `☒ - ${size}GB < ${min_transcode_size}GB\n`;
} else if(file.video_resolution === "720p") { //file will be encoded if the resolution is 720p }
var min_transcode_size = ((min_bitrate/2) * duration * 0.125)/1000000; //minimum size in GB for transcode } else if (file.video_resolution === "720p") {
min_transcode_size = min_transcode_size.toFixed(2); //file will be encoded if the resolution is 720p
var min_transcode_size = ((min_bitrate / 2) * duration * 0.125) / 1000000; //minimum size in GB for transcode
//check if file is large enough for transcode min_transcode_size = min_transcode_size.toFixed(2);
if (size >= ((min_bitrate/2) * duration * 0.125)/1000000) {
returns.log += `☑ - ${size}GB > ${min_transcode_size}GB\n`; //check if file is large enough for transcode
returns.size = 1; if (size >= ((min_bitrate / 2) * duration * 0.125) / 1000000) {
} else { returns.log += `☑ - ${size}GB > ${min_transcode_size}GB\n`;
returns.log += `☒ - ${size}GB < ${min_transcode_size}GB\n`; returns.size = 1;
} } else {
} else if(file.video_resolution === "480p" || file.video_resolution === "576p") { //file will be encoded if the resolution is 480p or 576p returns.log += `☒ - ${size}GB < ${min_transcode_size}GB\n`;
var min_transcode_size = ((min_bitrate/4) * duration * 0.125)/1000000; //minimum size in GB for transcode
min_transcode_size = min_transcode_size.toFixed(2);
//check if file is large enough for transcode
if (size >= ((min_bitrate/4) * duration * 0.125)/1000000) {
returns.log += `☑ - ${size}GB > ${min_transcode_size}GB\n`;
returns.size = 1;
} else {
returns.log += `☒ - ${size}GB < ${min_transcode_size}GB\n`;
}
} }
} else if (
file.video_resolution === "480p" ||
file.video_resolution === "576p"
) {
//file will be encoded if the resolution is 480p or 576p
var min_transcode_size = ((min_bitrate / 4) * duration * 0.125) / 1000000; //minimum size in GB for transcode
min_transcode_size = min_transcode_size.toFixed(2);
//check if file is large enough for transcode
if (size >= ((min_bitrate / 4) * duration * 0.125) / 1000000) {
returns.log += `☑ - ${size}GB > ${min_transcode_size}GB\n`;
returns.size = 1;
} else {
returns.log += `☒ - ${size}GB < ${min_transcode_size}GB\n`;
}
}
return returns; return returns;
} }
function error_fix(file, container) { function error_fix(file, container) {
var fix = { var fix = {
sub_codec: 0, //changes to 1 if unwanted codec is found sub_codec: 0, //changes to 1 if unwanted codec is found
muxing: 0 muxing: 0,
} };
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
//these subtitle codecs don't fit in a mkv container
//these subtitle codecs don't fit in a mkv container if (
if (file.ffProbeData.streams[i].codec_name && file.ffProbeData.streams[i].codec_type) { file.ffProbeData.streams[i].codec_name &&
if (file.ffProbeData.streams[i].codec_name.toLowerCase() == "eia_608" || file.ffProbeData.streams[i].codec_name.toLowerCase() == "mov_text" && file.ffProbeData.streams[i].codec_type.toLowerCase().includes("sub") && container == '.mkv') { file.ffProbeData.streams[i].codec_type
fix.sub_codec = 1; ) {
} if (
file.ffProbeData.streams[i].codec_name.toLowerCase() == "eia_608" ||
//mitigate TrueHD audio causing Too many packets error (file.ffProbeData.streams[i].codec_name.toLowerCase() == "mov_text" &&
if (file.ffProbeData.streams[i].codec_name.toLowerCase() == "truehd" || file.ffProbeData.streams[i].codec_name.toLowerCase() == "dts" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" ) { file.ffProbeData.streams[i].codec_type
fix.muxing = 1; .toLowerCase()
} .includes("sub") &&
} container == ".mkv")
) {
fix.sub_codec = 1;
}
//mitigate TrueHD audio causing Too many packets error
if (
file.ffProbeData.streams[i].codec_name.toLowerCase() == "truehd" ||
(file.ffProbeData.streams[i].codec_name.toLowerCase() == "dts" &&
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio")
) {
fix.muxing = 1;
}
} }
}
return fix; return fix;
} }
function encoder_string(file, avg_rate, max_rate, container) { function encoder_string(file, avg_rate, max_rate, container) {
var encoder = ``; //encoder var encoder = ``; //encoder
var fix = error_fix(file, container); var fix = error_fix(file, container);
var sub = ``; var sub = ``;
//tree for resolution : quality //tree for resolution : quality
if (file.video_resolution === "1080p" || file.video_resolution === "4KUHD") { //file will be encoded if the resolution is 1080p, or greater (it will be downscaled) if (file.video_resolution === "1080p" || file.video_resolution === "4KUHD") {
encoder += ` -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 26 -b:v ${avg_rate}k -maxrate:v ${max_rate}k`; //-qp 26 //file will be encoded if the resolution is 1080p, or greater (it will be downscaled)
} else if(file.video_resolution === "720p") { //file will be encoded if the resolution is 720p encoder += ` -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 26 -b:v ${avg_rate}k -maxrate:v ${max_rate}k`; //-qp 26
encoder += ` -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 26 -b:v ${avg_rate/2}k -maxrate:v ${max_rate/2}k`; //-qp 28 } else if (file.video_resolution === "720p") {
} else if(file.video_resolution === "480p" || file.video_resolution === "576p") { //file will be encoded if the resolution is 480p or 576p //file will be encoded if the resolution is 720p
encoder += ` -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 26 -b:v ${avg_rate/4}k -maxrate:v ${max_rate/4}k`; //-qp 30 encoder += ` -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 26 -b:v ${
} else { //fallback option to 1080p quality avg_rate / 2
encoder += ` -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 26 -b:v ${avg_rate}k -maxrate:v ${max_rate}k`; //-qp 26 }k -maxrate:v ${max_rate / 2}k`; //-qp 28
} } else if (
encoder += ` -c:v hevc_nvenc -preset slow -rc-lookahead 32 -spatial_aq:v 1 -aq-strength:v 8 -a53cc 0 -dn`; file.video_resolution === "480p" ||
file.video_resolution === "576p"
if (fix.sub_codec == 1) { ) {
for (var i = 0; i < file.ffProbeData.streams.length; i++) { //file will be encoded if the resolution is 480p or 576p
if (file.ffProbeData.streams[i].codec_name) { encoder += ` -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 26 -b:v ${
if (file.ffProbeData.streams[i].codec_name.toLowerCase() == "eia_608" || file.ffProbeData.streams[i].codec_name.toLowerCase() == "mov_text" && file.ffProbeData.streams[i].codec_type.toLowerCase().includes("sub")) { avg_rate / 4
sub += ` -c:${i} ass`; }k -maxrate:v ${max_rate / 4}k`; //-qp 30
} else { } else {
if (file.ffProbeData.streams[i].codec_type) { //fallback option to 1080p quality
if (file.ffProbeData.streams[i].codec_type.toLowerCase().includes("sub")) { encoder += ` -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 26 -b:v ${avg_rate}k -maxrate:v ${max_rate}k`; //-qp 26
sub += ` -c:${i} copy`; }
} encoder += ` -c:v hevc_nvenc -preset slow -rc-lookahead 32 -spatial_aq:v 1 -aq-strength:v 8 -a53cc 0 -dn`;
}
} if (fix.sub_codec == 1) {
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
if (file.ffProbeData.streams[i].codec_name) {
if (
file.ffProbeData.streams[i].codec_name.toLowerCase() == "eia_608" ||
(file.ffProbeData.streams[i].codec_name.toLowerCase() == "mov_text" &&
file.ffProbeData.streams[i].codec_type
.toLowerCase()
.includes("sub"))
) {
sub += ` -c:${i} ass`;
} else {
if (file.ffProbeData.streams[i].codec_type) {
if (
file.ffProbeData.streams[i].codec_type
.toLowerCase()
.includes("sub")
) {
sub += ` -c:${i} copy`;
} }
}
} }
} else { }
sub = ` -c:s copy`
} }
} else {
if (fix.muxing == 1) { sub = ` -c:s copy`;
encoder += ` -max_muxing_queue_size 2048`; }
}
return encoder + ` -c:a copy` + sub; if (fix.muxing == 1) {
encoder += ` -max_muxing_queue_size 2048`;
}
return encoder + ` -c:a copy` + sub;
} }
function encoder_string_full(highres, crop, encoder) { function encoder_string_full(highres, crop, encoder) {
console.log(`crop filter: ` + crop); console.log(`crop filter: ` + crop);
if (highres == 1 && crop != "0") { if (highres == 1 && crop != "0") {
return crop + `,scale=-1:1920 ` + encoder; return crop + `,scale=-1:1920 ` + encoder;
} else if (highres == 1) { } else if (highres == 1) {
return `-filter:0 scale=-1:1920 ` + encoder; return `-filter:0 scale=-1:1920 ` + encoder;
} else if (crop != "0") { } else if (crop != "0") {
return crop + encoder; return crop + encoder;
} else { } else {
return encoder; return encoder;
} }
} }
function execCommand(cmd) { function execCommand(cmd) {
const exec = require('child_process').exec; const exec = require("child_process").exec;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => { exec(cmd, (error, stdout, stderr) => {
if (error) { if (error) {
console.warn(error); console.warn(error);
} }
resolve(stdout? stdout : stderr); resolve(stdout ? stdout : stderr);
});
}); });
});
} }
module.exports.details = details; module.exports.details = details;

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_fd5T_Sparticus_4K_AC3_No_Subs", id: "Tdarr_Plugin_fd5T_Sparticus_4K_AC3_No_Subs",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -10,192 +6,181 @@ function details() {
Type: "Video", Type: "Video",
Description: `[Contains built-in filter] This plugin for 4K video removes subs. If no AC3 track exists, it adds one (max 5.1 channels). If only an AC3 commentary track exists, it adds a new AC3 main track (max 5.1 channels). The output container is the same as the original file. \n\n`, Description: `[Contains built-in filter] This plugin for 4K video removes subs. If no AC3 track exists, it adds one (max 5.1 channels). If only an AC3 commentary track exists, it adds a new AC3 main track (max 5.1 channels). The output container is the same as the original file. \n\n`,
Version: "1.04", Version: "1.04",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_fd5T_Sparticus_4K_AC3_No_Subs.js", Link:
Tags:'pre-processing,ffmpeg', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_fd5T_Sparticus_4K_AC3_No_Subs.js",
} Tags: "pre-processing,ffmpeg",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mp4', container: ".mp4",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: false, reQueueAfter: false,
infoLog: '', infoLog: "",
};
}
response.container = '.' + file.container
response.FFmpegMode = true
response.container = "." + file.container;
response.FFmpegMode = true;
if (file.fileMedium !== "video" || file.video_resolution !== "4KUHD") { if (file.fileMedium !== "video" || file.video_resolution !== "4KUHD") {
console.log("File is not a 4K video");
response.infoLog += "☒File is not a 4K video \n";
console.log("File is not a 4K video")
response.infoLog += "☒File is not a 4K video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
var ac3TrackCount = 0;
var AC3CommentaryCount = 0;
var hasSubs = false;
var ac3TrackCount = 0 var commentaryStreamIdx = false;
var AC3CommentaryCount = 0 var audioIdx = -1;
var hasSubs = false
var commentaryStreamIdx = false
var audioIdx = -1
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
//keep track of audio streams for when removing commentary track //keep track of audio streams for when removing commentary track
try { try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
audioIdx++ audioIdx++;
} }
} catch (err) { } } catch (err) {}
//check if commentary track and assing audio stream number //check if commentary track and assing audio stream number
try { try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].tags.title.toLowerCase().includes("commentary")) { if (
commentaryStreamIdx = audioIdx file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" &&
file.ffProbeData.streams[i].tags.title
.toLowerCase()
.includes("commentary")
) {
commentaryStreamIdx = audioIdx;
} }
} catch (err) { } } catch (err) {}
//check if commentary AC3 track //check if commentary AC3 track
try { try {
if (
if (file.ffProbeData.streams[i].codec_name.toLowerCase() == "ac3" && file.ffProbeData.streams[i].tags.title.toLowerCase().includes("commentary")) { file.ffProbeData.streams[i].codec_name.toLowerCase() == "ac3" &&
AC3CommentaryCount++ file.ffProbeData.streams[i].tags.title
.toLowerCase()
.includes("commentary")
) {
AC3CommentaryCount++;
} }
} catch (err) { } } catch (err) {}
//check if AC3 track //check if AC3 track
try { try {
if (file.ffProbeData.streams[i].codec_name.toLowerCase() == "ac3") { if (file.ffProbeData.streams[i].codec_name.toLowerCase() == "ac3") {
ac3TrackCount++ ac3TrackCount++;
} }
} catch (err) { } } catch (err) {}
//check if subs track //check if subs track
try { try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") { if (
hasSubs = true file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle"
) {
hasSubs = true;
} }
} catch (err) { } } catch (err) {}
} }
var hasOnlyAC3TrackCommentaries;
var hasOnlyAC3TrackCommentaries
if (ac3TrackCount > 0 && AC3CommentaryCount == ac3TrackCount) { if (ac3TrackCount > 0 && AC3CommentaryCount == ac3TrackCount) {
hasOnlyAC3TrackCommentaries = true hasOnlyAC3TrackCommentaries = true;
} else { } else {
hasOnlyAC3TrackCommentaries = false hasOnlyAC3TrackCommentaries = false;
} }
var hasNoAC3Track;
var hasNoAC3Track
if (ac3TrackCount == 0) { if (ac3TrackCount == 0) {
hasNoAC3Track = true hasNoAC3Track = true;
} else { } else {
hasNoAC3Track = false hasNoAC3Track = false;
} }
//max 5.1 audio in AC3 output //max 5.1 audio in AC3 output
var channels = file.ffProbeData.streams[1].channels var channels = file.ffProbeData.streams[1].channels;
if (channels > 6) { if (channels > 6) {
channels = 6 channels = 6;
} }
if (hasOnlyAC3TrackCommentaries && hasSubs) { if (hasOnlyAC3TrackCommentaries && hasSubs) {
response.infoLog += "☒File has no AC3 main track (has AC3 commentary) and has subs \n" response.infoLog +=
response.preset = ',-sn -map 0:v -map 0:a:0 -map 0:a -map 0:d? -c copy -c:a:0 ac3 -ac ' + channels "☒File has no AC3 main track (has AC3 commentary) and has subs \n";
response.preset =
",-sn -map 0:v -map 0:a:0 -map 0:a -map 0:d? -c copy -c:a:0 ac3 -ac " +
channels;
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
} }
if (hasNoAC3Track && hasSubs) { if (hasNoAC3Track && hasSubs) {
response.infoLog += "☒File has no AC3 main track and has subs \n" response.infoLog += "☒File has no AC3 main track and has subs \n";
response.preset = ',-sn -map 0:v -map 0:a:0 -map 0:a -map 0:d? -c copy -c:a:0 ac3 -ac ' + channels response.preset =
",-sn -map 0:v -map 0:a:0 -map 0:a -map 0:d? -c copy -c:a:0 ac3 -ac " +
channels;
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
} }
if (commentaryStreamIdx !== false) { if (commentaryStreamIdx !== false) {
response.infoLog += `☒File has AC3 commentary track in stream ${commentaryStreamIdx} \n`;
response.infoLog += `☒File has AC3 commentary track in stream ${commentaryStreamIdx} \n` response.preset = `,-map 0 -map -0:a:${commentaryStreamIdx} -codec copy`;
response.preset = `,-map 0 -map -0:a:${commentaryStreamIdx} -codec copy`
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
} }
if (!!hasOnlyAC3TrackCommentaries == true) { if (!!hasOnlyAC3TrackCommentaries == true) {
response.infoLog += "☒File has no AC3 main track (has AC3 commentary)! \n" response.infoLog +=
response.preset = ',-map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ac3 -ac ' + channels "☒File has no AC3 main track (has AC3 commentary)! \n";
response.preset =
",-map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ac3 -ac " +
channels;
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
} else { } else {
response.infoLog += "☑File does not have only AC3 track commentaries! \n" response.infoLog += "☑File does not have only AC3 track commentaries! \n";
} }
if (hasNoAC3Track) { if (hasNoAC3Track) {
response.infoLog += "☒File has no AC3 track! \n" response.infoLog += "☒File has no AC3 track! \n";
response.preset = ',-map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ac3 -ac ' + channels response.preset =
",-map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ac3 -ac " +
channels;
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
} else { } else {
response.infoLog += "☑File has AC3 track! \n" response.infoLog += "☑File has AC3 track! \n";
} }
if (hasSubs) { if (hasSubs) {
response.infoLog += "☒File has subs! \n" response.infoLog += "☒File has subs! \n";
response.preset = ',-sn -map 0 -c copy' response.preset = ",-sn -map 0 -c copy";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
} else { } else {
response.infoLog += "☑File has no subs \n" response.infoLog += "☑File has no subs \n";
} }
response.infoLog += "☑File meets conditions! \n";
response.infoLog += "☑File meets conditions! \n" return response;
return response
} }
} }

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_hk75_Drawmonster_MP4_AAC_No_Subs_No_metaTitle", id: "Tdarr_Plugin_hk75_Drawmonster_MP4_AAC_No_Subs_No_metaTitle",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,211 +7,164 @@ function details() {
Description: `[Contains built-in filter] This plugin removes subs, metadata (if a title exists) and adds a stereo 192kbit AAC track if an AAC track (English or any) doesn't exist. The output container is mp4. \n\n Description: `[Contains built-in filter] This plugin removes subs, metadata (if a title exists) and adds a stereo 192kbit AAC track if an AAC track (English or any) doesn't exist. The output container is mp4. \n\n
`, `,
Version: "1.07", Version: "1.07",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_hk75_Drawmonster_MP4_AAC_No_Subs_No_metaTitle.js", Link:
Tags:'pre-processing,ffmpeg', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_hk75_Drawmonster_MP4_AAC_No_Subs_No_metaTitle.js",
} Tags: "pre-processing,ffmpeg",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false,
preset: "",
container: ".mp4",
handBrakeMode: false,
FFmpegMode: false,
reQueueAfter: false,
infoLog: "",
};
processFile : false, response.FFmpegMode = true;
preset : '',
container : '.mp4',
handBrakeMode : false,
FFmpegMode : false,
reQueueAfter : false,
infoLog : '',
}
response.FFmpegMode = true
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else {
} else { var hasPreferredLangTrack = false;
var hasPreferredLangInRequiredCodecs = false;
var hasAnyInRequiredCodecs = false;
var hasPreferredLangTrack = false var audioIdx = -1;
var hasPreferredLangInRequiredCodecs = false var engTrackIdx = -1;
var hasAnyInRequiredCodecs = false
var audioIdx = -1 var requiredAudioCodecs = "aac";
var engTrackIdx = -1 var preferredLangTrack = "eng";
var preferredCodec = "aac";
var requiredAudioCodecs = "aac" var hasSubs = false;
var preferredLangTrack = "eng"
var preferredCodec = "aac"
var hasSubs = false
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try {
if(file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle"){
hasSubs = true
}
} catch (err) { }
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try {
if (
file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle"
) {
hasSubs = true;
}
} catch (err) {}
try { try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
audioIdx++ audioIdx++;
} }
} catch (err) { } } catch (err) {}
try { try {
if (requiredAudioCodecs.includes(file.ffProbeData.streams[i].codec_name)) { if (
hasAnyInRequiredCodecs = true requiredAudioCodecs.includes(file.ffProbeData.streams[i].codec_name)
) {
hasAnyInRequiredCodecs = true;
} }
} catch (err) { } } catch (err) {}
try { try {
if ((requiredAudioCodecs.includes(file.ffProbeData.streams[i].codec_name)) && file.ffProbeData.streams[i].tags.language.toLowerCase().includes(preferredLangTrack)) { if (
hasPreferredLangInRequiredCodecs = true requiredAudioCodecs.includes(
file.ffProbeData.streams[i].codec_name
) &&
file.ffProbeData.streams[i].tags.language
.toLowerCase()
.includes(preferredLangTrack)
) {
hasPreferredLangInRequiredCodecs = true;
} }
} catch (err) { } } catch (err) {}
try { try {
if (file.ffProbeData.streams[i].tags.language.toLowerCase().includes(preferredLangTrack) && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (
hasPreferredLangTrack = true file.ffProbeData.streams[i].tags.language
engTrackIdx = audioIdx .toLowerCase()
.includes(preferredLangTrack) &&
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio"
) {
hasPreferredLangTrack = true;
engTrackIdx = audioIdx;
} }
} catch (err) { } } catch (err) {}
}
}
if (hasPreferredLangInRequiredCodecs) {
response.infoLog += `☑File already has ${preferredLangTrack} language track in ${requiredAudioCodecs}! \n`
if (hasPreferredLangInRequiredCodecs) {
response.infoLog += `☑File already has ${preferredLangTrack} language track in ${requiredAudioCodecs}! \n`;
} else if (hasPreferredLangTrack) { } else if (hasPreferredLangTrack) {
response.processFile = true; response.processFile = true;
response.preset = `,-map 0:v -map 0:a:${engTrackIdx} -map 0:a -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2 -strict -2` response.preset = `,-map 0:v -map 0:a:${engTrackIdx} -map 0:a -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2 -strict -2`;
response.container = '.mp4' response.container = ".mp4";
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += `☒File has ${preferredLangTrack} language track but not in ${requiredAudioCodecs}! \n` response.infoLog += `☒File has ${preferredLangTrack} language track but not in ${requiredAudioCodecs}! \n`;
return response return response;
} else if (!hasAnyInRequiredCodecs) { } else if (!hasAnyInRequiredCodecs) {
if (audioIdx == -1) { if (audioIdx == -1) {
response.infoLog += `☒File does not have any audio streams. Can't create ${preferredCodec} track. \n` response.infoLog += `☒File does not have any audio streams. Can't create ${preferredCodec} track. \n`;
} else { } else {
response.processFile = true; response.processFile = true;
response.preset = `,-map 0:v -map 0:a:0 -map 0:a -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2 -strict -2` response.preset = `,-map 0:v -map 0:a:0 -map 0:a -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2 -strict -2`;
response.container = '.mp4' response.container = ".mp4";
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += `☒File has no language track in ${requiredAudioCodecs}. No ${preferredLangTrack} track marked so transcoding audio track 1 into ${preferredCodec}! \n` response.infoLog += `☒File has no language track in ${requiredAudioCodecs}. No ${preferredLangTrack} track marked so transcoding audio track 1 into ${preferredCodec}! \n`;
return response return response;
} }
} }
if (file.meta.Title != "undefined" && hasSubs) {
response.infoLog += "☒File has title and has subs \n";
response.preset = ",-sn -map_metadata -1 -c:v copy -c:a copy";
if(file.meta.Title != "undefined" && hasSubs){
response.infoLog += "☒File has title and has subs \n"
response.preset = ',-sn -map_metadata -1 -c:v copy -c:a copy'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
} }
///
if(file.meta.Title != undefined ){
response.infoLog += "☒File has title metadata \n" ///
response.preset = ',-map_metadata -1 -c:v copy -c:a copy' if (file.meta.Title != undefined) {
response.infoLog += "☒File has title metadata \n";
response.preset = ",-map_metadata -1 -c:v copy -c:a copy";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
}else{ } else {
response.infoLog += "☑File has no title metadata \n" response.infoLog += "☑File has no title metadata \n";
} }
if(hasSubs){
response.infoLog += "☒File has subs \n" if (hasSubs) {
response.preset = ',-sn -c:v copy -c:a copy' response.infoLog += "☒File has subs \n";
response.preset = ",-sn -c:v copy -c:a copy";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
} else {
}else{ response.infoLog += "☑File has no subs \n";
response.infoLog += "☑File has no subs \n" }
}
if( file.container != 'mp4'){ if (file.container != "mp4") {
response.infoLog += "☒File is not in mp4 container! \n" response.infoLog += "☒File is not in mp4 container! \n";
response.preset = ', -c:v copy -c:a copy' response.preset = ", -c:v copy -c:a copy";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
}else{ } else {
response.infoLog += "☑File is in mp4 container! \n" response.infoLog += "☑File is in mp4 container! \n";
} }
response.infoLog += "☑File meets conditions! \n"
return response
response.infoLog += "☑File meets conditions! \n";
return response;
} }
} }

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_hk76_GilbN_MP4_AAC_No_metaTitle", id: "Tdarr_Plugin_hk76_GilbN_MP4_AAC_No_metaTitle",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,93 +7,70 @@ function details() {
Description: `[Contains built-in filter] This plugin removes metadata (if a title exists) and adds a stereo 192kbit AAC track if an AAC track (any) doesn't exist. The output container is mp4. \n\n Description: `[Contains built-in filter] This plugin removes metadata (if a title exists) and adds a stereo 192kbit AAC track if an AAC track (any) doesn't exist. The output container is mp4. \n\n
`, `,
Version: "1.01", Version: "1.01",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_hk76_GilbN_MP4_AAC_No_metaTitle.js", Link:
Tags:'pre-processing,ffmpeg', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_hk76_GilbN_MP4_AAC_No_metaTitle.js",
} Tags: "pre-processing,ffmpeg",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mp4', container: ".mp4",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: false, reQueueAfter: false,
infoLog: '', infoLog: "",
};
}
response.FFmpegMode = true
response.FFmpegMode = true;
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
var jsonString = JSON.stringify(file);
var jsonString = JSON.stringify(file) if (file.container != "mp4") {
response.infoLog += "☒File is not in mp4 container! \n";
if (file.container != 'mp4') { response.preset = ", -map 0 -c copy";
response.infoLog += "☒File is not in mp4 container! \n"
response.preset = ', -map 0 -c copy'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
} else { } else {
response.infoLog += "☑File is in mp4 container! \n" response.infoLog += "☑File is in mp4 container! \n";
} }
if (file.meta.Title != undefined) { if (file.meta.Title != undefined) {
response.infoLog += "☒File has title metadata \n";
response.infoLog += "☒File has title metadata \n" response.preset = ",-map_metadata -1 -map 0 -c copy";
response.preset = ',-map_metadata -1 -map 0 -c copy'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
} else { } else {
response.infoLog += "☑File has no title metadata \n" response.infoLog += "☑File has no title metadata \n";
} }
if (!jsonString.includes("aac")) { if (!jsonString.includes("aac")) {
response.infoLog += "☒File has no aac track";
response.infoLog += "☒File has no aac track" response.preset =
response.preset = ',-map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 aac -b:a:0 192k -ac 2' ",-map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 aac -b:a:0 192k -ac 2";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
} else { } else {
response.infoLog += "☑File has aac track \n" response.infoLog += "☑File has aac track \n";
} }
response.infoLog += "☑File meets conditions! \n";
return response;
response.infoLog += "☑File meets conditions! \n"
return response
} }
} }

@ -1,5 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_lmg1_Reorder_Streams", id: "Tdarr_Plugin_lmg1_Reorder_Streams",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -8,59 +7,48 @@ function details() {
Description: `[Contains built-in filter] This plugin will move the video stream to the front so Tdarr will recognize the codec correctly.\n\n`, Description: `[Contains built-in filter] This plugin will move the video stream to the front so Tdarr will recognize the codec correctly.\n\n`,
Version: "1.00", Version: "1.00",
Link: "https://github.com/luigi311/Tdarr_Plugin_lmg1_Reorder_Streams", Link: "https://github.com/luigi311/Tdarr_Plugin_lmg1_Reorder_Streams",
Tags:'pre-processing,ffmpeg', Tags: "pre-processing,ffmpeg",
} };
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false,
processFile : false, preset: "",
preset : '', container: ".mp4",
container : '.mp4', handBrakeMode: false,
handBrakeMode : false, FFmpegMode: false,
FFmpegMode : false, reQueueAfter: false,
reQueueAfter : false, infoLog: "",
infoLog : '', };
}
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
console.log("File is not video") response.infoLog += " File is not video\n";
response.infoLog += " File is not video\n"
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
response.FFmpegMode = true;
response.container = "." + file.container;
response.FFmpegMode = true if (file.ffProbeData.streams[0].codec_type != "video") {
response.container = '.' + file.container response.infoLog += "Video is not in the first stream";
response.preset =
if(file.ffProbeData.streams[0].codec_type != 'video') { ",-map 0:v? -map 0:a? -map 0:s? -map 0:d? -map 0:t? -c copy";
response.infoLog += "Video is not in the first stream"
response.preset = ',-map 0:v? -map 0:a? -map 0:s? -map 0:d? -map 0:t? -c copy'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
} else { } else {
response.infoLog += "File has video in first stream\n";
response.infoLog += "File has video in first stream\n"
} }
response.infoLog += " File meets conditions!\n" response.infoLog += " File meets conditions!\n";
return response return response;
} }
} }

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_nc7x_Drawmonster_No_Title_Meta", id: "Tdarr_Plugin_nc7x_Drawmonster_No_Title_Meta",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,66 +7,53 @@ function details() {
Description: `[Contains built-in filter] This plugin removes metadata (if a title exists). The output container is the same as the original. \n\n Description: `[Contains built-in filter] This plugin removes metadata (if a title exists). The output container is the same as the original. \n\n
`, `,
Version: "1.00", Version: "1.00",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_nc7x_Drawmonster_No_Title_Meta.js", Link:
Tags:'pre-processing,ffmpeg', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_nc7x_Drawmonster_No_Title_Meta.js",
} Tags: "pre-processing,ffmpeg",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mp4', container: ".mp4",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: false, reQueueAfter: false,
infoLog: '', infoLog: "",
};
}
response.container = '.' + file.container
response.FFmpegMode = true
response.container = "." + file.container;
response.FFmpegMode = true;
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
// var jsonString = JSON.stringify(file)
// var jsonString = JSON.stringify(file)
if (file.meta.Title != undefined) { if (file.meta.Title != undefined) {
response.infoLog += "☒File has title metadata \n";
response.infoLog += "☒File has title metadata \n" response.preset = ",-map_metadata -1 -map 0 -c copy";
response.preset = ',-map_metadata -1 -map 0 -c copy'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
} else { } else {
response.infoLog += "☑File has no title metadata \n" response.infoLog += "☑File has no title metadata \n";
} }
response.infoLog += "☑File meets conditions! \n";
response.infoLog += "☑File meets conditions! \n" return response;
return response
} }
} }
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -4,63 +4,64 @@ function details() {
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "FFMPEG HQ 10-bit HEVC MKV for Animation", Name: "FFMPEG HQ 10-bit HEVC MKV for Animation",
Type: "Video", Type: "Video",
Operation:"Transcode", Operation: "Transcode",
Description: `[Contains built-in filter] High Quality FFMPEG transcoding settings for Animation. Converts all audio to AAC 512K. Preserves track names, metadata and attachments/fonts. Proper use of x265-params. CRF 18. Preset medium. 10-Bit Video encoding. Skips h.265 encoded videos. The output container is mkv. \n\n`, Description: `[Contains built-in filter] High Quality FFMPEG transcoding settings for Animation. Converts all audio to AAC 512K. Preserves track names, metadata and attachments/fonts. Proper use of x265-params. CRF 18. Preset medium. 10-Bit Video encoding. Skips h.265 encoded videos. The output container is mkv. \n\n`,
Version: "1.1", Version: "1.1",
Link: "", Link: "",
Tags:"pre-processing,ffmpeg,h265,aac,10bit,anime," Tags: "pre-processing,ffmpeg,h265,aac,10bit,anime,",
} };
} }
function plugin(file) { function plugin(file) {
var transcode = 0; //if this var changes to 1 the file will be transcoded var transcode = 0; //if this var changes to 1 the file will be transcoded
//default values that will be returned //default values that will be returned
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mkv', container: ".mkv",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: true, reQueueAfter: true,
infoLog: '' infoLog: "",
} };
//check if the file is a video, if not the function will be stopped immediately //check if the file is a video, if not the function will be stopped immediately
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
response.processFile = false response.processFile = false;
response.infoLog += "☒File is not a video! \n" response.infoLog += "☒File is not a video! \n";
return response return response;
} else { } else {
response.infoLog += "☑File is a video! \n" response.infoLog += "☑File is a video! \n";
} }
//check if the file is already hevc, it will not be transcoded if true and the function will be stopped immediately //check if the file is already hevc, it will not be transcoded if true and the function will be stopped immediately
if (file.ffProbeData.streams[0].codec_name == 'hevc') { if (file.ffProbeData.streams[0].codec_name == "hevc") {
response.processFile = false response.processFile = false;
response.infoLog += "☑File is already in hevc! \n" response.infoLog += "☑File is already in hevc! \n";
return response return response;
} }
//Transcoding options //Transcoding options
{ {
response.preset = ',-map 0 -c:s copy -movflags use_metadata_tags -c:a aac -b:a 512k -c:v:0 libx265 -preset medium -x265-params crf=18:tune=animation:qcomp=0.7:aq-strength=1.1 -pix_fmt yuv420p10le -f matroska' response.preset =
",-map 0 -c:s copy -movflags use_metadata_tags -c:a aac -b:a 512k -c:v:0 libx265 -preset medium -x265-params crf=18:tune=animation:qcomp=0.7:aq-strength=1.1 -pix_fmt yuv420p10le -f matroska";
transcode = 1; transcode = 1;
} }
//check if the file is eligible for transcoding //check if the file is eligible for transcoding
//if true the neccessary response values will be changed //if true the neccessary response values will be changed
if (transcode == 1) { if (transcode == 1) {
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += `☒File is ${file.video_resolution} but is not hevc!\n` response.infoLog += `☒File is ${file.video_resolution} but is not hevc!\n`;
response.infoLog += `☒File will be transcoded!\n` response.infoLog += `☒File will be transcoded!\n`;
} }
return response return response;
} }
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -4,168 +4,171 @@ function details() {
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "FFmpeg Tiered HEVC MKV", Name: "FFmpeg Tiered HEVC MKV",
Type: "Video", Type: "Video",
Operation:"Transcode", Operation: "Transcode",
Description: `[Contains built-in filter] This plugin uses different FFmpeg transcoding settings for 480p,576p,720p and 1080p. If files are not in hevc they will be transcoded. The output container is mkv. \n\n`, Description: `[Contains built-in filter] This plugin uses different FFmpeg transcoding settings for 480p,576p,720p and 1080p. If files are not in hevc they will be transcoded. The output container is mkv. \n\n`,
Version: "1.01", Version: "1.01",
Link: "", Link: "",
Tags:"pre-processing,ffmpeg,h265,video only," Tags: "pre-processing,ffmpeg,h265,video only,",
} };
} }
function plugin(file) { function plugin(file) {
var transcode = 0; //if this var changes to 1 the file will be transcoded var transcode = 0; //if this var changes to 1 the file will be transcoded
//default values that will be returned //default values that will be returned
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mkv', container: ".mkv",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: true, reQueueAfter: true,
infoLog: '' infoLog: "",
} };
//check if the file is a video, if not the function will be stopped immediately //check if the file is a video, if not the function will be stopped immediately
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
response.processFile = false response.processFile = false;
response.infoLog += "☒File is not a video! \n" response.infoLog += "☒File is not a video! \n";
return response return response;
} else { } else {
response.infoLog += "☑File is a video! \n" response.infoLog += "☑File is a video! \n";
} }
//check if the file is already hevc, it will not be transcoded if true and the function will be stopped immediately //check if the file is already hevc, it will not be transcoded if true and the function will be stopped immediately
if (file.ffProbeData.streams[0].codec_name == 'hevc') { if (file.ffProbeData.streams[0].codec_name == "hevc") {
response.processFile = false response.processFile = false;
response.infoLog += "☑File is already in hevc! \n" response.infoLog += "☑File is already in hevc! \n";
return response return response;
} }
//file will be encoded if the resolution is 480p or 576p //file will be encoded if the resolution is 480p or 576p
//codec will be checked so it can be transcoded correctly //codec will be checked so it can be transcoded correctly
if(file.video_resolution === "480p" || file.video_resolution === "576p" ) { if (file.video_resolution === "480p" || file.video_resolution === "576p") {
if (file.video_codec_name == 'h263') { if (file.video_codec_name == "h263") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27";
else if (file.video_codec_name == 'h264') { } else if (file.video_codec_name == "h264") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27";
else if (file.video_codec_name == 'mjpeg') { } else if (file.video_codec_name == "mjpeg") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27";
else if (file.video_codec_name == 'mpeg1') { } else if (file.video_codec_name == "mpeg1") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27";
else if (file.video_codec_name == 'mpeg2') { } else if (file.video_codec_name == "mpeg2") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27";
else if (file.video_codec_name == 'mpeg4') { } else if (file.video_codec_name == "mpeg4") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27";
else if (file.video_codec_name == 'vc1') { } else if (file.video_codec_name == "vc1") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27";
else if (file.video_codec_name == 'vp8') { } else if (file.video_codec_name == "vp8") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27";
else if (file.video_codec_name == 'vp9') { } else if (file.video_codec_name == "vp9") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27";
else { } else {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 27";
}
transcode = 1; transcode = 1;
} }
//file will be encoded if the resolution is 720p //file will be encoded if the resolution is 720p
//codec will be checked so it can be transcoded correctly //codec will be checked so it can be transcoded correctly
if(file.video_resolution === "720p") { if (file.video_resolution === "720p") {
if (file.video_codec_name == 'h263') { if (file.video_codec_name == "h263") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25";
else if (file.video_codec_name == 'h264') { } else if (file.video_codec_name == "h264") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25";
else if (file.video_codec_name == 'mjpeg') { } else if (file.video_codec_name == "mjpeg") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25";
else if (file.video_codec_name == 'mpeg1') { } else if (file.video_codec_name == "mpeg1") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25";
else if (file.video_codec_name == 'mpeg2') { } else if (file.video_codec_name == "mpeg2") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25";
else if (file.video_codec_name == 'mpeg4') { } else if (file.video_codec_name == "mpeg4") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25";
else if (file.video_codec_name == 'vc1') { } else if (file.video_codec_name == "vc1") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25";
else if (file.video_codec_name == 'vp8') { } else if (file.video_codec_name == "vp8") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25";
else if (file.video_codec_name == 'vp9') { } else if (file.video_codec_name == "vp9") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25";
else { } else {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 25";
}
transcode = 1; transcode = 1;
} }
//file will be encoded if the resolution is 1080p //file will be encoded if the resolution is 1080p
//codec will be checked so it can be transcoded correctly //codec will be checked so it can be transcoded correctly
if(file.video_resolution === "1080p") { if (file.video_resolution === "1080p") {
if (file.video_codec_name == 'h263') { if (file.video_codec_name == "h263") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23";
else if (file.video_codec_name == 'h264') { } else if (file.video_codec_name == "h264") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23";
else if (file.video_codec_name == 'mjpeg') { } else if (file.video_codec_name == "mjpeg") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23";
else if (file.video_codec_name == 'mpeg1') { } else if (file.video_codec_name == "mpeg1") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23";
else if (file.video_codec_name == 'mpeg2') { } else if (file.video_codec_name == "mpeg2") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23";
else if (file.video_codec_name == 'mpeg4') { } else if (file.video_codec_name == "mpeg4") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23";
else if (file.video_codec_name == 'vc1') { } else if (file.video_codec_name == "vc1") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23";
else if (file.video_codec_name == 'vp8') { } else if (file.video_codec_name == "vp8") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23";
else if (file.video_codec_name == 'vp9') { } else if (file.video_codec_name == "vp9") {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23";
else { } else {
response.preset = ',-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23' response.preset =
} ",-map 0:v -map 0:s? -c:s srt -map 0:a -c copy -c:v:0 libx265 -preset fast -crf 23";
}
transcode = 1; transcode = 1;
} }
//check if the file is eligible for transcoding //check if the file is eligible for transcoding
//if true the neccessary response values will be changed //if true the neccessary response values will be changed
if (transcode == 1) { if (transcode == 1) {
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += `☒File is ${file.video_resolution} but is not hevc!\n` response.infoLog += `☒File is ${file.video_resolution} but is not hevc!\n`;
response.infoLog += `☒File will be transcoded!\n` response.infoLog += `☒File will be transcoded!\n`;
} }
return response return response;
} }
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_s710_nick_h265_nvenc_4K", id: "Tdarr_Plugin_s710_nick_h265_nvenc_4K",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,166 +7,144 @@ function details() {
Description: `[Contains built-in filter] This plugin transcodes all 4K videos to h265 using nvenc (if not in h265 already). For 4K and files in other resolutions: If not in mkv the file is remuxed into mkv. If the English language track is not in AC3,EAC3 or DTS then an AC3 track is added.\n\n Description: `[Contains built-in filter] This plugin transcodes all 4K videos to h265 using nvenc (if not in h265 already). For 4K and files in other resolutions: If not in mkv the file is remuxed into mkv. If the English language track is not in AC3,EAC3 or DTS then an AC3 track is added.\n\n
`, `,
Version: "1.00", Version: "1.00",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_s710_nick_h265_nvenc_4K.js", Link:
Tags:'pre-processing,ffmpeg,nvenc h265', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_s710_nick_h265_nvenc_4K.js",
} Tags: "pre-processing,ffmpeg,nvenc h265",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mp4', container: ".mp4",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: false, reQueueAfter: false,
infoLog: '', infoLog: "",
};
}
response.FFmpegMode = true
response.FFmpegMode = true;
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
var jsonString = JSON.stringify(file);
response.container = ".mkv";
var jsonString = JSON.stringify(file) if (
response.container = '.mkv' file.ffProbeData.streams[0].codec_name == "hevc" ||
file.video_resolution !== "4KUHD"
) {
if (file.ffProbeData.streams[0].codec_name == 'hevc' || file.video_resolution !== "4KUHD") { var hasPreferredLangTrack = false;
var hasPreferredLangInRequiredCodecs = false;
var hasPreferredLangTrack = false var hasAnyInRequiredCodecs = false;
var hasPreferredLangInRequiredCodecs = false
var hasAnyInRequiredCodecs = false
var audioIdx = -1
var engTrackIdx = -1
var requiredAudioCodecs = "ac3,eac3,dts"
var preferredLangTrack = "eng"
var preferredCodec = "ac3"
var audioIdx = -1;
var engTrackIdx = -1;
var requiredAudioCodecs = "ac3,eac3,dts";
var preferredLangTrack = "eng";
var preferredCodec = "ac3";
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
audioIdx++ audioIdx++;
} }
} catch (err) { } } catch (err) {}
try { try {
if (requiredAudioCodecs.includes(file.ffProbeData.streams[i].codec_name)) { if (
hasAnyInRequiredCodecs = true requiredAudioCodecs.includes(file.ffProbeData.streams[i].codec_name)
) {
hasAnyInRequiredCodecs = true;
} }
} catch (err) { } } catch (err) {}
try { try {
if ((requiredAudioCodecs.includes(file.ffProbeData.streams[i].codec_name)) && file.ffProbeData.streams[i].tags.language.toLowerCase().includes(preferredLangTrack)) { if (
hasPreferredLangInRequiredCodecs = true requiredAudioCodecs.includes(
file.ffProbeData.streams[i].codec_name
) &&
file.ffProbeData.streams[i].tags.language
.toLowerCase()
.includes(preferredLangTrack)
) {
hasPreferredLangInRequiredCodecs = true;
} }
} catch (err) { } } catch (err) {}
try { try {
if (file.ffProbeData.streams[i].tags.language.toLowerCase().includes(preferredLangTrack) && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (
hasPreferredLangTrack = true file.ffProbeData.streams[i].tags.language
engTrackIdx = audioIdx .toLowerCase()
.includes(preferredLangTrack) &&
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio"
) {
hasPreferredLangTrack = true;
engTrackIdx = audioIdx;
} }
} catch (err) { } } catch (err) {}
} }
if (hasPreferredLangInRequiredCodecs) { if (hasPreferredLangInRequiredCodecs) {
response.infoLog += `☑File already has ${preferredLangTrack} language track in ${requiredAudioCodecs}! \n`;
response.infoLog += `☑File already has ${preferredLangTrack} language track in ${requiredAudioCodecs}! \n`
} else if (hasPreferredLangTrack) { } else if (hasPreferredLangTrack) {
response.processFile = true; response.processFile = true;
response.preset = `,-map 0:v -map 0:a:${engTrackIdx} -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2` response.preset = `,-map 0:v -map 0:a:${engTrackIdx} -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2`;
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += `☒File has ${preferredLangTrack} language track but not in ${requiredAudioCodecs}! \n` response.infoLog += `☒File has ${preferredLangTrack} language track but not in ${requiredAudioCodecs}! \n`;
return response return response;
} else if (!hasAnyInRequiredCodecs) { } else if (!hasAnyInRequiredCodecs) {
if (audioIdx == -1) { if (audioIdx == -1) {
response.infoLog += `☒File does not have any audio streams. Can't create ${preferredCodec} track. \n` response.infoLog += `☒File does not have any audio streams. Can't create ${preferredCodec} track. \n`;
} else { } else {
response.processFile = true; response.processFile = true;
response.preset = `,-map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2` response.preset = `,-map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2`;
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += `☒File has no language track in ${requiredAudioCodecs}. No ${preferredLangTrack} track marked so transcoding audio track 1 into ${preferredCodec}! \n` response.infoLog += `☒File has no language track in ${requiredAudioCodecs}. No ${preferredLangTrack} track marked so transcoding audio track 1 into ${preferredCodec}! \n`;
return response return response;
} }
} }
if (file.container != "mkv") {
if (file.container != 'mkv') {
response.processFile = true; response.processFile = true;
response.preset = ', -map 0 -c copy' response.preset = ", -map 0 -c copy";
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File is not in mkv container! \n" response.infoLog += "☒File is not in mkv container! \n";
return response return response;
} else { } else {
response.infoLog += "☑File is in mkv container! \n";
response.infoLog += "☑File is in mkv container! \n"
} }
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
response.processFile = true; response.processFile = true;
response.preset = '-Z "H.265 MKV 2160p60" --all-audio --all-subtitles' response.preset = '-Z "H.265 MKV 2160p60" --all-audio --all-subtitles';
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode = true response.handBrakeMode = true;
response.FFmpegMode = false response.FFmpegMode = false;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒ 4K file isn't in hevc! \n" response.infoLog += "☒ 4K file isn't in hevc! \n";
return response return response;
} }
} }
} }

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_s7x8_winsome_h265", id: "Tdarr_Plugin_s7x8_winsome_h265",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,166 +7,141 @@ function details() {
Description: `[Contains built-in filter] This plugin transcodes all videos to h265 (if not in h265 already) and remuxes if not in mkv. If the English language track is not in AC3,EAC3 or DTS then an AC3 track is added.\n\n Description: `[Contains built-in filter] This plugin transcodes all videos to h265 (if not in h265 already) and remuxes if not in mkv. If the English language track is not in AC3,EAC3 or DTS then an AC3 track is added.\n\n
`, `,
Version: "1.00", Version: "1.00",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_s7x8_winsome_h265.js", Link:
Tags:'pre-processing,handbrake,ffmpeg,h265', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_s7x8_winsome_h265.js",
} Tags: "pre-processing,handbrake,ffmpeg,h265",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mp4', container: ".mp4",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: false, reQueueAfter: false,
infoLog: '', infoLog: "",
};
}
response.FFmpegMode = true
response.FFmpegMode = true;
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
var jsonString = JSON.stringify(file);
response.container = ".mkv";
var jsonString = JSON.stringify(file) if (file.ffProbeData.streams[0].codec_name == "hevc") {
response.container = '.mkv' var hasPreferredLangTrack = false;
var hasPreferredLangInRequiredCodecs = false;
var hasAnyInRequiredCodecs = false;
if (file.ffProbeData.streams[0].codec_name == 'hevc') {
var hasPreferredLangTrack = false
var hasPreferredLangInRequiredCodecs = false
var hasAnyInRequiredCodecs = false
var audioIdx = -1
var engTrackIdx = -1
var requiredAudioCodecs = "ac3,eac3,dts"
var preferredLangTrack = "eng"
var preferredCodec = "ac3"
var audioIdx = -1;
var engTrackIdx = -1;
var requiredAudioCodecs = "ac3,eac3,dts";
var preferredLangTrack = "eng";
var preferredCodec = "ac3";
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
audioIdx++ audioIdx++;
} }
} catch (err) { } } catch (err) {}
try { try {
if (requiredAudioCodecs.includes(file.ffProbeData.streams[i].codec_name)) { if (
hasAnyInRequiredCodecs = true requiredAudioCodecs.includes(file.ffProbeData.streams[i].codec_name)
) {
hasAnyInRequiredCodecs = true;
} }
} catch (err) { } } catch (err) {}
try { try {
if ((requiredAudioCodecs.includes(file.ffProbeData.streams[i].codec_name)) && file.ffProbeData.streams[i].tags.language.toLowerCase().includes(preferredLangTrack)) { if (
hasPreferredLangInRequiredCodecs = true requiredAudioCodecs.includes(
file.ffProbeData.streams[i].codec_name
) &&
file.ffProbeData.streams[i].tags.language
.toLowerCase()
.includes(preferredLangTrack)
) {
hasPreferredLangInRequiredCodecs = true;
} }
} catch (err) { } } catch (err) {}
try { try {
if (file.ffProbeData.streams[i].tags.language.toLowerCase().includes(preferredLangTrack) && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (
hasPreferredLangTrack = true file.ffProbeData.streams[i].tags.language
engTrackIdx = audioIdx .toLowerCase()
.includes(preferredLangTrack) &&
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio"
) {
hasPreferredLangTrack = true;
engTrackIdx = audioIdx;
} }
} catch (err) { } } catch (err) {}
} }
if (hasPreferredLangInRequiredCodecs) { if (hasPreferredLangInRequiredCodecs) {
response.infoLog += `☑File already has ${preferredLangTrack} language track in ${requiredAudioCodecs}! \n`;
response.infoLog += `☑File already has ${preferredLangTrack} language track in ${requiredAudioCodecs}! \n`
} else if (hasPreferredLangTrack) { } else if (hasPreferredLangTrack) {
response.processFile = true; response.processFile = true;
response.preset = `,-map 0:v -map 0:a:${engTrackIdx} -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2` response.preset = `,-map 0:v -map 0:a:${engTrackIdx} -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2`;
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += `☒File has ${preferredLangTrack} language track but not in ${requiredAudioCodecs}! \n` response.infoLog += `☒File has ${preferredLangTrack} language track but not in ${requiredAudioCodecs}! \n`;
return response return response;
} else if (!hasAnyInRequiredCodecs) { } else if (!hasAnyInRequiredCodecs) {
if (audioIdx == -1) { if (audioIdx == -1) {
response.infoLog += `☒File does not have any audio streams. Can't create ${preferredCodec} track. \n` response.infoLog += `☒File does not have any audio streams. Can't create ${preferredCodec} track. \n`;
} else { } else {
response.processFile = true; response.processFile = true;
response.preset = `,-map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2` response.preset = `,-map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2`;
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += `☒File has no language track in ${requiredAudioCodecs}. No ${preferredLangTrack} track marked so transcoding audio track 1 into ${preferredCodec}! \n` response.infoLog += `☒File has no language track in ${requiredAudioCodecs}. No ${preferredLangTrack} track marked so transcoding audio track 1 into ${preferredCodec}! \n`;
return response return response;
} }
} }
if (file.container != "mkv") {
if (file.container != 'mkv') {
response.processFile = true; response.processFile = true;
response.preset = ', -map 0 -c copy' response.preset = ", -map 0 -c copy";
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File is not in mkv container! \n" response.infoLog += "☒File is not in mkv container! \n";
return response return response;
} else { } else {
response.infoLog += "☑File is in mkv container! \n";
response.infoLog += "☑File is in mkv container! \n"
} }
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
response.processFile = true; response.processFile = true;
response.preset = '-Z "H.265 MKV 2160p60" --all-audio --all-subtitles' response.preset = '-Z "H.265 MKV 2160p60" --all-audio --all-subtitles';
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode = true response.handBrakeMode = true;
response.FFmpegMode = false response.FFmpegMode = false;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File isn't in hevc! \n" response.infoLog += "☒File isn't in hevc! \n";
return response return response;
} }
} }
} }

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_s7x9_winsome_h265_10bit", id: "Tdarr_Plugin_s7x9_winsome_h265_10bit",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,167 +7,142 @@ function details() {
Description: `[Contains built-in filter] This plugin transcodes all videos to h265 10 bit (if not in h265 already) and remuxes if not in mkv. If the English language track is not in AC3,EAC3 or DTS then an AC3 track is added.\n\n Description: `[Contains built-in filter] This plugin transcodes all videos to h265 10 bit (if not in h265 already) and remuxes if not in mkv. If the English language track is not in AC3,EAC3 or DTS then an AC3 track is added.\n\n
`, `,
Version: "1.00", Version: "1.00",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_s7x9_winsome_h265_10bit.js", Link:
Tags:'pre-processing,handbrake,ffmpeg,h265', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_s7x9_winsome_h265_10bit.js",
} Tags: "pre-processing,handbrake,ffmpeg,h265",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mp4', container: ".mp4",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: false, reQueueAfter: false,
infoLog: '', infoLog: "",
};
}
response.FFmpegMode = true
response.FFmpegMode = true;
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
response.infoLog += "☒File is not video";
console.log("File is not video")
response.infoLog += "☒File is not video"
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
var jsonString = JSON.stringify(file);
response.container = ".mkv";
var jsonString = JSON.stringify(file) if (file.ffProbeData.streams[0].codec_name == "hevc") {
response.container = '.mkv' var hasPreferredLangTrack = false;
var hasPreferredLangInRequiredCodecs = false;
var hasAnyInRequiredCodecs = false;
if (file.ffProbeData.streams[0].codec_name == 'hevc') {
var hasPreferredLangTrack = false
var hasPreferredLangInRequiredCodecs = false
var hasAnyInRequiredCodecs = false
var audioIdx = -1
var engTrackIdx = -1
var requiredAudioCodecs = "ac3,eac3,dts"
var preferredLangTrack = "eng"
var preferredCodec = "ac3"
var audioIdx = -1;
var engTrackIdx = -1;
var requiredAudioCodecs = "ac3,eac3,dts";
var preferredLangTrack = "eng";
var preferredCodec = "ac3";
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
audioIdx++ audioIdx++;
} }
} catch (err) { } } catch (err) {}
try { try {
if (requiredAudioCodecs.includes(file.ffProbeData.streams[i].codec_name)) { if (
hasAnyInRequiredCodecs = true requiredAudioCodecs.includes(file.ffProbeData.streams[i].codec_name)
) {
hasAnyInRequiredCodecs = true;
} }
} catch (err) { } } catch (err) {}
try { try {
if ((requiredAudioCodecs.includes(file.ffProbeData.streams[i].codec_name)) && file.ffProbeData.streams[i].tags.language.toLowerCase().includes(preferredLangTrack)) { if (
hasPreferredLangInRequiredCodecs = true requiredAudioCodecs.includes(
file.ffProbeData.streams[i].codec_name
) &&
file.ffProbeData.streams[i].tags.language
.toLowerCase()
.includes(preferredLangTrack)
) {
hasPreferredLangInRequiredCodecs = true;
} }
} catch (err) { } } catch (err) {}
try { try {
if (file.ffProbeData.streams[i].tags.language.toLowerCase().includes(preferredLangTrack) && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (
hasPreferredLangTrack = true file.ffProbeData.streams[i].tags.language
engTrackIdx = audioIdx .toLowerCase()
.includes(preferredLangTrack) &&
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio"
) {
hasPreferredLangTrack = true;
engTrackIdx = audioIdx;
} }
} catch (err) { } } catch (err) {}
} }
if (hasPreferredLangInRequiredCodecs) { if (hasPreferredLangInRequiredCodecs) {
response.infoLog += `☑File already has ${preferredLangTrack} language track in ${requiredAudioCodecs}! \n`;
response.infoLog += `☑File already has ${preferredLangTrack} language track in ${requiredAudioCodecs}! \n`
} else if (hasPreferredLangTrack) { } else if (hasPreferredLangTrack) {
response.processFile = true; response.processFile = true;
response.preset = `,-map 0:v -map 0:a:${engTrackIdx} -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2` response.preset = `,-map 0:v -map 0:a:${engTrackIdx} -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2`;
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += `☒File has ${preferredLangTrack} language track but not in ${requiredAudioCodecs}! \n` response.infoLog += `☒File has ${preferredLangTrack} language track but not in ${requiredAudioCodecs}! \n`;
return response return response;
} else if (!hasAnyInRequiredCodecs) { } else if (!hasAnyInRequiredCodecs) {
if (audioIdx == -1) { if (audioIdx == -1) {
response.infoLog += `☒File does not have any audio streams. Can't create ${preferredCodec} track. \n` response.infoLog += `☒File does not have any audio streams. Can't create ${preferredCodec} track. \n`;
} else { } else {
response.processFile = true; response.processFile = true;
response.preset = `,-map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2` response.preset = `,-map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2`;
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += `☒File has no language track in ${requiredAudioCodecs}. No ${preferredLangTrack} track marked so transcoding audio track 1 into ${preferredCodec}! \n` response.infoLog += `☒File has no language track in ${requiredAudioCodecs}. No ${preferredLangTrack} track marked so transcoding audio track 1 into ${preferredCodec}! \n`;
return response return response;
} }
} }
if (file.container != "mkv") {
if (file.container != 'mkv') {
response.processFile = true; response.processFile = true;
response.preset = ', -map 0 -c copy' response.preset = ", -map 0 -c copy";
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File is not in mkv container! \n" response.infoLog += "☒File is not in mkv container! \n";
return response return response;
} else { } else {
response.infoLog += "☑File is in mkv container! \n";
response.infoLog += "☑File is in mkv container! \n"
} }
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
response.processFile = true; response.processFile = true;
response.preset = '-Z "H.265 MKV 2160p60" -e x265_10bit --all-audio --all-subtitles' response.preset =
response.container = '.mkv' '-Z "H.265 MKV 2160p60" -e x265_10bit --all-audio --all-subtitles';
response.handBrakeMode = true response.container = ".mkv";
response.FFmpegMode = false response.handBrakeMode = true;
response.FFmpegMode = false;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File isn't in hevc! \n" response.infoLog += "☒File isn't in hevc! \n";
return response return response;
} }
} }
} }

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_s7x9_winsome_h265_nvenc", id: "Tdarr_Plugin_s7x9_winsome_h265_nvenc",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,167 +7,142 @@ function details() {
Description: `[Contains built-in filter] This plugin transcodes all videos to h265 using nvenc (if not in h265 already) and remuxes if not in mkv. If the English language track is not in AC3,EAC3 or DTS then an AC3 track is added.\n\n Description: `[Contains built-in filter] This plugin transcodes all videos to h265 using nvenc (if not in h265 already) and remuxes if not in mkv. If the English language track is not in AC3,EAC3 or DTS then an AC3 track is added.\n\n
`, `,
Version: "1.00", Version: "1.00",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_s7x9_winsome_h265_nvenc.js", Link:
Tags:'pre-processing,handbrake,ffmpeg,nvenc h265', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_s7x9_winsome_h265_nvenc.js",
} Tags: "pre-processing,handbrake,ffmpeg,nvenc h265",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mp4', container: ".mp4",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: false, reQueueAfter: false,
infoLog: '', infoLog: "",
};
}
response.FFmpegMode = true
response.FFmpegMode = true;
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
var jsonString = JSON.stringify(file);
response.container = ".mkv";
var jsonString = JSON.stringify(file) if (file.ffProbeData.streams[0].codec_name == "hevc") {
response.container = '.mkv' var hasPreferredLangTrack = false;
var hasPreferredLangInRequiredCodecs = false;
var hasAnyInRequiredCodecs = false;
if (file.ffProbeData.streams[0].codec_name == 'hevc') {
var hasPreferredLangTrack = false
var hasPreferredLangInRequiredCodecs = false
var hasAnyInRequiredCodecs = false
var audioIdx = -1
var engTrackIdx = -1
var requiredAudioCodecs = "ac3,eac3,dts"
var preferredLangTrack = "eng"
var preferredCodec = "ac3"
var audioIdx = -1;
var engTrackIdx = -1;
var requiredAudioCodecs = "ac3,eac3,dts";
var preferredLangTrack = "eng";
var preferredCodec = "ac3";
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
audioIdx++ audioIdx++;
} }
} catch (err) { } } catch (err) {}
try { try {
if (requiredAudioCodecs.includes(file.ffProbeData.streams[i].codec_name)) { if (
hasAnyInRequiredCodecs = true requiredAudioCodecs.includes(file.ffProbeData.streams[i].codec_name)
) {
hasAnyInRequiredCodecs = true;
} }
} catch (err) { } } catch (err) {}
try { try {
if ((requiredAudioCodecs.includes(file.ffProbeData.streams[i].codec_name)) && file.ffProbeData.streams[i].tags.language.toLowerCase().includes(preferredLangTrack)) { if (
hasPreferredLangInRequiredCodecs = true requiredAudioCodecs.includes(
file.ffProbeData.streams[i].codec_name
) &&
file.ffProbeData.streams[i].tags.language
.toLowerCase()
.includes(preferredLangTrack)
) {
hasPreferredLangInRequiredCodecs = true;
} }
} catch (err) { } } catch (err) {}
try { try {
if (file.ffProbeData.streams[i].tags.language.toLowerCase().includes(preferredLangTrack) && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (
hasPreferredLangTrack = true file.ffProbeData.streams[i].tags.language
engTrackIdx = audioIdx .toLowerCase()
.includes(preferredLangTrack) &&
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio"
) {
hasPreferredLangTrack = true;
engTrackIdx = audioIdx;
} }
} catch (err) { } } catch (err) {}
} }
if (hasPreferredLangInRequiredCodecs) { if (hasPreferredLangInRequiredCodecs) {
response.infoLog += `☑File already has ${preferredLangTrack} language track in ${requiredAudioCodecs}! \n`;
response.infoLog += `☑File already has ${preferredLangTrack} language track in ${requiredAudioCodecs}! \n`
} else if (hasPreferredLangTrack) { } else if (hasPreferredLangTrack) {
response.processFile = true; response.processFile = true;
response.preset = `,-map 0:v -map 0:a:${engTrackIdx} -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2` response.preset = `,-map 0:v -map 0:a:${engTrackIdx} -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2`;
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += `☒File has ${preferredLangTrack} language track but not in ${requiredAudioCodecs}! \n` response.infoLog += `☒File has ${preferredLangTrack} language track but not in ${requiredAudioCodecs}! \n`;
return response return response;
} else if (!hasAnyInRequiredCodecs) { } else if (!hasAnyInRequiredCodecs) {
if (audioIdx == -1) { if (audioIdx == -1) {
response.infoLog += `☒File does not have any audio streams. Can't create ${preferredCodec} track. \n` response.infoLog += `☒File does not have any audio streams. Can't create ${preferredCodec} track. \n`;
} else { } else {
response.processFile = true; response.processFile = true;
response.preset = `,-map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2` response.preset = `,-map 0:v -map 0:a:0 -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${preferredCodec} -b:a:0 192k -ac 2`;
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += `☒File has no language track in ${requiredAudioCodecs}. No ${preferredLangTrack} track marked so transcoding audio track 1 into ${preferredCodec}! \n` response.infoLog += `☒File has no language track in ${requiredAudioCodecs}. No ${preferredLangTrack} track marked so transcoding audio track 1 into ${preferredCodec}! \n`;
return response return response;
} }
} }
if (file.container != "mkv") {
if (file.container != 'mkv') {
response.processFile = true; response.processFile = true;
response.preset = ', -map 0 -c copy' response.preset = ", -map 0 -c copy";
response.container = '.mkv' response.container = ".mkv";
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File is not in mkv container! \n" response.infoLog += "☒File is not in mkv container! \n";
return response return response;
} else { } else {
response.infoLog += "☑File is in mkv container! \n";
response.infoLog += "☑File is in mkv container! \n"
} }
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
response.processFile = true; response.processFile = true;
response.preset = '-Z "H.265 MKV 2160p60" --all-audio --all-subtitles -e nvenc_h265' response.preset =
response.container = '.mkv' '-Z "H.265 MKV 2160p60" --all-audio --all-subtitles -e nvenc_h265';
response.handBrakeMode = true response.container = ".mkv";
response.FFmpegMode = false response.handBrakeMode = true;
response.FFmpegMode = false;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File isn't in hevc! \n" response.infoLog += "☒File isn't in hevc! \n";
return response return response;
} }
} }
} }

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_sdd3_Remove_Commentary_Tracks", id: "Tdarr_Plugin_sdd3_Remove_Commentary_Tracks",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,90 +7,76 @@ function details() {
Operation: "Remux", Operation: "Remux",
Description: `[Contains built-in filter] If commentary tracks are detected, they will be removed. \n\n`, Description: `[Contains built-in filter] If commentary tracks are detected, they will be removed. \n\n`,
Version: "1.00", Version: "1.00",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_sdd3_Remove_Commentary_Tracks.js", Link:
Tags:'pre-processing,ffmpeg,audio only', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_sdd3_Remove_Commentary_Tracks.js",
} Tags: "pre-processing,ffmpeg,audio only",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mp4', container: ".mp4",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: false, reQueueAfter: false,
infoLog: '', infoLog: "",
};
}
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
response.processFile = false response.processFile = false;
response.infoLog += "☒File is not a video! \n" response.infoLog += "☒File is not a video! \n";
return response return response;
} else { } else {
response.infoLog += "☑File is a video! \n" response.infoLog += "☑File is a video! \n";
} }
var audioIdx = -1;
var hasCommentaryTrack = false;
var audioIdx = -1 var ffmpegCommandInsert = "";
var hasCommentaryTrack = false
var ffmpegCommandInsert = ""
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
//keep track of audio streams for when removing commentary track //keep track of audio streams for when removing commentary track
try { try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
audioIdx++ audioIdx++;
} }
} catch (err) { } } catch (err) {}
//check if commentary track and passing audio stream number //check if commentary track and passing audio stream number
try { try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].tags.title.toLowerCase().includes("commentary")) { if (
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" &&
file.ffProbeData.streams[i].tags.title
ffmpegCommandInsert += ` -map -0:a:${audioIdx}` .toLowerCase()
hasCommentaryTrack = true .includes("commentary")
) {
ffmpegCommandInsert += ` -map -0:a:${audioIdx}`;
hasCommentaryTrack = true;
} }
} catch (err) { } catch (err) {}
}
} }
if (hasCommentaryTrack === true) { if (hasCommentaryTrack === true) {
response.processFile = true; response.processFile = true;
response.preset = `, -map 0 ${ffmpegCommandInsert} -c copy` response.preset = `, -map 0 ${ffmpegCommandInsert} -c copy`;
response.container = '.' + file.container response.container = "." + file.container;
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File contains commentary tracks. Removing! \n" response.infoLog += "☒File contains commentary tracks. Removing! \n";
return response return response;
} else { } else {
response.infoLog += "☑File doesn't contain commentary tracks! \n";
response.infoLog += "☑File doesn't contain commentary tracks! \n"
} }
response.processFile = false response.processFile = false;
response.infoLog += "☑File meets conditions! \n" response.infoLog += "☑File meets conditions! \n";
return response return response;
} }
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_sdf5_Thierrrrry_Remove_Non_English_Audio", id: "Tdarr_Plugin_sdf5_Thierrrrry_Remove_Non_English_Audio",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,111 +7,99 @@ function details() {
Description: `[Contains built-in filter] This plugin removes audio tracks which are not English or are not undefined. It ensures at least 1 audio track is left in any language. \n\n Description: `[Contains built-in filter] This plugin removes audio tracks which are not English or are not undefined. It ensures at least 1 audio track is left in any language. \n\n
`, `,
Version: "1.00", Version: "1.00",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_sdf5_Thierrrrry_Remove_Non_English_Audio.js", Link:
Tags:'pre-processing,ffmpeg,audio only', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_sdf5_Thierrrrry_Remove_Non_English_Audio.js",
} Tags: "pre-processing,ffmpeg,audio only",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false, processFile: false,
preset: '', preset: "",
container: '.mp4', container: ".mp4",
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: false, reQueueAfter: false,
infoLog: '', infoLog: "",
};
}
response.FFmpegMode = true
response.FFmpegMode = true;
//check if files is video //check if files is video
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} }
var ffmpegCommandInsert = "";
var audioIdx = -1;
var hasNonEngTrack = false;
var ffmpegCommandInsert = '' var audioStreamsRemoved = 0;
var audioIdx = -1
var hasNonEngTrack = false
var audioStreamsRemoved = 0
//count number of audio streams //count number of audio streams
var audioStreamCount = file.ffProbeData.streams.filter(row => (row.codec_type.toLowerCase() == "audio")).length; var audioStreamCount = file.ffProbeData.streams.filter(
(row) => row.codec_type.toLowerCase() == "audio"
).length;
console.log("audioStreamCount:" + audioStreamCount) console.log("audioStreamCount:" + audioStreamCount);
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
//check if current stream is audio, update audioIdx if so //check if current stream is audio, update audioIdx if so
try { try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
audioIdx++ audioIdx++;
} }
} catch (err) { } } catch (err) {}
try { try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && !(file.ffProbeData.streams[i].tags.language.toLowerCase().includes('eng') || file.ffProbeData.streams[i].tags.language.toLowerCase().includes('und'))) { if (
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" &&
audioStreamsRemoved++ !(
file.ffProbeData.streams[i].tags.language
.toLowerCase()
.includes("eng") ||
file.ffProbeData.streams[i].tags.language
.toLowerCase()
.includes("und")
)
) {
audioStreamsRemoved++;
if (audioStreamsRemoved == audioStreamCount) { if (audioStreamsRemoved == audioStreamCount) {
break; break;
} }
ffmpegCommandInsert += ` -map -0:a:${audioIdx}` ffmpegCommandInsert += ` -map -0:a:${audioIdx}`;
hasNonEngTrack = true hasNonEngTrack = true;
} }
} catch (err) { } } catch (err) {}
} }
if (hasNonEngTrack === true) { if (hasNonEngTrack === true) {
response.processFile = true; response.processFile = true;
response.preset = `, -map 0 ${ffmpegCommandInsert} -c copy` response.preset = `, -map 0 ${ffmpegCommandInsert} -c copy`;
response.container = '.' + file.container response.container = "." + file.container;
response.handBrakeMode = false response.handBrakeMode = false;
response.FFmpegMode = true response.FFmpegMode = true;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += "☒File contains tracks which are not english or undefined. Removing! \n" response.infoLog +=
return response "☒File contains tracks which are not english or undefined. Removing! \n";
return response;
} else { } else {
response.infoLog +=
response.infoLog += "☑File doesn't contain tracks which are not english or undefined! \n" "☑File doesn't contain tracks which are not english or undefined! \n";
} }
response.processFile = false; response.processFile = false;
return response return response;
} }
module.exports.details = details; module.exports.details = details;

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_x7ab_Remove_Subs", id: "Tdarr_Plugin_x7ab_Remove_Subs",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -10,77 +6,60 @@ function details() {
Type: "Video", Type: "Video",
Description: `[Contains built-in filter] This plugin removes subtitles if detected. The output container is the same as the original. \n\n`, Description: `[Contains built-in filter] This plugin removes subtitles if detected. The output container is the same as the original. \n\n`,
Version: "1.00", Version: "1.00",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_x7ab_Remove_Subs.js", Link:
Tags:'pre-processing,ffmpeg,subtitle only', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_x7ab_Remove_Subs.js",
} Tags: "pre-processing,ffmpeg,subtitle only",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false,
processFile : false, preset: "",
preset : '', container: ".mp4",
container : '.mp4', handBrakeMode: false,
handBrakeMode : false, FFmpegMode: false,
FFmpegMode : false, reQueueAfter: false,
reQueueAfter : false, infoLog: "",
infoLog : '', };
}
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
console.log("File is not video") response.infoLog += "☒File is not video \n";
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else {
} else { response.FFmpegMode = true;
response.container = "." + file.container;
response.FFmpegMode = true var hasSubs = false;
response.container = '.' + file.container
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
var hasSubs = false try {
if (
for (var i = 0; i < file.ffProbeData.streams.length; i++) { file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle"
) {
try { hasSubs = true;
if(file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle"){ }
} catch (err) {}
hasSubs = true }
} if (hasSubs) {
} catch (err) { } response.infoLog += "☒File has subs \n";
} response.preset = ",-sn -map 0 -c copy";
if(hasSubs){
response.infoLog += "☒File has subs \n"
response.preset = ',-sn -map 0 -c copy'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
return response return response;
} else {
}else{ response.infoLog += "☑File has no subs \n";
response.infoLog += "☑File has no subs \n" }
}
response.infoLog += "☑File meets conditions! \n"
return response
response.infoLog += "☑File meets conditions! \n";
return response;
} }
} }

@ -1,86 +1,62 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_x7ac_Remove_Closed_Captions", id: "Tdarr_Plugin_x7ac_Remove_Closed_Captions",
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "Remove closed captions", Name: "Remove closed captions",
Type: "Video", Type: "Video",
Operation: "Remux", Operation: "Remux",
Description: "[Contains built-in filter] If detected, closed captions (XDS,608,708) will be removed.", Description:
"[Contains built-in filter] If detected, closed captions (XDS,608,708) will be removed.",
Version: "1.00", Version: "1.00",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_x7ac_Remove_Closed_Captions.js", Link:
Tags:'pre-processing,ffmpeg,subtitle only', "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_x7ac_Remove_Closed_Captions.js",
} Tags: "pre-processing,ffmpeg,subtitle only",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false,
preset: "",
container: ".mp4",
handBrakeMode: false,
FFmpegMode: false,
reQueueAfter: true,
infoLog: "",
};
processFile : false,
preset : '',
container : '.mp4',
handBrakeMode : false,
FFmpegMode : false,
reQueueAfter : true,
infoLog : '',
}
if (file.fileMedium !== "video") { if (file.fileMedium !== "video") {
console.log("File is not video");
console.log("File is not video") response.infoLog += "☒File is not video \n";
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response
} else {
if(file.hasClosedCaptions === true){
return response;
response = { } else {
if (file.hasClosedCaptions === true) {
processFile : true, response = {
preset : ',-map 0 -codec copy -bsf:v "filter_units=remove_types=6"', processFile: true,
container : '.' + file.container , preset: ',-map 0 -codec copy -bsf:v "filter_units=remove_types=6"',
handBrakeMode : false, container: "." + file.container,
FFmpegMode : true, handBrakeMode: false,
reQueueAfter : true, FFmpegMode: true,
infoLog : '☒This file has closed captions \n', reQueueAfter: true,
infoLog: "☒This file has closed captions \n",
} };
return response return response;
} else {
}else{ response.infoLog +=
"☑Closed captions have not been detected on this file \n";
response.infoLog += "☑Closed captions have not been detected on this file \n"
response.processFile = false; response.processFile = false;
return response
return response;
} }
} }
} }
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_z0ab_TheRealShadoh_FFmpeg_Subs_H264_Medium", id: "Tdarr_Plugin_z0ab_TheRealShadoh_FFmpeg_Subs_H264_Medium",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,148 +7,135 @@ function details() {
Description: `[Contains built-in filter] This plugin transcodes into H264 using FFmpeg's 'Medium' preset if the file is not in H264 already. It maintains all subtitles. It removes metadata (if a title exists), and maintains all audio tracks. The output container is MP4. \n\n Description: `[Contains built-in filter] This plugin transcodes into H264 using FFmpeg's 'Medium' preset if the file is not in H264 already. It maintains all subtitles. It removes metadata (if a title exists), and maintains all audio tracks. The output container is MP4. \n\n
`, `,
Version: "1.00", Version: "1.00",
Link: "https://github.com/TheRealShadoh/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_z0ab_TheRealShadoh_FFmpeg_Subs_H264_Medium.js", Link:
Tags:'pre-processing,ffmpeg,h264', "https://github.com/TheRealShadoh/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_z0ab_TheRealShadoh_FFmpeg_Subs_H264_Medium.js",
} Tags: "pre-processing,ffmpeg,h264",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false,
processFile : false, preset: "",
preset : '', container: ".mp4",
container : '.mp4', handBrakeMode: false,
handBrakeMode : false, FFmpegMode: false,
FFmpegMode : false, reQueueAfter: false,
reQueueAfter : false, infoLog: "",
infoLog : '', };
} if (file.fileMedium !== "video") {
console.log("File is not video");
if (file.fileMedium !== "video"){
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
var jsonString = JSON.stringify(file);
var jsonString = JSON.stringify(file)
var hasSubs = false;
var hasSubs = false for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try {
let streamData = file.ffProbeData.streams[i];
for (var i = 0; i < file.ffProbeData.streams.length; i++) { if (
streamData.codec_type.toLowerCase() == "subtitle" &&
try { streamData.codec_name != "mov_text"
let streamData = file.ffProbeData.streams[i]; ) {
if(streamData.codec_type.toLowerCase() == "subtitle" && streamData.codec_name != "mov_text"){ hasSubs = true;
hasSubs = true }
} } catch (err) {}
} catch (err) { } }
}
if (file.ffProbeData.streams[0].codec_name != "h264") {
response.infoLog += "☒File is not in h264! \n";
if(file.ffProbeData.streams[0].codec_name != 'h264'){ response.preset =
", -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v libx264 -preset medium -c:a aac -c:s mov_text";
response.infoLog += "☒File is not in h264! \n"
response.preset = ', -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v libx264 -preset medium -c:a aac -c:s mov_text'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} else {
}else{ response.infoLog += "☑File is already in h264! \n";
response.infoLog += "☑File is already in h264! \n" }
}
///
/// if (
file.meta.Title != undefined &&
if((file.meta.Title != undefined) && !jsonString.includes("aac") && hasSubs){ !jsonString.includes("aac") &&
hasSubs
response.infoLog += "☒File has title metadata and no aac and subs \n" ) {
response.preset = ', -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text' response.infoLog += "☒File has title metadata and no aac and subs \n";
response.preset =
", -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} }
if(!jsonString.includes("aac") && hasSubs){ if (!jsonString.includes("aac") && hasSubs) {
response.infoLog += "☒File has no aac track and has subs \n";
response.infoLog += "☒File has no aac track and has subs \n" response.preset =
response.preset = ', -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text' ", -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} }
if (file.meta.Title != undefined && hasSubs) {
if(file.meta.Title != undefined && hasSubs){ response.infoLog += "☒File has title and has subs \n";
response.preset =
response.infoLog += "☒File has title and has subs \n" ", -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text";
response.preset = ', -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} }
///
if (file.meta.Title != undefined) {
/// response.infoLog += "☒File has title metadata \n";
if(file.meta.Title != undefined ){ response.preset =
", -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text";
response.infoLog += "☒File has title metadata \n"
response.preset = ', -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
}else{ } else {
response.infoLog += "☑File has no title metadata \n" response.infoLog += "☑File has no title metadata \n";
} }
if(!jsonString.includes("aac")){ if (!jsonString.includes("aac")) {
response.infoLog += "☒File has no aac track \n";
response.infoLog += "☒File has no aac track \n" response.preset =
response.preset = ', -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text' ", -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} else {
}else{ response.infoLog += "☑File has aac track \n";
response.infoLog += "☑File has aac track \n" }
}
if (hasSubs) {
if(hasSubs){ response.infoLog += "☒File has incompatible subs \n";
response.preset =
response.infoLog += "☒File has incompatible subs \n" ", -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text";
response.preset = ', -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text'
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} else {
}else{ response.infoLog += "☑File has no/compatible subs \n";
response.infoLog += "☑File has no/compatible subs \n" }
}
response.infoLog += "☑File meets conditions! \n";
response.infoLog += "☑File meets conditions! \n" return response;
return response
} }
} }

@ -1,72 +1,69 @@
module.exports.details = function details() { module.exports.details = function details() {
return { return {
id: "Tdarr_Plugin_z18s_rename_files_based_on_codec", id: "Tdarr_Plugin_z18s_rename_files_based_on_codec",
Stage: "Post-processing", Stage: "Post-processing",
Name: "Rename based on codec", Name: "Rename based on codec",
Type: "Video", Type: "Video",
Operation: "", Operation: "",
Description: `[TESTING][Contains built-in filter]This plugin renames 264 files to 265 or vice versa depending on codec. \n\n`, Description: `[TESTING][Contains built-in filter]This plugin renames 264 files to 265 or vice versa depending on codec. \n\n`,
Version: "1.00", Version: "1.00",
Link: "", Link: "",
Tags:"post-processing", Tags: "post-processing",
};
} };
}
module.exports.plugin = function plugin(file, librarySettings, inputs) { module.exports.plugin = function plugin(file, librarySettings, inputs) {
try { try {
var fs = require("fs");
var fs = require('fs'); var path = require("path");
var path = require('path'); if (fs.existsSync(path.join(process.cwd(), "/npm"))) {
if (fs.existsSync(path.join(process.cwd() , '/npm'))) { var rootModules = path.join(process.cwd(), "/npm/node_modules/");
var rootModules = path.join(process.cwd() , '/npm/node_modules/') } else {
} else{ var rootModules = "";
var rootModules = ''
} }
var fsextra = require(rootModules+'fs-extra') var fsextra = require(rootModules + "fs-extra");
var fileNameOld = file._id var fileNameOld = file._id;
if (file.ffProbeData.streams[0].codec_name == 'hevc' && file._id.includes('264')) { if (
file.ffProbeData.streams[0].codec_name == "hevc" &&
file._id.includes("264")
) {
file._id = file._id.replace("264", "265"); file._id = file._id.replace("264", "265");
file.file = file.file.replace("264", "265"); file.file = file.file.replace("264", "265");
} }
if (
file.ffProbeData.streams[0].codec_name == "h264" &&
if (file.ffProbeData.streams[0].codec_name == 'h264' && file._id.includes('265')) { file._id.includes("265")
) {
file._id = file._id.replace("265", "264"); file._id = file._id.replace("265", "264");
file.file = file.file.replace("265", "264"); file.file = file.file.replace("265", "264");
} }
if (file.ffProbeData.streams[0].codec_name == 'h264' && file._id.includes('hevc')) { if (
file.ffProbeData.streams[0].codec_name == "h264" &&
file._id.includes("hevc")
) {
file._id = file._id.replace("hevc", "264"); file._id = file._id.replace("hevc", "264");
file.file = file.file.replace("hevc", "264"); file.file = file.file.replace("hevc", "264");
} }
if (fileNameOld != file._id) { if (fileNameOld != file._id) {
fsextra.moveSync(fileNameOld, file._id, { fsextra.moveSync(fileNameOld, file._id, {
overwrite: true overwrite: true,
}) });
var response = { var response = {
file, file,
removeFromDB: false, removeFromDB: false,
updateDB: true, updateDB: true,
} };
return response
return response;
} }
} catch (err) {
} catch (err) { console.log(err) } console.log(err);
} }
};

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_z1ab_TheRealShadoh_FFmpeg_Subs_H264_Fast", id: "Tdarr_Plugin_z1ab_TheRealShadoh_FFmpeg_Subs_H264_Fast",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,148 +7,136 @@ function details() {
Description: `[Contains built-in filter] This plugin transcodes into H264 using FFmpeg's 'Fast' preset if the file is not in H264 already. It maintains all subtitles. It removes metadata (if a title exists), and maintains all audio tracks. The output container is MP4. \n\n Description: `[Contains built-in filter] This plugin transcodes into H264 using FFmpeg's 'Fast' preset if the file is not in H264 already. It maintains all subtitles. It removes metadata (if a title exists), and maintains all audio tracks. The output container is MP4. \n\n
`, `,
Version: "1.00", Version: "1.00",
Link: "https://github.com/TheRealShadoh/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_z1ab_TheRealShadoh_FFmpeg_Subs_H264_Fast.js", Link:
Tags:'pre-processing,ffmpeg,h264', "https://github.com/TheRealShadoh/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_z1ab_TheRealShadoh_FFmpeg_Subs_H264_Fast.js",
} Tags: "pre-processing,ffmpeg,h264",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false,
processFile : false, preset: "",
preset : '', container: ".mp4",
container : '.mp4', handBrakeMode: false,
handBrakeMode : false, FFmpegMode: false,
FFmpegMode : false, reQueueAfter: false,
reQueueAfter : false, infoLog: "",
infoLog : '', };
} if (file.fileMedium !== "video") {
console.log("File is not video");
if (file.fileMedium !== "video"){
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
var jsonString = JSON.stringify(file);
var jsonString = JSON.stringify(file) var hasSubs = false;
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
var hasSubs = false try {
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try {
let streamData = file.ffProbeData.streams[i]; let streamData = file.ffProbeData.streams[i];
if(streamData.codec_type.toLowerCase() == "subtitle" && streamData.codec_name != "mov_text"){ if (
hasSubs = true streamData.codec_type.toLowerCase() == "subtitle" &&
streamData.codec_name != "mov_text"
) {
hasSubs = true;
} }
} catch (err) { } } catch (err) {}
} }
if(file.ffProbeData.streams[0].codec_name != 'h264'){ if (file.ffProbeData.streams[0].codec_name != "h264") {
response.infoLog += "☒File is not in h264! \n";
response.infoLog += "☒File is not in h264! \n" response.preset =
response.preset = ', -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v libx264 -preset fast -c:a aac -c:s mov_text' ", -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v libx264 -preset fast -c:a aac -c:s mov_text";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} else {
}else{ response.infoLog += "☑File is already in h264! \n";
response.infoLog += "☑File is already in h264! \n" }
}
///
/// if (
file.meta.Title != undefined &&
if((file.meta.Title != undefined) && !jsonString.includes("aac") && hasSubs){ !jsonString.includes("aac") &&
hasSubs
response.infoLog += "☒File has title metadata and no aac and subs \n" ) {
response.preset = ', -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text' response.infoLog += "☒File has title metadata and no aac and subs \n";
response.preset =
", -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} }
if(!jsonString.includes("aac") && hasSubs){ if (!jsonString.includes("aac") && hasSubs) {
response.infoLog += "☒File has no aac track and has subs \n";
response.infoLog += "☒File has no aac track and has subs \n" response.preset =
response.preset = ', -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text' ", -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} }
if (file.meta.Title != undefined && hasSubs) {
if(file.meta.Title != undefined && hasSubs){ response.infoLog += "☒File has title and has subs \n";
response.preset =
response.infoLog += "☒File has title and has subs \n" ", -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text";
response.preset = ', -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} }
///
/// if (file.meta.Title != undefined) {
if(file.meta.Title != undefined ){ response.infoLog += "☒File has title metadata \n";
response.preset =
response.infoLog += "☒File has title metadata \n" ", -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text";
response.preset = ', -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
}else{ } else {
response.infoLog += "☑File has no title metadata \n" response.infoLog += "☑File has no title metadata \n";
} }
if(!jsonString.includes("aac")){ if (!jsonString.includes("aac")) {
response.infoLog += "☒File has no aac track \n";
response.infoLog += "☒File has no aac track \n" response.preset =
response.preset = ', -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text' ", -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} else {
}else{ response.infoLog += "☑File has aac track \n";
response.infoLog += "☑File has aac track \n" }
}
if (hasSubs) {
if(hasSubs){ response.infoLog += "☒File has incompatible subs \n";
response.preset =
response.infoLog += "☒File has incompatible subs \n" ", -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text";
response.preset = ', -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} else {
}else{ response.infoLog += "☑File has no/compatible subs \n";
response.infoLog += "☑File has no/compatible subs \n" }
}
response.infoLog += "☑File meets conditions! \n";
response.infoLog += "☑File meets conditions! \n" return response;
return response
} }
} }

@ -1,8 +1,4 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_z2ab_TheRealShadoh_FFmpeg_Subs_H264_Slow", id: "Tdarr_Plugin_z2ab_TheRealShadoh_FFmpeg_Subs_H264_Slow",
Stage: "Pre-processing", Stage: "Pre-processing",
@ -11,149 +7,136 @@ function details() {
Description: `[Contains built-in filter] This plugin transcodes into H264 using FFmpeg's 'Slow' preset if the file is not in H264 already. It maintains all subtitles. It removes metadata (if a title exists), and maintains all audio tracks. The output container is MP4. \n\n Description: `[Contains built-in filter] This plugin transcodes into H264 using FFmpeg's 'Slow' preset if the file is not in H264 already. It maintains all subtitles. It removes metadata (if a title exists), and maintains all audio tracks. The output container is MP4. \n\n
`, `,
Version: "1.00", Version: "1.00",
Link: "https://github.com/TheRealShadoh/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_z2ab_TheRealShadoh_FFmpeg_Subs_H264_Slow.js", Link:
Tags:'pre-processing,ffmpeg,h264', "https://github.com/TheRealShadoh/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_z2ab_TheRealShadoh_FFmpeg_Subs_H264_Slow.js",
} Tags: "pre-processing,ffmpeg,h264",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false,
processFile : false, preset: "",
preset : '', container: ".mp4",
container : '.mp4', handBrakeMode: false,
handBrakeMode : false, FFmpegMode: false,
FFmpegMode : false, reQueueAfter: false,
reQueueAfter : false, infoLog: "",
infoLog : '', };
} if (file.fileMedium !== "video") {
console.log("File is not video");
if (file.fileMedium !== "video"){
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
var jsonString = JSON.stringify(file);
var jsonString = JSON.stringify(file) var hasSubs = false;
var hasSubs = false for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try {
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try {
let streamData = file.ffProbeData.streams[i]; let streamData = file.ffProbeData.streams[i];
if(streamData.codec_type.toLowerCase() == "subtitle" && streamData.codec_name != "mov_text"){ if (
hasSubs = true streamData.codec_type.toLowerCase() == "subtitle" &&
streamData.codec_name != "mov_text"
) {
hasSubs = true;
} }
} catch (err) { } } catch (err) {}
} }
if(file.ffProbeData.streams[0].codec_name != 'h264'){
response.infoLog += "☒File is not in h264! \n" if (file.ffProbeData.streams[0].codec_name != "h264") {
response.preset = ', -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v libx264 -preset slow -c:a aac -c:s mov_text' response.infoLog += "☒File is not in h264! \n";
response.preset =
", -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v libx264 -preset slow -c:a aac -c:s mov_text";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} else {
}else{ response.infoLog += "☑File is already in h264! \n";
response.infoLog += "☑File is already in h264! \n" }
}
///
/// if (
file.meta.Title != undefined &&
if((file.meta.Title != undefined) && !jsonString.includes("aac") && hasSubs){ !jsonString.includes("aac") &&
hasSubs
response.infoLog += "☒File has title metadata and no aac and subs \n" ) {
response.preset = ', -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text' response.infoLog += "☒File has title metadata and no aac and subs \n";
response.preset =
", -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} }
if(!jsonString.includes("aac") && hasSubs){ if (!jsonString.includes("aac") && hasSubs) {
response.infoLog += "☒File has no aac track and has subs \n";
response.infoLog += "☒File has no aac track and has subs \n" response.preset =
response.preset = ', -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text' ", -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} }
if (file.meta.Title != undefined && hasSubs) {
if(file.meta.Title != undefined && hasSubs){ response.infoLog += "☒File has title and has subs \n";
response.preset =
response.infoLog += "☒File has title and has subs \n" ", -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text";
response.preset = ', -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} }
///
if (file.meta.Title != undefined) {
/// response.infoLog += "☒File has title metadata \n";
if(file.meta.Title != undefined ){ response.preset =
", -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text";
response.infoLog += "☒File has title metadata \n"
response.preset = ', -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
}else{ } else {
response.infoLog += "☑File has no title metadata \n" response.infoLog += "☑File has no title metadata \n";
} }
if(!jsonString.includes("aac")){ if (!jsonString.includes("aac")) {
response.infoLog += "☒File has no aac track \n";
response.infoLog += "☒File has no aac track \n" response.preset =
response.preset = ', -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text' ", -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} else {
}else{ response.infoLog += "☑File has aac track \n";
response.infoLog += "☑File has aac track \n" }
}
if (hasSubs) {
if(hasSubs){ response.infoLog += "☒File has incompatible subs \n";
response.preset =
response.infoLog += "☒File has incompatible subs \n" ", -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text";
response.preset = ', -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} else {
}else{ response.infoLog += "☑File has no/compatible subs \n";
response.infoLog += "☑File has no/compatible subs \n" }
}
response.infoLog += "☑File meets conditions! \n";
response.infoLog += "☑File meets conditions! \n" return response;
return response
} }
} }

@ -1,159 +1,143 @@
function details() { function details() {
return { return {
id: "Tdarr_Plugin_z3ab_TheRealShadoh_FFmpeg_Subs_H264_VeryFast", id: "Tdarr_Plugin_z3ab_TheRealShadoh_FFmpeg_Subs_H264_VeryFast",
Stage: "Pre-processing", Stage: "Pre-processing",
Name: "TheRealShadoh FFmpeg Subs VeryFast, video MP4, audio AAC, keep subs. ", Name:
"TheRealShadoh FFmpeg Subs VeryFast, video MP4, audio AAC, keep subs. ",
Type: "Video", Type: "Video",
Description: `[Contains built-in filter] This plugin transcodes into H264 using FFmpeg's 'VeryFast' preset if the file is not in H264 already. It maintains all subtitles. It removes metadata (if a title exists), and maintains all audio tracks. The output container is MP4. \n\n Description: `[Contains built-in filter] This plugin transcodes into H264 using FFmpeg's 'VeryFast' preset if the file is not in H264 already. It maintains all subtitles. It removes metadata (if a title exists), and maintains all audio tracks. The output container is MP4. \n\n
`, `,
Version: "1.00", Version: "1.00",
Link: "https://github.com/TheRealShadoh/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_z3ab_TheRealShadoh_FFmpeg_Subs_H264_Veryfast.js", Link:
Tags:'pre-processing,ffmpeg,h264', "https://github.com/TheRealShadoh/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_z3ab_TheRealShadoh_FFmpeg_Subs_H264_Veryfast.js",
} Tags: "pre-processing,ffmpeg,h264",
};
} }
function plugin(file) { function plugin(file) {
//Must return this object //Must return this object
var response = { var response = {
processFile: false,
processFile : false, preset: "",
preset : '', container: ".mp4",
container : '.mp4', handBrakeMode: false,
handBrakeMode : false, FFmpegMode: false,
FFmpegMode : false, reQueueAfter: false,
reQueueAfter : false, infoLog: "",
infoLog : '', };
} if (file.fileMedium !== "video") {
console.log("File is not video");
if (file.fileMedium !== "video"){
response.infoLog += "☒File is not video \n";
console.log("File is not video")
response.infoLog += "☒File is not video \n"
response.processFile = false; response.processFile = false;
return response return response;
} else { } else {
var jsonString = JSON.stringify(file);
var jsonString = JSON.stringify(file) var hasSubs = false;
var hasSubs = false for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try {
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try {
let streamData = file.ffProbeData.streams[i]; let streamData = file.ffProbeData.streams[i];
if(streamData.codec_type.toLowerCase() == "subtitle" && streamData.codec_name != "mov_text"){ if (
hasSubs = true streamData.codec_type.toLowerCase() == "subtitle" &&
streamData.codec_name != "mov_text"
) {
hasSubs = true;
} }
} catch (err) { } } catch (err) {}
} }
if(file.ffProbeData.streams[0].codec_name != 'h264'){
response.infoLog += "☒File is not in h264! \n" if (file.ffProbeData.streams[0].codec_name != "h264") {
response.preset = ', -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v libx264 -preset veryfast -c:a aac -c:s mov_text' response.infoLog += "☒File is not in h264! \n";
response.preset =
", -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v libx264 -preset veryfast -c:a aac -c:s mov_text";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} else {
}else{ response.infoLog += "☑File is already in h264! \n";
response.infoLog += "☑File is already in h264! \n" }
}
///
/// if (
file.meta.Title != undefined &&
if((file.meta.Title != undefined) && !jsonString.includes("aac") && hasSubs){ !jsonString.includes("aac") &&
hasSubs
response.infoLog += "☒File has title metadata and no aac and subs \n" ) {
response.preset = ', -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text' response.infoLog += "☒File has title metadata and no aac and subs \n";
response.preset =
", -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} }
if(!jsonString.includes("aac") && hasSubs){ if (!jsonString.includes("aac") && hasSubs) {
response.infoLog += "☒File has no aac track and has subs \n";
response.infoLog += "☒File has no aac track and has subs \n" response.preset =
response.preset = ', -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text' ", -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} }
if (file.meta.Title != undefined && hasSubs) {
if(file.meta.Title != undefined && hasSubs){ response.infoLog += "☒File has title and has subs \n";
response.preset =
response.infoLog += "☒File has title and has subs \n" ", -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text";
response.preset = ', -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} }
///
if (file.meta.Title != undefined) {
/// response.infoLog += "☒File has title metadata \n";
if(file.meta.Title != undefined ){ response.preset =
", -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text";
response.infoLog += "☒File has title metadata \n"
response.preset = ', -map_metadata -1 -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
}else{ } else {
response.infoLog += "☑File has no title metadata \n" response.infoLog += "☑File has no title metadata \n";
} }
if(!jsonString.includes("aac")){ if (!jsonString.includes("aac")) {
response.infoLog += "☒File has no aac track \n";
response.infoLog += "☒File has no aac track \n" response.preset =
response.preset = ', -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text' ", -map 0:v -map 0:s? -map 0:a -c:v copy -c:a aac -c:s mov_text";
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} else {
}else{ response.infoLog += "☑File has aac track \n";
response.infoLog += "☑File has aac track \n" }
}
if (hasSubs) {
if(hasSubs){ response.infoLog += "☒File has incompatible subs \n";
response.preset =
response.infoLog += "☒File has incompatible subs \n" ", -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text";
response.preset = ', -map 0:v -map 0:s? -map 0:a -c:v copy -c:a copy -c:s mov_text'
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;
response.FFmpegMode = true response.FFmpegMode = true;
return response return response;
} else {
}else{ response.infoLog += "☑File has no/compatible subs \n";
response.infoLog += "☑File has no/compatible subs \n" }
}
response.infoLog += "☑File meets conditions! \n";
response.infoLog += "☑File meets conditions! \n" return response;
return response
} }
} }

@ -14,11 +14,11 @@ https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Tdarr_Plugin_aaaa_Pre_P
https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Tdarr_Plugin_zzzz_Post_Proc_Example.js https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Tdarr_Plugin_zzzz_Post_Proc_Example.js
2.Determine an id for your plugin. Every id must start with 'Tdarr_Plugin_xxxx' where xxxx is a random mini id containing the following: 2.Determine an id for your plugin. Every id must start with 'Tdarr_Plugin_xxxx' where xxxx is a random mini id containing the following:
Numeric digits (0-9) Numeric digits (0-9)
Uppercase letters (A-Z) Uppercase letters (A-Z)
Lowercase letters (a-z) Lowercase letters (a-z)
The rest of the plugin id can be whatever you like. See the plugins folder for examples: The rest of the plugin id can be whatever you like. See the plugins folder for examples:
https://github.com/HaveAGitGat/Tdarr_Plugins/tree/master/Community https://github.com/HaveAGitGat/Tdarr_Plugins/tree/master/Community
@ -29,7 +29,7 @@ Your plugin id inside the file must be exactly the same as the plugin filename.
IMPORTANT: Think carefully about what you'd like your plugin to do. You cannot change the aim of a community plugin at a later date as others may be using the plugin. After the plugin has been submitted to community plugins, you can only fix bugs, clarify details and improve plugin performance. IMPORTANT: Think carefully about what you'd like your plugin to do. You cannot change the aim of a community plugin at a later date as others may be using the plugin. After the plugin has been submitted to community plugins, you can only fix bugs, clarify details and improve plugin performance.
4.(If local plugin then you can skip this) 4.(If local plugin then you can skip this)
For the plugin link, I'll add this once you create a PR to community plugins. For the plugin link, I'll add this once you create a PR to community plugins.
5. Configure 'function plugin(file)' with logic on whether to transcode the file or not. 'file' is an object with hundreds of file properties extracted using FFprobe and ExifTool. The following response object MUST be returned by your plugin. The values shown are the default values: 5. Configure 'function plugin(file)' with logic on whether to transcode the file or not. 'file' is an object with hundreds of file properties extracted using FFprobe and ExifTool. The following response object MUST be returned by your plugin. The values shown are the default values:
@ -37,7 +37,7 @@ For the plugin link, I'll add this once you create a PR to community plugins.
var response = { var response = {
processFile: false, //If set to false, the file will be skipped. Set to true to have the file transcoded. processFile: false, //If set to false, the file will be skipped. Set to true to have the file transcoded.
preset: '', //HandBrake/FFmpeg CLI aguments you'd like to use. preset: '', //HandBrake/FFmpeg CLI aguments you'd like to use.
//For FFmpeg, the input arguments come first followed by a comma, followed by the output argument. //For FFmpeg, the input arguments come first followed by a comma, followed by the output argument.
// Examples // Examples
//HandBrake //HandBrake
@ -50,28 +50,25 @@ For the plugin link, I'll add this once you create a PR to community plugins.
reQueueAfter: false, //If you can't do all tasks in one pass, set this to true. The file will be re-added to the transcode queue reQueueAfter: false, //If you can't do all tasks in one pass, set this to true. The file will be re-added to the transcode queue
//afterwards for additional processing. See Tdarr_Plugin_hk75_Drawmonster_MP4_AAC_No_Subs_No_metaTitle //afterwards for additional processing. See Tdarr_Plugin_hk75_Drawmonster_MP4_AAC_No_Subs_No_metaTitle
//In that plugin, several passes are used to remove subs, metadata and add an aac track. //In that plugin, several passes are used to remove subs, metadata and add an aac track.
infoLog: '', //This will be shown when the user clicks the 'i' (info) button on a file in the output queue if 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. //it has been skipped.
// Give reasons why it has been skipped ('File has no title metadata, File meets conditions!') // Give reasons why it has been skipped ('File has no title metadata, File meets conditions!')
} }
Please see the bottom of this README for the structure of an example file object. To see a specific file's details, search for the file in the search tab and click the 'i' info button.
Please see the bottom of this README for the structure of an example file object. To see a specific file's details, search for the file in the search tab and click the 'i' info button.
6.Once you have finished configuring your plugin,
6.Once you have finished configuring your plugin, For community plugins:
Create a pull request to have your plugin added to:
For community plugins: https://github.com/HaveAGitGat/Tdarr_Plugins/tree/master/Community
Create a pull request to have your plugin added to:
https://github.com/HaveAGitGat/Tdarr_Plugins/tree/master/Community For local plugins:
For local plugins:
Add them to 'User\Documents\Tdarr\Plugins\Local'. In Tdarr, select 'Local' in the plugin section of the library you're in and add your local plugin id. Add them to 'User\Documents\Tdarr\Plugins\Local'. In Tdarr, select 'Local' in the plugin section of the library you're in and add your local plugin id.
Example file object: Example file object:
var file = { var file = {
_id: 'C:/Users/H/Desktop/Test Input1/Sample.mp4', _id: 'C:/Users/H/Desktop/Test Input1/Sample.mp4',
DB: 'ZRPDmnmpyuAEQi7nG', DB: 'ZRPDmnmpyuAEQi7nG',
HealthCheck: 'Not attempted', HealthCheck: 'Not attempted',
@ -312,6 +309,3 @@ Add them to 'User\Documents\Tdarr\Plugins\Local'. In Tdarr, select 'Local' in th
processingStatus: false, processingStatus: false,
video_codec_name: 'h264', video_codec_name: 'h264',
video_resolution: '720p' } video_resolution: '720p' }

@ -1,8 +1,4 @@
module.exports.details = function details() { module.exports.details = function details() {
return { return {
id: "Tdarr_Plugin_aaaa_Pre_Proc_Example", id: "Tdarr_Plugin_aaaa_Pre_Proc_Example",
Stage: "Pre-processing", //Preprocessing or Post-processing. Determines when the plugin will be executed. Stage: "Pre-processing", //Preprocessing or Post-processing. Determines when the plugin will be executed.
@ -12,12 +8,13 @@ module.exports.details = function details() {
Description: `This plugin removes metadata (if a title exists). The output container is the same as the original. \n\n`, Description: `This plugin removes metadata (if a title exists). The output container is the same as the original. \n\n`,
Version: "1.00", Version: "1.00",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugin_aaaa_Pre_Proc_Example", Link: "https://github.com/HaveAGitGat/Tdarr_Plugin_aaaa_Pre_Proc_Example",
Tags:"ffmpeg,h265", //Provide tags to categorise your plugin in the plugin browser.Tag options: h265,hevc,h264,nvenc h265,nvenc h264,video only,audio only,subtitle only,handbrake,ffmpeg,radarr,sonarr,pre-processing,post-processing,configurable Tags: "ffmpeg,h265", //Provide tags to categorise your plugin in the plugin browser.Tag options: h265,hevc,h264,nvenc h265,nvenc h264,video only,audio only,subtitle only,handbrake,ffmpeg,radarr,sonarr,pre-processing,post-processing,configurable
Inputs: [ //(Optional) Inputs you'd like the user to enter to allow your plugin to be easily configurable from the UI Inputs: [
{ //(Optional) Inputs you'd like the user to enter to allow your plugin to be easily configurable from the UI
name: 'language', {
tooltip: `Enter one language tag here for the language of the subtitles you'd like to keep. name: "language",
tooltip: `Enter one language tag here for the language of the subtitles you'd like to keep.
\\nExample:\\n \\nExample:\\n
eng eng
@ -28,357 +25,345 @@ module.exports.details = function details() {
\\nExample:\\n \\nExample:\\n
de` //Each line following `Example:` will be clearly formatted. \\n used for line breaks de`, //Each line following `Example:` will be clearly formatted. \\n used for line breaks
}, },
{ {
name: 'channels', name: "channels",
tooltip: `Desired audio channel number. tooltip: `Desired audio channel number.
\\nExample:\\n \\nExample:\\n
2` 2`,
}, },
] ],
};
} };
}
module.exports.plugin = function plugin(file, librarySettings, inputs) { module.exports.plugin = function plugin(file, librarySettings, inputs) {
//Must return this object at some point in the function else plugin will fail. //Must return this object at some point in the function else plugin will fail.
var response = { var response = {
processFile: false, //If set to false, the file will be skipped. Set to true to have the file transcoded. 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. preset: "", //HandBrake/FFmpeg CLI arguments you'd like to use.
//For FFmpeg, the input arguments come first followed by a comma, followed by the output argument. //For FFmpeg, the input arguments come first followed by a comma, followed by the output argument.
// Examples // Examples
//HandBrake //HandBrake
// '-Z "Very Fast 1080p30"' // '-Z "Very Fast 1080p30"'
//FFmpeg //FFmpeg
// '-sn,-map_metadata -1 -c:v copy -c:a copy' // '-sn,-map_metadata -1 -c:v copy -c:a copy'
container: '.mp4', // The container of the transcoded output file. container: ".mp4", // The container of the transcoded output file.
handBrakeMode: false, //Set whether to use HandBrake or FFmpeg for transcoding handBrakeMode: false, //Set whether to use HandBrake or FFmpeg for transcoding
FFmpegMode: false, FFmpegMode: false,
reQueueAfter: true, //Leave as true. File will be re-qeued afterwards and pass through the plugin filter again to make sure it meets conditions. reQueueAfter: true, //Leave as true. File will be re-qeued afterwards and pass through the plugin filter again to make sure it meets conditions.
infoLog: '', //This will be shown when the user clicks the 'i' (info) button on a file in the output queue if 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. //it has been skipped.
// Give reasons why it has been skipped ('File has no title metadata, File meets conditions!') // Give reasons why it has been skipped ('File has no title metadata, File meets conditions!')
//Optional (include together) //Optional (include together)
file, file,
removeFromDB: false, //Tell Tdarr to remove file from database if true removeFromDB: false, //Tell Tdarr to remove file from database if true
updateDB: false, //Change file object above and update database if true updateDB: false, //Change file object above and update database if true
} };
console.log(inputs.language) //eng if user entered 'eng' in input box in Tdarr plugin UI
console.log(inputs.channels) //2 if user entered '2' in input box in Tdarr plugin UI
console.log(inputs.language); //eng if user entered 'eng' in input box in Tdarr plugin UI
console.log(inputs.channels); //2 if user entered '2' in input box in Tdarr plugin UI
//Here we specify that we want the output file container to be the same as the current container. //Here we specify that we want the output file container to be the same as the current container.
response.container = '.' + file.container response.container = "." + file.container;
//We will use FFmpeg for this procedure. //We will use FFmpeg for this procedure.
response.FFmpegMode = true response.FFmpegMode = true;
//Check if file has title metadata //Check if file has title metadata
if (file.meta.Title != undefined) { if (file.meta.Title != undefined) {
//if so, remove it //if so, remove it
response.infoLog += " File has title metadata" response.infoLog += " File has title metadata";
response.preset = ',-map_metadata -1 -c:v copy -c:a copy' response.preset = ",-map_metadata -1 -c:v copy -c:a copy";
response.processFile = true response.processFile = true;
return response return response;
} else { } else {
response.infoLog += " File has no title metadata" response.infoLog += " File has no title metadata";
} }
response.infoLog += " File meets conditions!"
return response
}
module.exports.onTranscodeSuccess = function onTranscodeSuccess(file, librarySettings, inputs) {
console.log('Transcode success! Now do some stuff with the newly scanned file.') response.infoLog += " File meets conditions!";
return response;
};
module.exports.onTranscodeSuccess = function onTranscodeSuccess(
file,
librarySettings,
inputs
) {
console.log(
"Transcode success! Now do some stuff with the newly scanned file."
);
//Optional response if you need to modify database //Optional response if you need to modify database
var response = { var response = {
file, file,
removeFromDB: false, removeFromDB: false,
updateDB: false, updateDB: false,
} };
return response
}
module.exports.onTranscodeError = function onTranscodeError(file, librarySettings, inputs) { return response;
};
console.log('Transcode fail! Now do some stuff with the original file.')
module.exports.onTranscodeError = function onTranscodeError(
file,
librarySettings,
inputs
) {
console.log("Transcode fail! Now do some stuff with the original file.");
//Optional response if you need to modify database //Optional response if you need to modify database
var response = { var response = {
file, file,
removeFromDB: false, removeFromDB: false,
updateDB: false, updateDB: false,
} };
return response
}
return response;
};
//Example file object: //Example file object:
// { // {
// _id: 'C:/Users/H/Desktop/Test Input1/Sample.mp4', // _id: 'C:/Users/H/Desktop/Test Input1/Sample.mp4',
// DB: 'ZRPDmnmpyuAEQi7nG', // DB: 'ZRPDmnmpyuAEQi7nG',
// HealthCheck: 'Not attempted', // HealthCheck: 'Not attempted',
// TranscodeDecisionMaker: 'Not attempted', // TranscodeDecisionMaker: 'Not attempted',
// bit_rate: 1690430.4, // bit_rate: 1690430.4,
// container: 'mp4', // container: 'mp4',
// createdAt: 2019-09-26T06:46:31.929Z, // createdAt: 2019-09-26T06:46:31.929Z,
// ffProbeData: // ffProbeData:
// { streams: // { streams:
// [ { index: 0, // [ { index: 0,
// codec_name: 'h264', // codec_name: 'h264',
// codec_long_name: 'H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10', // codec_long_name: 'H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10',
// profile: 'Main', // profile: 'Main',
// codec_type: 'video', // codec_type: 'video',
// codec_time_base: '1/50', // codec_time_base: '1/50',
// codec_tag_string: 'avc1', // codec_tag_string: 'avc1',
// codec_tag: '0x31637661', // codec_tag: '0x31637661',
// width: 1280, // width: 1280,
// height: 720, // height: 720,
// coded_width: 1280, // coded_width: 1280,
// coded_height: 720, // coded_height: 720,
// has_b_frames: 0, // has_b_frames: 0,
// sample_aspect_ratio: '1:1', // sample_aspect_ratio: '1:1',
// display_aspect_ratio: '16:9', // display_aspect_ratio: '16:9',
// pix_fmt: 'yuv420p', // pix_fmt: 'yuv420p',
// level: 31, // level: 31,
// chroma_location: 'left', // chroma_location: 'left',
// refs: 1, // refs: 1,
// is_avc: 'true', // is_avc: 'true',
// nal_length_size: '4', // nal_length_size: '4',
// r_frame_rate: '25/1', // r_frame_rate: '25/1',
// avg_frame_rate: '25/1', // avg_frame_rate: '25/1',
// time_base: '1/12800', // time_base: '1/12800',
// start_pts: 0, // start_pts: 0,
// start_time: '0.000000', // start_time: '0.000000',
// duration_ts: 67584, // duration_ts: 67584,
// duration: '5.280000', // duration: '5.280000',
// bit_rate: '1205959', // bit_rate: '1205959',
// bits_per_raw_sample: '8', // bits_per_raw_sample: '8',
// nb_frames: '132', // nb_frames: '132',
// disposition: // disposition:
// { default: 1, // { default: 1,
// dub: 0, // dub: 0,
// original: 0, // original: 0,
// comment: 0, // comment: 0,
// lyrics: 0, // lyrics: 0,
// karaoke: 0, // karaoke: 0,
// forced: 0, // forced: 0,
// hearing_impaired: 0, // hearing_impaired: 0,
// visual_impaired: 0, // visual_impaired: 0,
// clean_effects: 0, // clean_effects: 0,
// attached_pic: 0, // attached_pic: 0,
// timed_thumbnails: 0 }, // timed_thumbnails: 0 },
// tags: // tags:
// { creation_time: '1970-01-01T00:00:00.000000Z', // { creation_time: '1970-01-01T00:00:00.000000Z',
// language: 'und', // language: 'und',
// handler_name: 'VideoHandler' } }, // handler_name: 'VideoHandler' } },
// { index: 1, // { index: 1,
// codec_name: 'aac', // codec_name: 'aac',
// codec_long_name: 'AAC (Advanced Audio Coding)', // codec_long_name: 'AAC (Advanced Audio Coding)',
// profile: 'LC', // profile: 'LC',
// codec_type: 'audio', // codec_type: 'audio',
// codec_time_base: '1/48000', // codec_time_base: '1/48000',
// codec_tag_string: 'mp4a', // codec_tag_string: 'mp4a',
// codec_tag: '0x6134706d', // codec_tag: '0x6134706d',
// sample_fmt: 'fltp', // sample_fmt: 'fltp',
// sample_rate: '48000', // sample_rate: '48000',
// channels: 6, // channels: 6,
// channel_layout: '5.1', // channel_layout: '5.1',
// bits_per_sample: 0, // bits_per_sample: 0,
// r_frame_rate: '0/0', // r_frame_rate: '0/0',
// avg_frame_rate: '0/0', // avg_frame_rate: '0/0',
// time_base: '1/48000', // time_base: '1/48000',
// start_pts: 0, // start_pts: 0,
// start_time: '0.000000', // start_time: '0.000000',
// duration_ts: 254976, // duration_ts: 254976,
// duration: '5.312000', // duration: '5.312000',
// bit_rate: '384828', // bit_rate: '384828',
// max_bit_rate: '400392', // max_bit_rate: '400392',
// nb_frames: '249', // nb_frames: '249',
// disposition: // disposition:
// { default: 1, // { default: 1,
// dub: 0, // dub: 0,
// original: 0, // original: 0,
// comment: 0, // comment: 0,
// lyrics: 0, // lyrics: 0,
// karaoke: 0, // karaoke: 0,
// forced: 0, // forced: 0,
// hearing_impaired: 0, // hearing_impaired: 0,
// visual_impaired: 0, // visual_impaired: 0,
// clean_effects: 0, // clean_effects: 0,
// attached_pic: 0, // attached_pic: 0,
// timed_thumbnails: 0 }, // timed_thumbnails: 0 },
// tags: // tags:
// { creation_time: '1970-01-01T00:00:00.000000Z', // { creation_time: '1970-01-01T00:00:00.000000Z',
// language: 'und', // language: 'und',
// handler_name: 'SoundHandler' } } ] }, // handler_name: 'SoundHandler' } } ] },
// ffProbeRead: 'success', // ffProbeRead: 'success',
// file: 'C:/Users/H/Desktop/Test Input1/Sample.mp4', // file: 'C:/Users/H/Desktop/Test Input1/Sample.mp4',
// fileMedium: 'video', // fileMedium: 'video',
// file_size: 1.056519, // file_size: 1.056519,
// meta: // meta:
// { SourceFile: 'C:/Users/H/Desktop/Test Input1/Sample.mp4', // { SourceFile: 'C:/Users/H/Desktop/Test Input1/Sample.mp4',
// errors: [], // errors: [],
// Duration: 5.312, // Duration: 5.312,
// PreviewDuration: 0, // PreviewDuration: 0,
// SelectionDuration: 0, // SelectionDuration: 0,
// TrackDuration: 5.28, // TrackDuration: 5.28,
// MediaDuration: 5.312, // MediaDuration: 5.312,
// ExifToolVersion: 11.65, // ExifToolVersion: 11.65,
// FileName: 'Sample.mp4', // FileName: 'Sample.mp4',
// Directory: 'C:/Users/H/Desktop/Test Input1', // Directory: 'C:/Users/H/Desktop/Test Input1',
// FileSize: '1032 kB', // FileSize: '1032 kB',
// FileModifyDate: // FileModifyDate:
// { year: 2019, // { year: 2019,
// month: 9, // month: 9,
// day: 24, // day: 24,
// hour: 7, // hour: 7,
// minute: 24, // minute: 24,
// second: 22, // second: 22,
// millisecond: 0, // millisecond: 0,
// tzoffsetMinutes: 60, // tzoffsetMinutes: 60,
// rawValue: '2019:09:24 07:24:22+01:00' }, // rawValue: '2019:09:24 07:24:22+01:00' },
// FileAccessDate: // FileAccessDate:
// { year: 2019, // { year: 2019,
// month: 9, // month: 9,
// day: 26, // day: 26,
// hour: 7, // hour: 7,
// minute: 44, // minute: 44,
// second: 30, // second: 30,
// millisecond: 0, // millisecond: 0,
// tzoffsetMinutes: 60, // tzoffsetMinutes: 60,
// rawValue: '2019:09:26 07:44:30+01:00' }, // rawValue: '2019:09:26 07:44:30+01:00' },
// FileCreateDate: // FileCreateDate:
// { year: 2019, // { year: 2019,
// month: 9, // month: 9,
// day: 26, // day: 26,
// hour: 7, // hour: 7,
// minute: 44, // minute: 44,
// second: 30, // second: 30,
// millisecond: 0, // millisecond: 0,
// tzoffsetMinutes: 60, // tzoffsetMinutes: 60,
// rawValue: '2019:09:26 07:44:30+01:00' }, // rawValue: '2019:09:26 07:44:30+01:00' },
// FilePermissions: 'rw-rw-rw-', // FilePermissions: 'rw-rw-rw-',
// FileType: 'MP4', // FileType: 'MP4',
// FileTypeExtension: 'mp4', // FileTypeExtension: 'mp4',
// MIMEType: 'video/mp4', // MIMEType: 'video/mp4',
// MajorBrand: 'MP4 Base Media v1 [IS0 14496-12:2003]', // MajorBrand: 'MP4 Base Media v1 [IS0 14496-12:2003]',
// MinorVersion: '0.2.0', // MinorVersion: '0.2.0',
// CompatibleBrands: [ 'isom', 'iso2', 'avc1', 'mp41' ], // CompatibleBrands: [ 'isom', 'iso2', 'avc1', 'mp41' ],
// MovieDataSize: 0, // MovieDataSize: 0,
// MovieDataOffset: 1051515, // MovieDataOffset: 1051515,
// MovieHeaderVersion: 0, // MovieHeaderVersion: 0,
// CreateDate: // CreateDate:
// { year: 1970, // { year: 1970,
// month: 1, // month: 1,
// day: 8, // day: 8,
// hour: 0, // hour: 0,
// minute: 0, // minute: 0,
// second: 0, // second: 0,
// millisecond: 0, // millisecond: 0,
// rawValue: '1970:01:08 00:00:00' }, // rawValue: '1970:01:08 00:00:00' },
// ModifyDate: // ModifyDate:
// { year: 2014, // { year: 2014,
// month: 7, // month: 7,
// day: 19, // day: 19,
// hour: 17, // hour: 17,
// minute: 15, // minute: 15,
// second: 29, // second: 29,
// millisecond: 0, // millisecond: 0,
// rawValue: '2014:07:19 17:15:29' }, // rawValue: '2014:07:19 17:15:29' },
// TimeScale: 1000, // TimeScale: 1000,
// PreferredRate: 1, // PreferredRate: 1,
// PreferredVolume: '100.00%', // PreferredVolume: '100.00%',
// PreviewTime: '0 s', // PreviewTime: '0 s',
// PosterTime: '0 s', // PosterTime: '0 s',
// SelectionTime: '0 s', // SelectionTime: '0 s',
// CurrentTime: '0 s', // CurrentTime: '0 s',
// NextTrackID: 3, // NextTrackID: 3,
// TrackHeaderVersion: 0, // TrackHeaderVersion: 0,
// TrackCreateDate: '0000:00:00 00:00:00', // TrackCreateDate: '0000:00:00 00:00:00',
// TrackModifyDate: '0000:00:00 00:00:00', // TrackModifyDate: '0000:00:00 00:00:00',
// TrackID: 1, // TrackID: 1,
// TrackLayer: 0, // TrackLayer: 0,
// TrackVolume: '0.00%', // TrackVolume: '0.00%',
// ImageWidth: 1280, // ImageWidth: 1280,
// ImageHeight: 720, // ImageHeight: 720,
// GraphicsMode: 'srcCopy', // GraphicsMode: 'srcCopy',
// OpColor: '0 0 0', // OpColor: '0 0 0',
// CompressorID: 'avc1', // CompressorID: 'avc1',
// SourceImageWidth: 1280, // SourceImageWidth: 1280,
// SourceImageHeight: 720, // SourceImageHeight: 720,
// XResolution: 72, // XResolution: 72,
// YResolution: 72, // YResolution: 72,
// BitDepth: 24, // BitDepth: 24,
// VideoFrameRate: 25, // VideoFrameRate: 25,
// MatrixStructure: '1 0 0 0 1 0 0 0 1', // MatrixStructure: '1 0 0 0 1 0 0 0 1',
// MediaHeaderVersion: 0, // MediaHeaderVersion: 0,
// MediaCreateDate: '0000:00:00 00:00:00', // MediaCreateDate: '0000:00:00 00:00:00',
// MediaModifyDate: '0000:00:00 00:00:00', // MediaModifyDate: '0000:00:00 00:00:00',
// MediaTimeScale: 48000, // MediaTimeScale: 48000,
// MediaLanguageCode: 'und', // MediaLanguageCode: 'und',
// HandlerDescription: 'SoundHandler', // HandlerDescription: 'SoundHandler',
// Balance: 0, // Balance: 0,
// AudioFormat: 'mp4a', // AudioFormat: 'mp4a',
// AudioChannels: 2, // AudioChannels: 2,
// AudioBitsPerSample: 16, // AudioBitsPerSample: 16,
// AudioSampleRate: 48000, // AudioSampleRate: 48000,
// HandlerType: 'Metadata', // HandlerType: 'Metadata',
// HandlerVendorID: 'Apple', // HandlerVendorID: 'Apple',
// Encoder: 'Lavf53.24.2', // Encoder: 'Lavf53.24.2',
// Title: 'Sample title test', // Title: 'Sample title test',
// Composer: 'th', // Composer: 'th',
// BeatsPerMinute: '', // BeatsPerMinute: '',
// ContentCreateDate: 2018, // ContentCreateDate: 2018,
// Genre: 'this', // Genre: 'this',
// Artist: 'hhj', // Artist: 'hhj',
// Comment: 'hhk', // Comment: 'hhk',
// Subtitle: 'jj', // Subtitle: 'jj',
// Mood: 'lik', // Mood: 'lik',
// ContentDistributor: 'cont', // ContentDistributor: 'cont',
// Conductor: 'jo', // Conductor: 'jo',
// Writer: 'writ', // Writer: 'writ',
// InitialKey: 'ho', // InitialKey: 'ho',
// Producer: 'prod', // Producer: 'prod',
// ParentalRating: 'par', // ParentalRating: 'par',
// Director: 'dir', // Director: 'dir',
// Period: 'pol', // Period: 'pol',
// Publisher: 'pub', // Publisher: 'pub',
// PromotionURL: 'prom', // PromotionURL: 'prom',
// AuthorURL: 'auth', // AuthorURL: 'auth',
// EncodedBy: 'enc', // EncodedBy: 'enc',
// Category: 'h', // Category: 'h',
// ImageSize: '1280x720', // ImageSize: '1280x720',
// Megapixels: 0.922, // Megapixels: 0.922,
// AvgBitrate: '1.58 Mbps', // AvgBitrate: '1.58 Mbps',
// Rotation: 0 }, // Rotation: 0 },
// processingStatus: false, // processingStatus: false,
// video_codec_name: 'h264', // video_codec_name: 'h264',
// video_resolution: '720p' } // video_resolution: '720p' }

@ -1,8 +1,4 @@
module.exports.details = function details() { module.exports.details = function details() {
return { return {
id: "Tdarr_Plugin_zzzz_Post_Proc_Example", id: "Tdarr_Plugin_zzzz_Post_Proc_Example",
Stage: "Post-processing", //Preprocessing or Post-processing. Determines when the plugin will be executed. This plugin does some stuff after all plugins have been executed Stage: "Post-processing", //Preprocessing or Post-processing. Determines when the plugin will be executed. This plugin does some stuff after all plugins have been executed
@ -12,12 +8,13 @@ module.exports.details = function details() {
Description: `This plugin does some stuff after all plugins have been executed. \n\n`, Description: `This plugin does some stuff after all plugins have been executed. \n\n`,
Version: "1.00", Version: "1.00",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugin_aaaa_Post_Proc_Example", Link: "https://github.com/HaveAGitGat/Tdarr_Plugin_aaaa_Post_Proc_Example",
Tags:"ffmpeg,h265", //Provide tags to categorise your plugin in the plugin browser.Tag options: h265,hevc,h264,nvenc h265,nvenc h264,video only,audio only,subtitle only,handbrake,ffmpeg,radarr,sonarr,pre-processing,post-processing,configurable Tags: "ffmpeg,h265", //Provide tags to categorise your plugin in the plugin browser.Tag options: h265,hevc,h264,nvenc h265,nvenc h264,video only,audio only,subtitle only,handbrake,ffmpeg,radarr,sonarr,pre-processing,post-processing,configurable
Inputs: [ //(Optional) Inputs you'd like the user to enter to allow your plugin to be easily configurable from the UI Inputs: [
{ //(Optional) Inputs you'd like the user to enter to allow your plugin to be easily configurable from the UI
name: 'language', {
tooltip: `Enter one language tag here for the language of the subtitles you'd like to keep. name: "language",
tooltip: `Enter one language tag here for the language of the subtitles you'd like to keep.
\\nExample:\\n \\nExample:\\n
eng eng
@ -26,277 +23,273 @@ module.exports.details = function details() {
fr fr
\\nExample:\\n \\nExample:\\n
de` //Each line following `Example:` will be clearly formatted. \\n used for line breaks de`, //Each line following `Example:` will be clearly formatted. \\n used for line breaks
}, },
{ {
name: 'channels', name: "channels",
tooltip: `Desired audio channel number. tooltip: `Desired audio channel number.
\\nExample:\\n \\nExample:\\n
2` 2`,
}, },
] ],
};
} };
}
module.exports.plugin = function plugin(file, librarySettings, inputs) { module.exports.plugin = function plugin(file, librarySettings, inputs) {
console.log(
console.log('Transcode success! Now do some stuff with the newly scanned file.') "Transcode success! Now do some stuff with the newly scanned file."
);
//Optional response if you need to modify database //Optional response if you need to modify database
var response = { var response = {
file, file,
removeFromDB: false, removeFromDB: false,
updateDB: false, updateDB: false,
} };
return response
}
return response;
};
//Example file object: //Example file object:
// { // {
// _id: 'C:/Users/H/Desktop/Test Input1/Sample.mp4', // _id: 'C:/Users/H/Desktop/Test Input1/Sample.mp4',
// DB: 'ZRPDmnmpyuAEQi7nG', // DB: 'ZRPDmnmpyuAEQi7nG',
// HealthCheck: 'Not attempted', // HealthCheck: 'Not attempted',
// TranscodeDecisionMaker: 'Not attempted', // TranscodeDecisionMaker: 'Not attempted',
// bit_rate: 1690430.4, // bit_rate: 1690430.4,
// container: 'mp4', // container: 'mp4',
// createdAt: 2019-09-26T06:46:31.929Z, // createdAt: 2019-09-26T06:46:31.929Z,
// ffProbeData: // ffProbeData:
// { streams: // { streams:
// [ { index: 0, // [ { index: 0,
// codec_name: 'h264', // codec_name: 'h264',
// codec_long_name: 'H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10', // codec_long_name: 'H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10',
// profile: 'Main', // profile: 'Main',
// codec_type: 'video', // codec_type: 'video',
// codec_time_base: '1/50', // codec_time_base: '1/50',
// codec_tag_string: 'avc1', // codec_tag_string: 'avc1',
// codec_tag: '0x31637661', // codec_tag: '0x31637661',
// width: 1280, // width: 1280,
// height: 720, // height: 720,
// coded_width: 1280, // coded_width: 1280,
// coded_height: 720, // coded_height: 720,
// has_b_frames: 0, // has_b_frames: 0,
// sample_aspect_ratio: '1:1', // sample_aspect_ratio: '1:1',
// display_aspect_ratio: '16:9', // display_aspect_ratio: '16:9',
// pix_fmt: 'yuv420p', // pix_fmt: 'yuv420p',
// level: 31, // level: 31,
// chroma_location: 'left', // chroma_location: 'left',
// refs: 1, // refs: 1,
// is_avc: 'true', // is_avc: 'true',
// nal_length_size: '4', // nal_length_size: '4',
// r_frame_rate: '25/1', // r_frame_rate: '25/1',
// avg_frame_rate: '25/1', // avg_frame_rate: '25/1',
// time_base: '1/12800', // time_base: '1/12800',
// start_pts: 0, // start_pts: 0,
// start_time: '0.000000', // start_time: '0.000000',
// duration_ts: 67584, // duration_ts: 67584,
// duration: '5.280000', // duration: '5.280000',
// bit_rate: '1205959', // bit_rate: '1205959',
// bits_per_raw_sample: '8', // bits_per_raw_sample: '8',
// nb_frames: '132', // nb_frames: '132',
// disposition: // disposition:
// { default: 1, // { default: 1,
// dub: 0, // dub: 0,
// original: 0, // original: 0,
// comment: 0, // comment: 0,
// lyrics: 0, // lyrics: 0,
// karaoke: 0, // karaoke: 0,
// forced: 0, // forced: 0,
// hearing_impaired: 0, // hearing_impaired: 0,
// visual_impaired: 0, // visual_impaired: 0,
// clean_effects: 0, // clean_effects: 0,
// attached_pic: 0, // attached_pic: 0,
// timed_thumbnails: 0 }, // timed_thumbnails: 0 },
// tags: // tags:
// { creation_time: '1970-01-01T00:00:00.000000Z', // { creation_time: '1970-01-01T00:00:00.000000Z',
// language: 'und', // language: 'und',
// handler_name: 'VideoHandler' } }, // handler_name: 'VideoHandler' } },
// { index: 1, // { index: 1,
// codec_name: 'aac', // codec_name: 'aac',
// codec_long_name: 'AAC (Advanced Audio Coding)', // codec_long_name: 'AAC (Advanced Audio Coding)',
// profile: 'LC', // profile: 'LC',
// codec_type: 'audio', // codec_type: 'audio',
// codec_time_base: '1/48000', // codec_time_base: '1/48000',
// codec_tag_string: 'mp4a', // codec_tag_string: 'mp4a',
// codec_tag: '0x6134706d', // codec_tag: '0x6134706d',
// sample_fmt: 'fltp', // sample_fmt: 'fltp',
// sample_rate: '48000', // sample_rate: '48000',
// channels: 6, // channels: 6,
// channel_layout: '5.1', // channel_layout: '5.1',
// bits_per_sample: 0, // bits_per_sample: 0,
// r_frame_rate: '0/0', // r_frame_rate: '0/0',
// avg_frame_rate: '0/0', // avg_frame_rate: '0/0',
// time_base: '1/48000', // time_base: '1/48000',
// start_pts: 0, // start_pts: 0,
// start_time: '0.000000', // start_time: '0.000000',
// duration_ts: 254976, // duration_ts: 254976,
// duration: '5.312000', // duration: '5.312000',
// bit_rate: '384828', // bit_rate: '384828',
// max_bit_rate: '400392', // max_bit_rate: '400392',
// nb_frames: '249', // nb_frames: '249',
// disposition: // disposition:
// { default: 1, // { default: 1,
// dub: 0, // dub: 0,
// original: 0, // original: 0,
// comment: 0, // comment: 0,
// lyrics: 0, // lyrics: 0,
// karaoke: 0, // karaoke: 0,
// forced: 0, // forced: 0,
// hearing_impaired: 0, // hearing_impaired: 0,
// visual_impaired: 0, // visual_impaired: 0,
// clean_effects: 0, // clean_effects: 0,
// attached_pic: 0, // attached_pic: 0,
// timed_thumbnails: 0 }, // timed_thumbnails: 0 },
// tags: // tags:
// { creation_time: '1970-01-01T00:00:00.000000Z', // { creation_time: '1970-01-01T00:00:00.000000Z',
// language: 'und', // language: 'und',
// handler_name: 'SoundHandler' } } ] }, // handler_name: 'SoundHandler' } } ] },
// ffProbeRead: 'success', // ffProbeRead: 'success',
// file: 'C:/Users/H/Desktop/Test Input1/Sample.mp4', // file: 'C:/Users/H/Desktop/Test Input1/Sample.mp4',
// fileMedium: 'video', // fileMedium: 'video',
// file_size: 1.056519, // file_size: 1.056519,
// meta: // meta:
// { SourceFile: 'C:/Users/H/Desktop/Test Input1/Sample.mp4', // { SourceFile: 'C:/Users/H/Desktop/Test Input1/Sample.mp4',
// errors: [], // errors: [],
// Duration: 5.312, // Duration: 5.312,
// PreviewDuration: 0, // PreviewDuration: 0,
// SelectionDuration: 0, // SelectionDuration: 0,
// TrackDuration: 5.28, // TrackDuration: 5.28,
// MediaDuration: 5.312, // MediaDuration: 5.312,
// ExifToolVersion: 11.65, // ExifToolVersion: 11.65,
// FileName: 'Sample.mp4', // FileName: 'Sample.mp4',
// Directory: 'C:/Users/H/Desktop/Test Input1', // Directory: 'C:/Users/H/Desktop/Test Input1',
// FileSize: '1032 kB', // FileSize: '1032 kB',
// FileModifyDate: // FileModifyDate:
// { year: 2019, // { year: 2019,
// month: 9, // month: 9,
// day: 24, // day: 24,
// hour: 7, // hour: 7,
// minute: 24, // minute: 24,
// second: 22, // second: 22,
// millisecond: 0, // millisecond: 0,
// tzoffsetMinutes: 60, // tzoffsetMinutes: 60,
// rawValue: '2019:09:24 07:24:22+01:00' }, // rawValue: '2019:09:24 07:24:22+01:00' },
// FileAccessDate: // FileAccessDate:
// { year: 2019, // { year: 2019,
// month: 9, // month: 9,
// day: 26, // day: 26,
// hour: 7, // hour: 7,
// minute: 44, // minute: 44,
// second: 30, // second: 30,
// millisecond: 0, // millisecond: 0,
// tzoffsetMinutes: 60, // tzoffsetMinutes: 60,
// rawValue: '2019:09:26 07:44:30+01:00' }, // rawValue: '2019:09:26 07:44:30+01:00' },
// FileCreateDate: // FileCreateDate:
// { year: 2019, // { year: 2019,
// month: 9, // month: 9,
// day: 26, // day: 26,
// hour: 7, // hour: 7,
// minute: 44, // minute: 44,
// second: 30, // second: 30,
// millisecond: 0, // millisecond: 0,
// tzoffsetMinutes: 60, // tzoffsetMinutes: 60,
// rawValue: '2019:09:26 07:44:30+01:00' }, // rawValue: '2019:09:26 07:44:30+01:00' },
// FilePermissions: 'rw-rw-rw-', // FilePermissions: 'rw-rw-rw-',
// FileType: 'MP4', // FileType: 'MP4',
// FileTypeExtension: 'mp4', // FileTypeExtension: 'mp4',
// MIMEType: 'video/mp4', // MIMEType: 'video/mp4',
// MajorBrand: 'MP4 Base Media v1 [IS0 14496-12:2003]', // MajorBrand: 'MP4 Base Media v1 [IS0 14496-12:2003]',
// MinorVersion: '0.2.0', // MinorVersion: '0.2.0',
// CompatibleBrands: [ 'isom', 'iso2', 'avc1', 'mp41' ], // CompatibleBrands: [ 'isom', 'iso2', 'avc1', 'mp41' ],
// MovieDataSize: 0, // MovieDataSize: 0,
// MovieDataOffset: 1051515, // MovieDataOffset: 1051515,
// MovieHeaderVersion: 0, // MovieHeaderVersion: 0,
// CreateDate: // CreateDate:
// { year: 1970, // { year: 1970,
// month: 1, // month: 1,
// day: 8, // day: 8,
// hour: 0, // hour: 0,
// minute: 0, // minute: 0,
// second: 0, // second: 0,
// millisecond: 0, // millisecond: 0,
// rawValue: '1970:01:08 00:00:00' }, // rawValue: '1970:01:08 00:00:00' },
// ModifyDate: // ModifyDate:
// { year: 2014, // { year: 2014,
// month: 7, // month: 7,
// day: 19, // day: 19,
// hour: 17, // hour: 17,
// minute: 15, // minute: 15,
// second: 29, // second: 29,
// millisecond: 0, // millisecond: 0,
// rawValue: '2014:07:19 17:15:29' }, // rawValue: '2014:07:19 17:15:29' },
// TimeScale: 1000, // TimeScale: 1000,
// PreferredRate: 1, // PreferredRate: 1,
// PreferredVolume: '100.00%', // PreferredVolume: '100.00%',
// PreviewTime: '0 s', // PreviewTime: '0 s',
// PosterTime: '0 s', // PosterTime: '0 s',
// SelectionTime: '0 s', // SelectionTime: '0 s',
// CurrentTime: '0 s', // CurrentTime: '0 s',
// NextTrackID: 3, // NextTrackID: 3,
// TrackHeaderVersion: 0, // TrackHeaderVersion: 0,
// TrackCreateDate: '0000:00:00 00:00:00', // TrackCreateDate: '0000:00:00 00:00:00',
// TrackModifyDate: '0000:00:00 00:00:00', // TrackModifyDate: '0000:00:00 00:00:00',
// TrackID: 1, // TrackID: 1,
// TrackLayer: 0, // TrackLayer: 0,
// TrackVolume: '0.00%', // TrackVolume: '0.00%',
// ImageWidth: 1280, // ImageWidth: 1280,
// ImageHeight: 720, // ImageHeight: 720,
// GraphicsMode: 'srcCopy', // GraphicsMode: 'srcCopy',
// OpColor: '0 0 0', // OpColor: '0 0 0',
// CompressorID: 'avc1', // CompressorID: 'avc1',
// SourceImageWidth: 1280, // SourceImageWidth: 1280,
// SourceImageHeight: 720, // SourceImageHeight: 720,
// XResolution: 72, // XResolution: 72,
// YResolution: 72, // YResolution: 72,
// BitDepth: 24, // BitDepth: 24,
// VideoFrameRate: 25, // VideoFrameRate: 25,
// MatrixStructure: '1 0 0 0 1 0 0 0 1', // MatrixStructure: '1 0 0 0 1 0 0 0 1',
// MediaHeaderVersion: 0, // MediaHeaderVersion: 0,
// MediaCreateDate: '0000:00:00 00:00:00', // MediaCreateDate: '0000:00:00 00:00:00',
// MediaModifyDate: '0000:00:00 00:00:00', // MediaModifyDate: '0000:00:00 00:00:00',
// MediaTimeScale: 48000, // MediaTimeScale: 48000,
// MediaLanguageCode: 'und', // MediaLanguageCode: 'und',
// HandlerDescription: 'SoundHandler', // HandlerDescription: 'SoundHandler',
// Balance: 0, // Balance: 0,
// AudioFormat: 'mp4a', // AudioFormat: 'mp4a',
// AudioChannels: 2, // AudioChannels: 2,
// AudioBitsPerSample: 16, // AudioBitsPerSample: 16,
// AudioSampleRate: 48000, // AudioSampleRate: 48000,
// HandlerType: 'Metadata', // HandlerType: 'Metadata',
// HandlerVendorID: 'Apple', // HandlerVendorID: 'Apple',
// Encoder: 'Lavf53.24.2', // Encoder: 'Lavf53.24.2',
// Title: 'Sample title test', // Title: 'Sample title test',
// Composer: 'th', // Composer: 'th',
// BeatsPerMinute: '', // BeatsPerMinute: '',
// ContentCreateDate: 2018, // ContentCreateDate: 2018,
// Genre: 'this', // Genre: 'this',
// Artist: 'hhj', // Artist: 'hhj',
// Comment: 'hhk', // Comment: 'hhk',
// Subtitle: 'jj', // Subtitle: 'jj',
// Mood: 'lik', // Mood: 'lik',
// ContentDistributor: 'cont', // ContentDistributor: 'cont',
// Conductor: 'jo', // Conductor: 'jo',
// Writer: 'writ', // Writer: 'writ',
// InitialKey: 'ho', // InitialKey: 'ho',
// Producer: 'prod', // Producer: 'prod',
// ParentalRating: 'par', // ParentalRating: 'par',
// Director: 'dir', // Director: 'dir',
// Period: 'pol', // Period: 'pol',
// Publisher: 'pub', // Publisher: 'pub',
// PromotionURL: 'prom', // PromotionURL: 'prom',
// AuthorURL: 'auth', // AuthorURL: 'auth',
// EncodedBy: 'enc', // EncodedBy: 'enc',
// Category: 'h', // Category: 'h',
// ImageSize: '1280x720', // ImageSize: '1280x720',
// Megapixels: 0.922, // Megapixels: 0.922,
// AvgBitrate: '1.58 Mbps', // AvgBitrate: '1.58 Mbps',
// Rotation: 0 }, // Rotation: 0 },
// processingStatus: false, // processingStatus: false,
// video_codec_name: 'h264', // video_codec_name: 'h264',
// video_resolution: '720p' } // video_resolution: '720p' }

@ -1,14 +1,21 @@
var fs = require('fs'); var fs = require("fs");
var path = require("path"); var path = require("path");
if (fs.existsSync(path.join(process.cwd() , "/npm"))) { if (fs.existsSync(path.join(process.cwd(), "/npm"))) {
var rootModules = path.join(process.cwd() , '/npm/node_modules/') var rootModules = path.join(process.cwd(), "/npm/node_modules/");
} else{ } else {
var rootModules = '' var rootModules = "";
} }
const importFresh = require(rootModules+'import-fresh'); const importFresh = require(rootModules + "import-fresh");
module.exports.remuxContainer = importFresh(
module.exports.remuxContainer = importFresh('./library/actions/remuxContainer.js') "./library/actions/remuxContainer.js"
module.exports.transcodeStandardiseAudioCodecs = importFresh('./library/actions/transcodeStandardiseAudioCodecs.js') );
module.exports.transcodeAddAudioStream = importFresh('./library/actions/transcodeAddAudioStream.js') module.exports.transcodeStandardiseAudioCodecs = importFresh(
module.exports.transcodeKeepOneAudioStream = importFresh('./library/actions/transcodeKeepOneAudioStream.js') "./library/actions/transcodeStandardiseAudioCodecs.js"
);
module.exports.transcodeAddAudioStream = importFresh(
"./library/actions/transcodeAddAudioStream.js"
);
module.exports.transcodeKeepOneAudioStream = importFresh(
"./library/actions/transcodeKeepOneAudioStream.js"
);

@ -1,15 +1,20 @@
var fs = require('fs'); var fs = require("fs");
var path = require("path"); var path = require("path");
if (fs.existsSync(path.join(process.cwd() , "/npm"))) { if (fs.existsSync(path.join(process.cwd(), "/npm"))) {
var rootModules = path.join(process.cwd() , '/npm/node_modules/') var rootModules = path.join(process.cwd(), "/npm/node_modules/");
} else{ } else {
var rootModules = '' var rootModules = "";
} }
const importFresh = require(rootModules+'import-fresh'); const importFresh = require(rootModules + "import-fresh");
module.exports.filterByAge = importFresh("./library/filters/filterByAge.js");
module.exports.filterByAge = importFresh('./library/filters/filterByAge.js') module.exports.filterByCodec = importFresh(
module.exports.filterByCodec = importFresh('./library/filters/filterByCodec.js') "./library/filters/filterByCodec.js"
module.exports.filterByMedium = importFresh('./library/filters/filterByMedium.js') );
module.exports.filterByResolution = importFresh('./library/filters/filterByResolution.js') module.exports.filterByMedium = importFresh(
module.exports.filterBySize = importFresh('./library/filters/filterBySize.js') "./library/filters/filterByMedium.js"
);
module.exports.filterByResolution = importFresh(
"./library/filters/filterByResolution.js"
);
module.exports.filterBySize = importFresh("./library/filters/filterBySize.js");

@ -1,11 +1,11 @@
var fs = require('fs'); var fs = require("fs");
var path = require("path"); var path = require("path");
if (fs.existsSync(path.join(process.cwd() , "/npm"))) { if (fs.existsSync(path.join(process.cwd(), "/npm"))) {
var rootModules = path.join(process.cwd() , '/npm/node_modules/') var rootModules = path.join(process.cwd(), "/npm/node_modules/");
} else{ } else {
var rootModules = '' var rootModules = "";
} }
const importFresh = require(rootModules+'import-fresh'); const importFresh = require(rootModules + "import-fresh");
module.exports.filters = importFresh('./filters.js') module.exports.filters = importFresh("./filters.js");
module.exports.actions = importFresh('./actions.js') module.exports.actions = importFresh("./actions.js");

@ -1,38 +1,25 @@
function remuxContainer(file, container) { function remuxContainer(file, container) {
try {
try { if (file.container != container) {
var response = {
processFile: true,
if (file.container != container) { note: `File is not in ${container} \n`,
};
var response = { return response;
processFile: true, } else {
note:`File is not in ${container} \n` var response = {
} processFile: false,
return response note: `File is already in ${container} \n`,
};
} else { return response;
var response = {
processFile: false,
note:`File is already in ${container} \n`
}
return response
}
} catch (err) {
var response = {
processFile: false,
note:`library.actions.remuxContainer error: ${err} \n`
}
return response
} }
} catch (err) {
var response = {
processFile: false,
note: `library.actions.remuxContainer error: ${err} \n`,
};
return response;
}
} }
module.exports = remuxContainer;
module.exports = remuxContainer

@ -1,313 +1,276 @@
module.exports = function transcodeAddAudioStream(
file,
audioEncoder,
langTag,
channelCount
) {
// response.preset = library.actions.transcodeAddAudioStream(file, 'aac', 'en', 1).preset
//Function required responses
// preset
// processFile
// note
try {
var audioCodec = audioEncoder;
langTag = langTag.toLowerCase();
if (audioEncoder == "dca") {
audioCodec = "dts";
}
if (audioEncoder == "libmp3lame") {
audioCodec = "mp3";
}
module.exports = function transcodeAddAudioStream(file, audioEncoder, langTag, channelCount) { //Step 1: Check if the file already has the required stream codec/langtag/channel count
// response.preset = library.actions.transcodeAddAudioStream(file, 'aac', 'en', 1).preset var hasStreamAlready = file.ffProbeData.streams.filter((stream) => {
try {
//Function required responses if (
// preset stream.codec_type == "audio" &&
// processFile stream.codec_name === audioCodec &&
// note stream.tags.language.toLowerCase().includes(langTag.toLowerCase()) &&
stream.channels == channelCount
try { ) {
return true;
var audioCodec = audioEncoder
langTag = langTag.toLowerCase()
if (audioEncoder == 'dca') {
audioCodec = 'dts'
}
if (audioEncoder == 'libmp3lame') {
audioCodec = 'mp3'
} }
} catch (err) {}
//Step 1: Check if the file already has the required stream codec/langtag/channel count return false;
});
var hasStreamAlready = file.ffProbeData.streams.filter(stream => { if (hasStreamAlready.length > 0) {
return {
try { preset: "",
if (stream.codec_type == 'audio' && stream.codec_name === audioCodec && stream.tags.language.toLowerCase().includes(langTag.toLowerCase()) && stream.channels == channelCount) { processFile: false,
return true note: `File already has ${langTag} stream in ${audioEncoder}, ${channelCount} channels\n`,
} };
}
} catch (err) { }
return false
})
if (hasStreamAlready.length > 0) { //Step 2: Check if file has streams with specified lang tag
return { var streamsWithLangTag = file.ffProbeData.streams.filter((stream) => {
preset: '', try {
processFile: false, if (
note: `File already has ${langTag} stream in ${audioEncoder}, ${channelCount} channels\n` stream.codec_type == "audio" &&
} stream.tags.language.toLowerCase().includes(langTag)
) {
return true;
} }
} catch (err) {}
return false;
});
//Step 2: Check if file has streams with specified lang tag console.log("streamsWithLangTag:" + streamsWithLangTag);
var streamsWithLangTag = file.ffProbeData.streams.filter(stream => {
try {
if (stream.codec_type == 'audio' && stream.tags.language.toLowerCase().includes(langTag)) {
return true
}
} catch (err) { }
return false if (streamsWithLangTag.length != 0) {
return attemptMakeStreamLang(langTag);
}) } else {
return attemptMakeStreamUnd("und");
console.log("streamsWithLangTag:" + streamsWithLangTag) }
if (streamsWithLangTag.length != 0) {
return attemptMakeStreamLang(langTag)
function attemptMakeStreamLang(langTag) {
var streamsWithLangTag = file.ffProbeData.streams.filter((stream) => {
try {
if (
stream.codec_type == "audio" &&
stream.tags.language.toLowerCase().includes(langTag)
) {
return true;
}
} catch (err) {}
return false;
});
var highestChannelCount = streamsWithLangTag.reduce(getHighest);
function getHighest(first, second) {
if (first.channels > second.channels && first) {
return first;
} else { } else {
return second;
return attemptMakeStreamUnd('und')
} }
}
function attemptMakeStreamLang(langTag) { if (parseInt(highestChannelCount.channels) >= parseInt(channelCount)) {
var hasStreamAlready = file.ffProbeData.streams.filter((stream) => {
try {
var streamsWithLangTag = file.ffProbeData.streams.filter(stream => { if (
try { stream.codec_type == "audio" &&
if (stream.codec_type == 'audio' && stream.tags.language.toLowerCase().includes(langTag)) { stream.codec_name === audioCodec &&
stream.tags.language
return true .toLowerCase()
} .includes(langTag.toLowerCase()) &&
stream.channels == channelCount
} catch (err) { } ) {
return true;
return false
})
var highestChannelCount = streamsWithLangTag.reduce(getHighest)
function getHighest(first, second) {
if (first.channels > second.channels && first) {
return first
} else {
return second
}
} }
} catch (err) {}
return false;
});
if (hasStreamAlready.length > 0) {
if (parseInt(highestChannelCount.channels) >= parseInt(channelCount)) { return {
preset: "",
var hasStreamAlready = file.ffProbeData.streams.filter(stream => { processFile: false,
note: `File already has ${langTag} stream in ${audioEncoder}, ${channelCount} channels \n`,
try { };
if (stream.codec_type == 'audio' && stream.codec_name === audioCodec && stream.tags.language.toLowerCase().includes(langTag.toLowerCase()) && stream.channels == channelCount) { } else {
return true return {
} preset: `,-map 0:v -map 0:${highestChannelCount.index} -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${audioEncoder} -ac ${channelCount}`,
processFile: true,
} catch (err) { } note: `The required channel count ${channelCount} is lower than the highest available channel count (${highestChannelCount.channels}). Adding! \n`,
};
return false
})
if (hasStreamAlready.length > 0) {
return {
preset: '',
processFile: false,
note: `File already has ${langTag} stream in ${audioEncoder}, ${channelCount} channels \n`
}
} else {
return {
preset: `,-map 0:v -map 0:${highestChannelCount.index} -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${audioEncoder} -ac ${channelCount}`,
processFile: true,
note: `The required channel count ${channelCount} is lower than the highest available channel count (${highestChannelCount.channels}). Adding! \n`
}
}
} else {
console.log('here3')
var hasStreamAlready = file.ffProbeData.streams.filter(stream => {
try {
if (stream.codec_type == 'audio' && stream.codec_name === audioCodec && stream.tags.language.toLowerCase().includes(langTag.toLowerCase()) && stream.channels == highestChannelCount.channels) {
return true
}
} catch (err) { }
return false
})
if (hasStreamAlready.length > 0) {
return {
preset: '',
processFile: false,
note: `File already has ${langTag} stream in ${audioEncoder}, ${highestChannelCount.channels} channels (Highest available) \n`
}
} else {
return {
preset: `,-map 0:v -map 0:${highestChannelCount.index} -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${audioEncoder} -ac ${highestChannelCount.channels}`,
processFile: true,
note: `The required channel count (${channelCount}) is higher than the highest channel available in specified lang tag (${highestChannelCount.channels}). Adding lower channel track. \n`
}
}
}
} }
} else {
console.log("here3");
function attemptMakeStreamUnd(langTag) {
var hasStreamAlready = file.ffProbeData.streams.filter((stream) => {
console.log('No tracks with specified lang tag exist. Checking undefined tracks.') try {
if (
console.log(langTag) stream.codec_type == "audio" &&
stream.codec_name === audioCodec &&
var streamsWithLangTag = file.ffProbeData.streams.filter(stream => { stream.tags.language
.toLowerCase()
try { .includes(langTag.toLowerCase()) &&
if (stream.codec_type == 'audio' && (stream.tags == undefined || stream.tags.language == undefined || stream.tags.language.toLowerCase().includes(langTag))) { stream.channels == highestChannelCount.channels
) {
return true return true;
}
} catch (err) { }
return false
})
if (streamsWithLangTag.length == 0) {
return {
preset: ``,
processFile: false,
note: `Unable to add audio stream in ${langTag}/und with ${channelCount} channels \n`
}
} }
} catch (err) {}
var highestChannelCount = streamsWithLangTag.reduce(getHighest) return false;
});
function getHighest(first, second) {
if (first.channels > second.channels && first) {
return first
} else {
return second
}
}
if (parseInt(highestChannelCount.channels) >= parseInt(channelCount)) {
var hasStreamAlready = file.ffProbeData.streams.filter(stream => {
try {
if (stream.codec_type == 'audio' && stream.codec_name === audioCodec && (stream.tags == undefined || stream.tags.language == undefined || stream.tags.language.toLowerCase().includes(langTag)) && stream.channels == channelCount) {
return true
}
} catch (err) { }
return false
})
if (hasStreamAlready.length > 0) {
return {
preset: '',
processFile: false,
note: `File already has ${langTag} stream in ${audioEncoder}, ${channelCount} channels \n`
}
} else {
return {
preset: `,-map 0:v -map 0:${highestChannelCount.index} -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${audioEncoder} -ac ${channelCount}`,
processFile: true,
note: `The required channel count ${channelCount} is lower than the highest available channel count (${highestChannelCount.channels}). Adding! \n`
}
}
if (hasStreamAlready.length > 0) {
return {
} else { preset: "",
processFile: false,
note: `File already has ${langTag} stream in ${audioEncoder}, ${highestChannelCount.channels} channels (Highest available) \n`,
};
var hasStreamAlready = file.ffProbeData.streams.filter(stream => { } else {
return {
try { preset: `,-map 0:v -map 0:${highestChannelCount.index} -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${audioEncoder} -ac ${highestChannelCount.channels}`,
if (stream.codec_type == 'audio' && stream.codec_name === audioCodec && (stream.tags == undefined || stream.tags.language == undefined || stream.tags.language.toLowerCase().includes(langTag)) && stream.channels == highestChannelCount.channels) { processFile: true,
return true note: `The required channel count (${channelCount}) is higher than the highest channel available in specified lang tag (${highestChannelCount.channels}). Adding lower channel track. \n`,
} };
} catch (err) { }
return false
})
if (hasStreamAlready.length > 0) {
return {
preset: '',
processFile: false,
note: `File already has ${langTag} stream in ${audioEncoder}, ${highestChannelCount.channels} channels (Highest available) \n`
}
} else {
return {
preset: `,-map 0:v -map 0:${highestChannelCount.index} -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${audioEncoder} -ac ${highestChannelCount.channels}`,
processFile: true,
note: `The required channel count (${channelCount}) is higher than the highest channel available in specified lang tag (${highestChannelCount.channels}). Adding lower channel track. \n`
}
}
}
} }
}
}
function attemptMakeStreamUnd(langTag) {
console.log(
"No tracks with specified lang tag exist. Checking undefined tracks."
);
console.log(langTag);
var streamsWithLangTag = file.ffProbeData.streams.filter((stream) => {
try {
if (
stream.codec_type == "audio" &&
(stream.tags == undefined ||
stream.tags.language == undefined ||
stream.tags.language.toLowerCase().includes(langTag))
) {
return true;
}
} catch (err) {}
return false;
});
if (streamsWithLangTag.length == 0) {
return {
preset: ``,
processFile: false,
note: `Unable to add audio stream in ${langTag}/und with ${channelCount} channels \n`,
};
}
var highestChannelCount = streamsWithLangTag.reduce(getHighest);
function getHighest(first, second) {
if (first.channels > second.channels && first) {
return first;
} else {
return second;
}
}
if (parseInt(highestChannelCount.channels) >= parseInt(channelCount)) {
var hasStreamAlready = file.ffProbeData.streams.filter((stream) => {
try {
if (
stream.codec_type == "audio" &&
stream.codec_name === audioCodec &&
(stream.tags == undefined ||
stream.tags.language == undefined ||
stream.tags.language.toLowerCase().includes(langTag)) &&
stream.channels == channelCount
) {
return true;
}
} catch (err) {}
return false;
});
if (hasStreamAlready.length > 0) {
return {
preset: "",
processFile: false,
note: `File already has ${langTag} stream in ${audioEncoder}, ${channelCount} channels \n`,
};
} else {
return {
preset: `,-map 0:v -map 0:${highestChannelCount.index} -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${audioEncoder} -ac ${channelCount}`,
processFile: true,
note: `The required channel count ${channelCount} is lower than the highest available channel count (${highestChannelCount.channels}). Adding! \n`,
};
}
} else {
var hasStreamAlready = file.ffProbeData.streams.filter((stream) => {
try {
if (
stream.codec_type == "audio" &&
stream.codec_name === audioCodec &&
(stream.tags == undefined ||
stream.tags.language == undefined ||
stream.tags.language.toLowerCase().includes(langTag)) &&
stream.channels == highestChannelCount.channels
) {
return true;
}
} catch (err) {}
return false;
});
} catch (err) { if (hasStreamAlready.length > 0) {
return {
return { preset: "",
preset: '',
processFile: false, processFile: false,
note: `library.actions.transcodeAddAudioStream error: ${err} \n` note: `File already has ${langTag} stream in ${audioEncoder}, ${highestChannelCount.channels} channels (Highest available) \n`,
};
} else {
return {
preset: `,-map 0:v -map 0:${highestChannelCount.index} -map 0:a -map 0:s? -map 0:d? -c copy -c:a:0 ${audioEncoder} -ac ${highestChannelCount.channels}`,
processFile: true,
note: `The required channel count (${channelCount}) is higher than the highest channel available in specified lang tag (${highestChannelCount.channels}). Adding lower channel track. \n`,
};
} }
}
} }
} } catch (err) {
return {
preset: "",
processFile: false,
note: `library.actions.transcodeAddAudioStream error: ${err} \n`,
};
}
};

@ -1,365 +1,325 @@
module.exports = function transcodeKeepOneAudioStream(
file,
audioEncoder,
langTag,
channelCount
) {
// response.preset = library.actions.transcodeKeepOneAudioStream(file, 'aac', 'en', 1).preset
//Function required responses
// preset
// processFile
// note
try {
var audioCodec = audioEncoder;
langTag = langTag.toLowerCase();
if (audioEncoder == "dca") {
audioCodec = "dts";
}
if (audioEncoder == "libmp3lame") {
audioCodec = "mp3";
}
module.exports = function transcodeKeepOneAudioStream(file, audioEncoder, langTag, channelCount) { var reqLang = langTag;
// response.preset = library.actions.transcodeKeepOneAudioStream(file, 'aac', 'en', 1).preset
//Function required responses
// preset
// processFile
// note
try { var numberOfAudioStreams = file.ffProbeData.streams.filter(
(stream) => stream.codec_type == "audio"
).length;
var audioCodec = audioEncoder //Step 1: Check if the file already has the required stream codec/langtag/channel count
langTag = langTag.toLowerCase()
if (audioEncoder == 'dca') { var hasStreamAlready = file.ffProbeData.streams.filter((stream) => {
audioCodec = 'dts' try {
if (
stream.codec_type == "audio" &&
stream.codec_name === audioCodec &&
stream.tags.language.toLowerCase().includes(langTag.toLowerCase()) &&
stream.channels == channelCount
) {
return true;
} }
} catch (err) {}
return false;
});
if (numberOfAudioStreams == 1 && hasStreamAlready.length == 1) {
return {
preset: "",
processFile: false,
note: `File already has ${langTag} stream in ${audioEncoder}, ${channelCount} channels. It is the only track! \n`,
};
} else if (hasStreamAlready.length >= 1) {
var audioStreamToKeep = hasStreamAlready[0].index;
var ffmpegCommandInsert = "";
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try {
if (
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" &&
i !== audioStreamToKeep
) {
ffmpegCommandInsert += ` -map -0:${i}`;
}
} catch (err) {}
}
return {
preset: `, -map 0 ${ffmpegCommandInsert} -c copy`,
processFile: true,
note: `File already has ${langTag} stream in ${audioEncoder}, ${channelCount} channels. It is not the only track, removing others. \n`,
};
}
if (audioEncoder == 'libmp3lame') { //Step 2: Check if file has streams with specified lang tag
audioCodec = 'mp3'
}
var reqLang = langTag
var numberOfAudioStreams = file.ffProbeData.streams.filter(stream => stream.codec_type == 'audio').length
//Step 1: Check if the file already has the required stream codec/langtag/channel count
var hasStreamAlready = file.ffProbeData.streams.filter(stream => {
try {
if (stream.codec_type == 'audio' && stream.codec_name === audioCodec && stream.tags.language.toLowerCase().includes(langTag.toLowerCase()) && stream.channels == channelCount) {
return true
}
} catch (err) { } var streamsWithLangTag = file.ffProbeData.streams.filter((stream) => {
try {
if (
stream.codec_type == "audio" &&
stream.tags.language.toLowerCase().includes(langTag)
) {
return true;
}
} catch (err) {}
return false return false;
}) });
if (numberOfAudioStreams == 1 && hasStreamAlready.length == 1) {
console.log("streamsWithLangTag:" + streamsWithLangTag);
if (streamsWithLangTag.length != 0) {
return attemptMakeStreamLang(langTag);
} else {
return attemptMakeStreamUnd("und");
}
return { function attemptMakeStreamLang(langTag) {
preset: '', var streamsWithLangTag = file.ffProbeData.streams.filter((stream) => {
processFile: false, try {
note: `File already has ${langTag} stream in ${audioEncoder}, ${channelCount} channels. It is the only track! \n` if (
stream.codec_type == "audio" &&
stream.tags.language.toLowerCase().includes(langTag)
) {
return true;
}
} catch (err) {}
return false;
});
var highestChannelCount = streamsWithLangTag.reduce(getHighest);
function getHighest(first, second) {
if (first.channels > second.channels && first) {
return first;
} else {
return second;
}
}
if (parseInt(highestChannelCount.channels) >= parseInt(channelCount)) {
var hasStreamAlready = file.ffProbeData.streams.filter((stream) => {
try {
if (
stream.codec_type == "audio" &&
stream.codec_name === audioCodec &&
stream.tags.language
.toLowerCase()
.includes(langTag.toLowerCase()) &&
stream.channels == channelCount
) {
return true;
} }
} catch (err) {}
return false;
});
if (numberOfAudioStreams == 1 && hasStreamAlready.length == 1) {
return {
preset: "",
processFile: false,
note: `The required stream already exists. It is the only audio stream. \n`,
};
} else if (hasStreamAlready.length >= 1) { } else if (hasStreamAlready.length >= 1) {
return {
var audioStreamToKeep = hasStreamAlready[0].index preset: `,-map 0:v -map 0:${hasStreamAlready[0].index} -map 0:s? -map 0:d? -c copy`,
var ffmpegCommandInsert = '' processFile: true,
for (var i = 0; i < file.ffProbeData.streams.length; i++) { note: `The required stream already exists. Removing others. \n`,
};
try { } else {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && i !== audioStreamToKeep) { return {
ffmpegCommandInsert += ` -map -0:${i}` preset: `,-map 0:v -map 0:${highestChannelCount.index} -map 0:s? -map 0:d? -c copy -c:a:0 ${audioEncoder} -ac ${channelCount}`,
processFile: true,
} note: `The required channel count ${channelCount} is lower than the highest available channel count (${highestChannelCount.channels}). Adding it and removing others! \n`,
} catch (err) { } };
}
} else {
console.log("here3");
var hasStreamAlready = file.ffProbeData.streams.filter((stream) => {
try {
if (
stream.codec_type == "audio" &&
stream.codec_name === audioCodec &&
stream.tags.language
.toLowerCase()
.includes(langTag.toLowerCase()) &&
stream.channels == highestChannelCount.channels
) {
return true;
} }
} catch (err) {}
return { return false;
preset: `, -map 0 ${ffmpegCommandInsert} -c copy`, });
processFile: true,
note: `File already has ${langTag} stream in ${audioEncoder}, ${channelCount} channels. It is not the only track, removing others. \n`
}
if (numberOfAudioStreams == 1 && hasStreamAlready.length == 1) {
return {
preset: "",
processFile: false,
note: `The best ${reqLang} stream already exists. It is the only audio stream. \n`,
};
} else if (hasStreamAlready.length >= 1) {
return {
preset: `,-map 0:v -map 0:${hasStreamAlready[0].index} -map 0:s? -map 0:d? -c copy`,
processFile: true,
note: `The best ${reqLang} stream already exists. Removing others. \n`,
};
} else {
return {
preset: `,-map 0:v -map 0:${highestChannelCount.index} -map 0:s? -map 0:d? -c copy -c:a:0 ${audioEncoder} -ac ${highestChannelCount.channels}`,
processFile: true,
note: `The required channel count (${channelCount}) is higher than the highest channel available in specified lang tag (${highestChannelCount.channels}). Adding lower channel track, removing others. \n`,
};
} }
}
}
function attemptMakeStreamUnd(langTag) {
console.log(
"No tracks with specified lang tag exist. Checking undefined tracks."
);
console.log(langTag);
var streamsWithLangTag = file.ffProbeData.streams.filter((stream) => {
try {
if (
stream.codec_type == "audio" &&
(stream.tags == undefined ||
stream.tags.language == undefined ||
stream.tags.language.toLowerCase().includes(langTag))
) {
return true;
}
} catch (err) {}
return false;
});
if (streamsWithLangTag.length == 0) {
return {
preset: ``,
processFile: false,
note: `Unable to add audio stream in ${langTag}/und with ${channelCount} channels \n`,
};
}
//Step 2: Check if file has streams with specified lang tag var highestChannelCount = streamsWithLangTag.reduce(getHighest);
var streamsWithLangTag = file.ffProbeData.streams.filter(stream => {
try {
if (stream.codec_type == 'audio' && stream.tags.language.toLowerCase().includes(langTag)) {
return true
}
} catch (err) { }
return false
})
console.log("streamsWithLangTag:" + streamsWithLangTag)
if (streamsWithLangTag.length != 0) {
return attemptMakeStreamLang(langTag)
function getHighest(first, second) {
if (first.channels > second.channels && first) {
return first;
} else { } else {
return second;
return attemptMakeStreamUnd('und')
} }
}
function attemptMakeStreamLang(langTag) { if (parseInt(highestChannelCount.channels) >= parseInt(channelCount)) {
var hasStreamAlready = file.ffProbeData.streams.filter((stream) => {
try {
var streamsWithLangTag = file.ffProbeData.streams.filter(stream => { if (
try { stream.codec_type == "audio" &&
if (stream.codec_type == 'audio' && stream.tags.language.toLowerCase().includes(langTag)) { stream.codec_name === audioCodec &&
(stream.tags == undefined ||
return true stream.tags.language == undefined ||
} stream.tags.language.toLowerCase().includes(langTag)) &&
stream.channels == channelCount
} catch (err) { } ) {
return true;
return false
})
var highestChannelCount = streamsWithLangTag.reduce(getHighest)
function getHighest(first, second) {
if (first.channels > second.channels && first) {
return first
} else {
return second
}
} }
} catch (err) {}
return false;
});
if (numberOfAudioStreams == 1 && hasStreamAlready.length == 1) {
if (parseInt(highestChannelCount.channels) >= parseInt(channelCount)) { return {
preset: "",
var hasStreamAlready = file.ffProbeData.streams.filter(stream => { processFile: false,
note: `No ${reqLang} streams. The required und stream already exists. It is the only audio stream. \n`,
try { };
if (stream.codec_type == 'audio' && stream.codec_name === audioCodec && stream.tags.language.toLowerCase().includes(langTag.toLowerCase()) && stream.channels == channelCount) { } else if (hasStreamAlready.length >= 1) {
return true return {
} preset: `,-map 0:v -map 0:${hasStreamAlready[0].index} -map 0:s? -map 0:d? -c copy`,
processFile: true,
} catch (err) { } note: `No ${reqLang} streams. The required und stream already exists. Removing others. \n`,
};
return false } else {
}) return {
preset: `,-map 0:v -map 0:${highestChannelCount.index} -map 0:s? -map 0:d? -c copy -c:a:0 ${audioEncoder} -ac ${channelCount}`,
if (numberOfAudioStreams == 1 && hasStreamAlready.length == 1) { processFile: true,
note: `No ${reqLang} streams. The required channel count ${channelCount} is lower than the highest available channel count (${highestChannelCount.channels}).Adding it and removing others! \n`,
return { };
preset: '',
processFile: false,
note: `The required stream already exists. It is the only audio stream. \n`
}
} else if (hasStreamAlready.length >= 1) {
return {
preset: `,-map 0:v -map 0:${hasStreamAlready[0].index} -map 0:s? -map 0:d? -c copy`,
processFile: true,
note: `The required stream already exists. Removing others. \n`
}
} else {
return {
preset: `,-map 0:v -map 0:${highestChannelCount.index} -map 0:s? -map 0:d? -c copy -c:a:0 ${audioEncoder} -ac ${channelCount}`,
processFile: true,
note: `The required channel count ${channelCount} is lower than the highest available channel count (${highestChannelCount.channels}). Adding it and removing others! \n`
}
}
} else {
console.log('here3')
var hasStreamAlready = file.ffProbeData.streams.filter(stream => {
try {
if (stream.codec_type == 'audio' && stream.codec_name === audioCodec && stream.tags.language.toLowerCase().includes(langTag.toLowerCase()) && stream.channels == highestChannelCount.channels) {
return true
}
} catch (err) { }
return false
})
if (numberOfAudioStreams == 1 && hasStreamAlready.length == 1) {
return {
preset: '',
processFile: false,
note: `The best ${reqLang} stream already exists. It is the only audio stream. \n`
}
} else if (hasStreamAlready.length >= 1) {
return {
preset: `,-map 0:v -map 0:${hasStreamAlready[0].index} -map 0:s? -map 0:d? -c copy`,
processFile: true,
note: `The best ${reqLang} stream already exists. Removing others. \n`
}
} else {
return {
preset: `,-map 0:v -map 0:${highestChannelCount.index} -map 0:s? -map 0:d? -c copy -c:a:0 ${audioEncoder} -ac ${highestChannelCount.channels}`,
processFile: true,
note: `The required channel count (${channelCount}) is higher than the highest channel available in specified lang tag (${highestChannelCount.channels}). Adding lower channel track, removing others. \n`
}
}
}
} }
} else {
var hasStreamAlready = file.ffProbeData.streams.filter((stream) => {
function attemptMakeStreamUnd(langTag) { try {
if (
console.log('No tracks with specified lang tag exist. Checking undefined tracks.') stream.codec_type == "audio" &&
stream.codec_name === audioCodec &&
console.log(langTag) (stream.tags == undefined ||
stream.tags.language == undefined ||
var streamsWithLangTag = file.ffProbeData.streams.filter(stream => { stream.tags.language.toLowerCase().includes(langTag)) &&
stream.channels == highestChannelCount.channels
try { ) {
if (stream.codec_type == 'audio' && (stream.tags == undefined || stream.tags.language == undefined || stream.tags.language.toLowerCase().includes(langTag))) { return true;
return true
}
} catch (err) { }
return false
})
if (streamsWithLangTag.length == 0) {
return {
preset: ``,
processFile: false,
note: `Unable to add audio stream in ${langTag}/und with ${channelCount} channels \n`
}
}
var highestChannelCount = streamsWithLangTag.reduce(getHighest)
function getHighest(first, second) {
if (first.channels > second.channels && first) {
return first
} else {
return second
}
}
if (parseInt(highestChannelCount.channels) >= parseInt(channelCount)) {
var hasStreamAlready = file.ffProbeData.streams.filter(stream => {
try {
if (stream.codec_type == 'audio' && stream.codec_name === audioCodec && (stream.tags == undefined || stream.tags.language == undefined || stream.tags.language.toLowerCase().includes(langTag)) && stream.channels == channelCount) {
return true
}
} catch (err) { }
return false
})
if (numberOfAudioStreams == 1 && hasStreamAlready.length == 1) {
return {
preset: '',
processFile: false,
note: `No ${reqLang} streams. The required und stream already exists. It is the only audio stream. \n`
}
} else if (hasStreamAlready.length >= 1) {
return {
preset: `,-map 0:v -map 0:${hasStreamAlready[0].index} -map 0:s? -map 0:d? -c copy`,
processFile: true,
note: `No ${reqLang} streams. The required und stream already exists. Removing others. \n`
}
} else {
return {
preset: `,-map 0:v -map 0:${highestChannelCount.index} -map 0:s? -map 0:d? -c copy -c:a:0 ${audioEncoder} -ac ${channelCount}`,
processFile: true,
note: `No ${reqLang} streams. The required channel count ${channelCount} is lower than the highest available channel count (${highestChannelCount.channels}).Adding it and removing others! \n`
}
}
} else {
var hasStreamAlready = file.ffProbeData.streams.filter(stream => {
try {
if (stream.codec_type == 'audio' && stream.codec_name === audioCodec && (stream.tags == undefined || stream.tags.language == undefined || stream.tags.language.toLowerCase().includes(langTag)) && stream.channels == highestChannelCount.channels) {
return true
}
} catch (err) { }
return false
})
if (numberOfAudioStreams == 1 && hasStreamAlready.length == 1) {
return {
preset: '',
processFile: false,
note: `No ${reqLang} streams. The best und stream already exists. It is the only audio stream. \n`
}
} else if (hasStreamAlready.length >= 1) {
return {
preset: `,-map 0:v -map 0:${hasStreamAlready[0].index} -map 0:s? -map 0:d? -c copy`,
processFile: true,
note: `No ${reqLang} streams. The best stream already exists. Removing others. \n`
}
} else {
return {
preset: `,-map 0:v -map 0:${highestChannelCount.index} -map 0:s? -map 0:d? -c copy -c:a:0 ${audioEncoder} -ac ${highestChannelCount.channels}`,
processFile: true,
note: `No ${reqLang} streams. The required channel count (${channelCount}) is higher than the highest channel available in specified lang tag (${highestChannelCount.channels}). Adding lower channel track, removing others. \n`
}
}
} }
} } catch (err) {}
return false;
});
} catch (err) { if (numberOfAudioStreams == 1 && hasStreamAlready.length == 1) {
return {
return { preset: "",
preset: '',
processFile: false, processFile: false,
note: `library.actions.transcodeKeepOneAudioStream error: ${err} \n` note: `No ${reqLang} streams. The best und stream already exists. It is the only audio stream. \n`,
};
} else if (hasStreamAlready.length >= 1) {
return {
preset: `,-map 0:v -map 0:${hasStreamAlready[0].index} -map 0:s? -map 0:d? -c copy`,
processFile: true,
note: `No ${reqLang} streams. The best stream already exists. Removing others. \n`,
};
} else {
return {
preset: `,-map 0:v -map 0:${highestChannelCount.index} -map 0:s? -map 0:d? -c copy -c:a:0 ${audioEncoder} -ac ${highestChannelCount.channels}`,
processFile: true,
note: `No ${reqLang} streams. The required channel count (${channelCount}) is higher than the highest channel available in specified lang tag (${highestChannelCount.channels}). Adding lower channel track, removing others. \n`,
};
} }
}
} }
} } catch (err) {
return {
preset: "",
processFile: false,
note: `library.actions.transcodeKeepOneAudioStream error: ${err} \n`,
};
}
};

@ -1,77 +1,59 @@
module.exports = function transcodeStandardiseAudioCodecs(file, audioEncoder) { module.exports = function transcodeStandardiseAudioCodecs(file, audioEncoder) {
//Function required responses
// preset
// processFile
// note
try {
var audioIdx = -1;
var hasNonSpecifiedAudioCodecStream = false;
var ffmpegCommandInsert = "";
var audioCodec = audioEncoder;
if (audioEncoder == "dca") {
audioCodec = "dts";
}
if (audioEncoder == "libmp3lame") {
audioCodec = "mp3";
}
//Function required responses for (var i = 0; i < file.ffProbeData.streams.length; i++) {
// preset try {
// processFile if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
// note audioIdx++;
try {
var audioIdx = -1
var hasNonSpecifiedAudioCodecStream = false
var ffmpegCommandInsert = ''
var audioCodec = audioEncoder
if (audioEncoder == 'dca') {
audioCodec = 'dts'
}
if (audioEncoder == 'libmp3lame') {
audioCodec = 'mp3'
}
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
audioIdx++
}
} catch (err) { }
try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].codec_name != audioCodec) {
ffmpegCommandInsert += ` -c:a:${audioIdx} ${audioEncoder}`
hasNonSpecifiedAudioCodecStream = true
}
} catch (err) { }
}
if (hasNonSpecifiedAudioCodecStream === true) {
return {
preset: `,-map 0:v -map 0:a -map 0:s? -map 0:d? -c copy ${ffmpegCommandInsert}`,
processFile: true,
note: `File has audio streams which aren't in ${audioCodec} \n`
}
}
return {
preset: '',
processFile: false,
note: `File does not have any audio streams which aren't in ${audioCodec} \n`
} }
} catch (err) {}
try {
} catch (err) { if (
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" &&
return { file.ffProbeData.streams[i].codec_name != audioCodec
preset: '', ) {
processFile: false, ffmpegCommandInsert += ` -c:a:${audioIdx} ${audioEncoder}`;
note: `library.actions.transcodeStandardiseAudioCodecs error: ${err} \n` hasNonSpecifiedAudioCodecStream = true;
} }
} catch (err) {}
}
if (hasNonSpecifiedAudioCodecStream === true) {
return {
preset: `,-map 0:v -map 0:a -map 0:s? -map 0:d? -c copy ${ffmpegCommandInsert}`,
processFile: true,
note: `File has audio streams which aren't in ${audioCodec} \n`,
};
} }
}
return {
preset: "",
processFile: false,
note: `File does not have any audio streams which aren't in ${audioCodec} \n`,
};
} catch (err) {
return {
preset: "",
processFile: false,
note: `library.actions.transcodeStandardiseAudioCodecs error: ${err} \n`,
};
}
};

@ -1,40 +1,29 @@
function filterByAge(file, ageCutOff_Seconds) { function filterByAge(file, ageCutOff_Seconds) {
try {
try { var timeNow = new Date();
var dateCreated = new Date(file.statSync.birthtime);
var timeNow = new Date() var fileAge = Math.round((timeNow - dateCreated) / 1000);
var dateCreated = new Date(file.statSync.birthtime)
var fileAge = Math.round((timeNow - dateCreated) / 1000) if (fileAge > ageCutOff_Seconds) {
var response = {
outcome: false,
if (fileAge > ageCutOff_Seconds) { note: `☒File creation date is older than specified requirement. \n`,
};
var response = { return response;
outcome: false, } else {
note: `☒File creation date is older than specified requirement. \n` var response = {
} outcome: true,
return response note: `☑File creation date is within specified requirement. \n`,
};
} else { return response;
var response = {
outcome: true,
note: `☑File creation date is within specified requirement. \n`
}
return response
}
} catch (err) {
var response = {
outcome: false,
note: `library.filters.filterByAge error: ${err} \n`
}
return response
} }
} catch (err) {
var response = {
outcome: false,
note: `library.filters.filterByAge error: ${err} \n`,
};
return response;
}
} }
module.exports = filterByAge;
module.exports = filterByAge

@ -1,82 +1,60 @@
function filterByCodec(file, mode, codecs) { function filterByCodec(file, mode, codecs) {
try {
// console.log(file,mode,codecs)
var allCodecs = file.ffProbeData.streams.map((row) => row.codec_name);
try { var included = false;
// console.log(file,mode,codecs)
var allCodecs = file.ffProbeData.streams.map(row => row.codec_name)
var included = false
for (var i = 0; i < allCodecs.length; i++) {
if (codecs.toLowerCase().includes(allCodecs[i])) {
included = true
}
}
if (mode === 'include') {
if (included) {
var response = {
outcome: true,
note: `☑Codec included \n`
}
return response
} else {
var response = {
outcome: false,
note: `☒Codec excluded \n`
}
return response
}
} else if (mode === 'exclude') { for (var i = 0; i < allCodecs.length; i++) {
if (codecs.toLowerCase().includes(allCodecs[i])) {
if (included) { included = true;
}
var response = { }
outcome: false,
note: `☒Codec excluded \n`
}
return response
} else {
var response = {
outcome: true,
note: `☑Codec not excluded \n`
}
return response
}
}
if (mode === "include") {
if (included) {
var response = { var response = {
outcome: false, outcome: true,
note: `library.filters.filterByCodec error: ${err} \n` note: `☑Codec included \n`,
} };
return response return response;
} else {
} catch (err) {
console.log(err)
var response = { var response = {
outcome: false, outcome: false,
note: `Filter error hello! ${err}\n` note: `☒Codec excluded \n`,
} };
return response return response;
}
} else if (mode === "exclude") {
if (included) {
var response = {
outcome: false,
note: `☒Codec excluded \n`,
};
return response;
} else {
var response = {
outcome: true,
note: `☑Codec not excluded \n`,
};
return response;
}
} }
var response = {
outcome: false,
note: `library.filters.filterByCodec error: ${err} \n`,
};
return response;
} catch (err) {
console.log(err);
var response = {
outcome: false,
note: `Filter error hello! ${err}\n`,
};
return response;
}
} }
module.exports = filterByCodec;
module.exports = filterByCodec

@ -1,34 +1,25 @@
function filterByMedium(file, medium) { function filterByMedium(file, medium) {
try {
try { if (file.fileMedium !== medium) {
var response = {
if (file.fileMedium !== medium) { outcome: false,
note: `☒File is not ${medium} \n`,
var response = { };
outcome: false, return response;
note: `☒File is not ${medium} \n` } else {
} var response = {
return response outcome: true,
note: `☑File is ${medium} \n`,
} else { };
return response;
var response = {
outcome: true,
note: `☑File is ${medium} \n`
}
return response
}
} catch (err) {
var response = {
outcome: false,
note: `library.filters.filterByMedium error: ${err} \n`
}
return response
} }
} catch (err) {
var response = {
outcome: false,
note: `library.filters.filterByMedium error: ${err} \n`,
};
return response;
}
} }
module.exports = filterByMedium;
module.exports = filterByMedium

@ -1,58 +1,45 @@
function filterByResolution(file, mode, resolution) { function filterByResolution(file, mode, resolution) {
try {
try { if (mode === "exclude") {
if (
if (mode === 'exclude') { resolution.toLowerCase().includes(file.video_resolution.toLowerCase())
) {
if (resolution.toLowerCase().includes(file.video_resolution.toLowerCase())) { var response = {
outcome: false,
var response = { note: `☒File is in excluded resolution. \n`,
outcome: false, };
note: `☒File is in excluded resolution. \n` return response;
} } else {
return response var response = {
outcome: true,
} else { note: `☑File is not in excluded resolution. \n`,
};
var response = { return response;
outcome: true, }
note: `☑File is not in excluded resolution. \n` } else if (mode === "include") {
} if (
return response resolution.toLowerCase().includes(file.video_resolution.toLowerCase())
) {
}
} else if (mode === 'include') {
if (resolution.toLowerCase().includes(file.video_resolution.toLowerCase())) {
var response = {
outcome: true,
note: `☑File is in included resolution. \n`
}
return response
} else {
var response = {
outcome: false,
note: `☒File is not in included resolution. \n`
}
return response
}
}
} catch (err) {
var response = { var response = {
outcome: false, outcome: true,
note: `library.filters.filterByResolution error: ${err} \n` note: `☑File is in included resolution. \n`,
} };
return response return response;
} else {
var response = {
outcome: false,
note: `☒File is not in included resolution. \n`,
};
return response;
}
} }
} catch (err) {
var response = {
outcome: false,
note: `library.filters.filterByResolution error: ${err} \n`,
};
return response;
}
} }
module.exports = filterByResolution;
module.exports = filterByResolution

@ -1,34 +1,28 @@
function filterBySize(file, lowerBound, upperBound) { function filterBySize(file, lowerBound, upperBound) {
try {
try { if (
file.file_size / 1000 >= lowerBound &&
if (file.file_size / 1000 >= lowerBound && file.file_size / 1000 <= upperBound) { file.file_size / 1000 <= upperBound
) {
var response = { var response = {
outcome: true, outcome: true,
note: `☑File size is within filter limits. \n` note: `☑File size is within filter limits. \n`,
} };
return response return response;
} else {
} else { var response = {
outcome: false,
var response = { note: `☒File size is not within filter limits. \n`,
outcome: false, };
note: `☒File size is not within filter limits. \n` return response;
}
return response
}
} catch (err) {
var response = {
outcome: false,
note: `library.filters.filterBySize error: ${err} \n`
}
return response
} }
} catch (err) {
var response = {
outcome: false,
note: `library.filters.filterBySize error: ${err} \n`,
};
return response;
}
} }
module.exports = filterBySize module.exports = filterBySize;

Loading…
Cancel
Save