Migz Plugins

1. Made changes to all plugins following lint testing. There are still various warnings/errors but my very limited knowledge of javascript means I just don't understand what the errors mean. Or in some cases I don't understand how to split the variable across several lines to confirm to the line limits.
I did manage to get it from
952 problems (943 errors, 9 warnings)
down to
37 problems (28 errors, 9 warnings)

2. Fix Flawed logic in FFMPEG plugins which would cause remux conditions to never trigger. Was checking if file was HEVC & VP9 which is impossible as they're both codecs.

3. Fixed a bug with CleanTitle where plugin would fail if a stream in the file didn't have a title.

4. Modify CleanSubtitle plugin to not remove sdh subtitles.

5. Include new plugin to just perform remuxes. Mainly aimed at remuxing to mkv or mp4.
make-only-subtitle-default
Migz93 5 years ago
parent e9370ffe7c
commit 864cf41f1d

@ -1,253 +1,286 @@
/* eslint-disable */ /* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
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 This plugin will skip any files that are in the VP9 codec as these are already at a comparable compression level to H265. \n\n`, Description: `Files not in H265 will be transcoded into H265 using Nvidia GPU with ffmpeg.
Version: "2.8", \\n Settings are dependant on file bitrate
Link: \\n Working by the logic that H265 can support the same ammount of data at half the bitrate of H264.
"https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz1FFMPEG.js", \\n NVDEC & NVENC compatable GPU required.
Tags: "pre-processing,ffmpeg,video only,nvenc h265,configurable", \\n This plugin will skip any files that are in the VP9 codec. \n\n`,
Inputs: [ Version: '3.0',
{ Link: 'https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz1FFMPEG.js',
name: "container", Tags: 'pre-processing,ffmpeg,video only,nvenc h265,configurable',
tooltip: `Specify output container of file, ensure that all stream types you may have are supported by your chosen container. mkv is recommended. Inputs: [{
\\nExample:\\n name: 'container',
mkv tooltip: `Specify output container of file
\\n Ensure that all stream types you may have are supported by your chosen container.
\\nExample:\\n \\n mkv is recommended.
mp4`, \\nExample:\\n
}, mkv
{
name: "bitrate_cutoff", \\nExample:\\n
tooltip: `Specify bitrate cutoff, files with a current bitrate lower then this will not be transcoded. Rate is in kbps. Leave empty to disable. mp4`,
\\nExample:\\n },
6000 {
name: 'bitrate_cutoff',
\\nExample:\\n tooltip: `Specify bitrate cutoff, files with a current bitrate lower then this will not be transcoded.
4000`, \\n Rate is in kbps.
}, \\n Leave empty to disable.
{ \\nExample:\\n
name: "enable_10bit", 6000
tooltip: `Specify if output file should be 10bit. Default is false.
\\nExample:\\n \\nExample:\\n
true 4000`,
},
\\nExample:\\n {
false`, name: 'enable_10bit',
}, tooltip: `Specify if output file should be 10bit. Default is false.
{ \\nExample:\\n
name: "enable_bframes", true
tooltip: `Specify if b frames should be used. Using B frames should decrease file sizes but are only supported on newer GPUs. Default is false.
\\nExample:\\n \\nExample:\\n
true false`,
},
\\nExample:\\n {
false`, name: 'enable_bframes',
}, tooltip: `Specify if b frames should be used.
{ \\n Using B frames should decrease file sizes but are only supported on newer GPUs.
name: "force_conform", \\n Default is false.
tooltip: `Make the file conform to output containers requirements. \\nExample:\\n
true
\\nExample:\\n
false`,
},
{
name: 'force_conform',
tooltip: `Make the file conform to output containers requirements.
\\n Drop hdmv_pgs_subtitle/eia_608/subrip/timed_id3 for MP4. \\n Drop hdmv_pgs_subtitle/eia_608/subrip/timed_id3 for MP4.
\\n Drop data streams/mov_text/eia_608/timed_id3 for MKV. \\n Drop data streams/mov_text/eia_608/timed_id3 for MKV.
\\n Default is false. \\n 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 = { const response = {
processFile: false, processFile: false,
preset: "", preset: '',
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: true, reQueueAfter: true,
infoLog: "", infoLog: '',
}; };
let duration = '';
// 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 += response.infoLog += 'Plugin has not been configured, please configure required options. Skipping this plugin. \n';
"☒Container has not been configured within plugin settings, please configure required options. Skipping this plugin. \n";
response.processFile = false; response.processFile = false;
return response; return response;
} else {
response.container = "." + inputs.container;
} }
response.container = `.${inputs.container}`;
// 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;
} }
// 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. // Check if duration info is filled, if so times it by 0.0166667 to get time in minutes.
if (typeof file.meta.Duration != "undefined") { // If not filled then get duration of stream 0 and do the same.
var duration = file.meta.Duration * 0.0166667; if (typeof file.meta.Duration !== 'undefined') {
duration = file.meta.Duration * 0.0166667;
} else { } else {
var duration = file.ffProbeData.streams[0].duration * 0.0166667; duration = file.ffProbeData.streams[0].duration * 0.0166667;
} }
// Set up required variables. // Set up required variables.
var videoIdx = 0; let videoIdx = 0;
var CPU10 = false; let CPU10 = false;
var extraArguments = ""; let extraArguments = '';
var bitrateSettings = ""; let 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/ // Work out currentBitrate using "Bitrate = file size / (number of minutes * .0075)"
var currentBitrate = ~~(file.file_size / (duration * 0.0075)); // Used from here https://blog.frame.io/2017/03/06/calculate-video-bitrates/
// 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. const currentBitrate = ~~(file.file_size / (duration * 0.0075));
var targetBitrate = ~~(file.file_size / (duration * 0.0075) / 2); // 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.
const targetBitrate = ~~(file.file_size / (duration * 0.0075) / 2);
// Allow some leeway under and over the targetBitrate. // Allow some leeway under and over the targetBitrate.
var minimumBitrate = ~~(targetBitrate * 0.7); const minimumBitrate = ~~(targetBitrate * 0.7);
var maximumBitrate = ~~(targetBitrate * 1.3); const 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 comes out as 0 then something has gone wrong and bitrates could not be calculated.
if (targetBitrate == "0") { // Cancel plugin completely.
if (targetBitrate === '0') {
response.processFile = false; response.processFile = false;
response.infoLog += response.infoLog += 'Target bitrate could not be calculated. Skipping this plugin. \n';
"☒Target bitrate could not be calculated. Skipping this plugin. \n";
return response; return response;
} }
// Check if inputs.bitrate cutoff has something entered (Entered means user actually wants something to happen, empty would disable this). // Check if inputs.bitrate cutoff has something entered.
if (inputs.bitrate_cutoff != "") { // (Entered means user actually wants something to happen, empty would disable this).
// Checks if currentBitrate is below inputs.bitrate_cutoff, if so then cancel plugin without touching original files. 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) { if (currentBitrate <= inputs.bitrate_cutoff) {
response.processFile = false; response.processFile = false;
response.infoLog += `☑Current bitrate is below configured bitrate cutoff of ${inputs.bitrate_cutoff}. Nothing to do, cancelling plugin. \n`; response.infoLog += `Current bitrate is below set cutoff of ${inputs.bitrate_cutoff}. Cancelling plugin. \n`;
return response; return response;
} }
} }
// Check if force_conform option is checked. If so then check streams and add any extra parameters required to make file conform with output format. // Check if force_conform option is checked.
if (inputs.force_conform == "true") { // If so then check streams and add any extra parameters required to make file conform with output format.
if (inputs.container.toLowerCase() == "mkv") { if (inputs.force_conform === 'true') {
extraArguments += `-map -0:d `; if (inputs.container.toLowerCase() === 'mkv') {
for (var i = 0; i < file.ffProbeData.streams.length; i++) extraArguments += '-map -0:d ';
try { for (let i = 0; i < file.ffProbeData.streams.length; i++) {
if ( try {
file.ffProbeData.streams[i].codec_name if (
.toLowerCase() == "mov_text" || file.ffProbeData.streams[i].codec_name
file.ffProbeData.streams[i].codec_name .toLowerCase() === 'mov_text'
.toLowerCase() == "eia_608" || || file.ffProbeData.streams[i].codec_name
file.ffProbeData.streams[i].codec_name .toLowerCase() === 'eia_608'
.toLowerCase() == "timed_id3" || file.ffProbeData.streams[i].codec_name
) { .toLowerCase() === 'timed_id3'
extraArguments += `-map -0:${i} `; ) {
} extraArguments += `-map -0:${i} `;
} catch (err) {} }
} catch (err) {
// Error
}
}
} }
if (inputs.container.toLowerCase() == "mp4") { if (inputs.container.toLowerCase() === 'mp4') {
for (var i = 0; i < file.ffProbeData.streams.length; i++) for (let i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
if ( if (
file.ffProbeData.streams[i].codec_name file.ffProbeData.streams[i].codec_name
.toLowerCase() == "hdmv_pgs_subtitle" || .toLowerCase() === 'hdmv_pgs_subtitle'
file.ffProbeData.streams[i].codec_name || file.ffProbeData.streams[i].codec_name
.toLowerCase() == "eia_608" || .toLowerCase() === 'eia_608'
file.ffProbeData.streams[i].codec_name || file.ffProbeData.streams[i].codec_name
.toLowerCase() == "subrip" || .toLowerCase() === 'subrip'
file.ffProbeData.streams[i].codec_name || file.ffProbeData.streams[i].codec_name
.toLowerCase() == "timed_id3" .toLowerCase() === 'timed_id3'
) { ) {
extraArguments += `-map -0:${i} `; extraArguments += `-map -0:${i} `;
} }
} catch (err) {} } catch (err) {
// Error
}
}
} }
} }
// Check if 10bit variable is true. // Check if 10bit variable is true.
if (inputs.enable_10bit == "true") { if (inputs.enable_10bit === 'true') {
// If set to true then add 10bit argument // If set to true then add 10bit argument
extraArguments += `-pix_fmt p010le `; extraArguments += '-pix_fmt p010le ';
} }
// Check if b frame variable is true. // Check if b frame variable is true.
if (inputs.enable_bframes == "true") { if (inputs.enable_bframes === 'true') {
// If set to true then add b frames argument // If set to true then add b frames argument
extraArguments += `-bf 5 `; extraArguments += '-bf 5 ';
} }
// 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 (let i = 0; i < file.ffProbeData.streams.length; i++) {
// Check if stream is a video. // Check if stream is a video.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'video') {
// Check if codec of stream is mjpeg/png, if so then remove this "video" stream. mjpeg/png are usually embedded pictures that can cause havoc with plugins. // Check if codec of stream is mjpeg/png, if so then remove this "video" stream.
if (file.ffProbeData.streams[i].codec_name == "mjpeg" || file.ffProbeData.streams[i].codec_name == "png") { // mjpeg/png are usually embedded pictures that can cause havoc with plugins.
if (file.ffProbeData.streams[i].codec_name === 'mjpeg' || file.ffProbeData.streams[i].codec_name === 'png') {
extraArguments += `-map -v:${videoIdx} `; extraArguments += `-map -v:${videoIdx} `;
} }
// Check if codec of stream is hevc or vp9 AND check if file.container matches inputs.container. If so nothing for plugin to do. // Check if codec of stream is hevc or vp9 AND check if file.container matches inputs.container.
// If so nothing for plugin to do.
if ( if (
file.ffProbeData.streams[i].codec_name == "hevc" || file.ffProbeData.streams[i].codec_name == "vp9" && (
file.container == inputs.container file.ffProbeData.streams[i].codec_name === 'hevc'
|| file.ffProbeData.streams[i].codec_name === 'vp9'
)
&& file.container === inputs.container
) { ) {
response.processFile = false; response.processFile = false;
response.infoLog += `☑File is already hevc or vp9 & in ${inputs.container}. \n`; response.infoLog += `File is already hevc or vp9 & in ${inputs.container}. \n`;
return response; return response;
} }
// Check if codec of stream is hevc or vp9 AND check if file.container does NOT match inputs.container. If so remux file. // Check if codec of stream is hevc or vp9
// AND check if file.container does NOT match inputs.container.
// If so remux file.
if ( if (
file.ffProbeData.streams[i].codec_name == "hevc" || file.ffProbeData.streams[i].codec_name == "vp9" && (
file.container != "${inputs.container}" file.ffProbeData.streams[i].codec_name === 'hevc'
|| file.ffProbeData.streams[i].codec_name === 'vp9'
)
&& file.container !== inputs.container
) { ) {
response.infoLog += `☒File is hevc or vp9 but is not in ${inputs.container} container. Remuxing. \n`; response.infoLog += `File is hevc or vp9 but is not in ${inputs.container} container. Remuxing. \n`;
response.preset = `, -map 0 -c copy ${extraArguments}`; response.preset = `, -map 0 -c copy ${extraArguments}`;
response.processFile = true; response.processFile = true;
return response; return response;
} }
// Check if video stream is HDR or 10bit // Check if video stream is HDR or 10bit
if (file.ffProbeData.streams[i].profile == "High 10" || file.ffProbeData.streams[i].bits_per_raw_sample == "10" ) { if (
CPU10 = true file.ffProbeData.streams[i].profile === 'High 10'
|| file.ffProbeData.streams[i].bits_per_raw_sample === '10'
) {
CPU10 = true;
} }
// Increment videoIdx. // Increment videoIdx.
videoIdx++; videoIdx += 1;
} }
} }
// Set bitrateSettings variable using bitrate information calulcated earlier. // Set bitrateSettings variable using bitrate information calulcated earlier.
bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k -maxrate ${maximumBitrate}k -bufsize ${currentBitrate}k`; bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k -maxrate ${maximumBitrate}k -bufsize ${currentBitrate}k`;
// Print to infoLog information around file & bitrate settings. // Print to infoLog information around file & bitrate settings.
response.infoLog += `Container for output selected as ${ response.infoLog += `Container for output selected as ${inputs.container}. \n`;
inputs.container response.infoLog += `Current bitrate = ${currentBitrate} \n`;
}. \n Current bitrate = ${~~( response.infoLog += 'Bitrate settings: \n';
file.file_size / response.infoLog += `Target = ${targetBitrate} \n`;
(duration * 0.0075) response.infoLog += `Minimum = ${minimumBitrate} \n`;
)} \n Bitrate settings: \nTarget = ${targetBitrate} \nMinimum = ${minimumBitrate} \nMaximum = ${maximumBitrate} \n`; response.infoLog += `Maximum = ${maximumBitrate} \n`;
// Codec will be checked so it can be transcoded correctly // Codec will be checked so it can be transcoded correctly
if (file.video_codec_name == "h263") { if (file.video_codec_name === 'h263') {
response.preset = `-c:v h263_cuvid`; response.preset = '-c:v h263_cuvid';
} else if (file.video_codec_name == "h264") { } else if (file.video_codec_name === 'h264') {
if (CPU10 == false) { if (CPU10 === false) {
response.preset = `-c:v h264_cuvid`; response.preset = '-c:v h264_cuvid';
} }
} else if (file.video_codec_name == "mjpeg") { } else if (file.video_codec_name === 'mjpeg') {
response.preset = `c:v mjpeg_cuvid`; response.preset = 'c:v mjpeg_cuvid';
} else if (file.video_codec_name == "mpeg1") { } else if (file.video_codec_name === 'mpeg1') {
response.preset = `-c:v mpeg1_cuvid`; response.preset = '-c:v mpeg1_cuvid';
} else if (file.video_codec_name == "mpeg2") { } else if (file.video_codec_name === 'mpeg2') {
response.preset = `-c:v mpeg2_cuvid`; response.preset = '-c:v mpeg2_cuvid';
} else if (file.video_codec_name == "vc1") { } else if (file.video_codec_name === 'vc1') {
response.preset = `-c:v vc1_cuvid`; response.preset = '-c:v vc1_cuvid';
} else if (file.video_codec_name == "vp8") { } else if (file.video_codec_name === 'vp8') {
response.preset = `-c:v vp8_cuvid`; response.preset = '-c:v vp8_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 9999 ${extraArguments}`; 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 9999 ${extraArguments}`;
response.processFile = true; response.processFile = true;
response.infoLog += `☒File is not hevc or vp9. Transcoding. \n`; response.infoLog += 'File is not hevc or vp9. Transcoding. \n';
return response; return response;
} }
module.exports.details = details; module.exports.details = details;

@ -1,212 +1,235 @@
/* eslint-disable */ /* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
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 This plugin will skip any files that are in the VP9 codec as these are already at a comparable compression level to H265.\n\n`, Description: `Files not in H265 will be transcoded into H265 using Nvidia GPU with ffmpeg.
Version: "1.7", \\n Settings are dependant on file bitrate
Link: \\n Working by the logic that H265 can support the same ammount of data at half the bitrate of H264.
"https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz1FFMPEG_CPU.js", \\n This plugin will skip any files that are in the VP9 codec. \n\n`,
Tags: "pre-processing,ffmpeg,video only,configurable,h265", Version: '1.9',
Inputs: [ Link: 'https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz1FFMPEG_CPU.js',
{ 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',
\\nExample:\\n tooltip: `Specify output container of file.
mkv \\n Ensure that all stream types you may have are supported by your chosen container.
\\n mkv is recommended.
\\nExample:\\n \\nExample:\\n
mp4`, mkv
},
{ \\nExample:\\n
name: "bitrate_cutoff", mp4`,
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 {
6000 name: 'bitrate_cutoff',
tooltip: `Specify bitrate cutoff, files with a current bitrate lower then this will not be transcoded.
\\nExample:\\n \\n Rate is in kbps.
4000`, \\n Leave empty to disable.
}, \\nExample:\\n
{ 6000
name: "enable_10bit",
tooltip: `Specify if output file should be 10bit. Default is false. \\nExample:\\n
\\nExample:\\n 4000`,
true },
{
\\nExample:\\n name: 'enable_10bit',
false`, tooltip: `Specify if output file should be 10bit. Default is false.
}, \\nExample:\\n
{ true
name: "force_conform",
tooltip: `Make the file conform to output containers requirements. \\nExample:\\n
false`,
},
{
name: 'force_conform',
tooltip: `Make the file conform to output containers requirements.
\\n Drop hdmv_pgs_subtitle/eia_608/subrip/timed_id3 for MP4. \\n Drop hdmv_pgs_subtitle/eia_608/subrip/timed_id3 for MP4.
\\n Drop data streams/mov_text/eia_608/timed_id3 for MKV. \\n Drop data streams/mov_text/eia_608/timed_id3 for MKV.
\\n Default is false. \\n 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 = { const response = {
processFile: false, processFile: false,
preset: "", preset: '',
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: true, FFmpegMode: true,
reQueueAfter: true, reQueueAfter: true,
infoLog: "", infoLog: '',
}; };
let duration = '';
// 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 || inputs.container == "") { if (inputs.container === '') {
response.infoLog += response.infoLog += 'Plugin has not been configured, please configure required options. Skipping this plugin. \n';
"☒Container has not been configured within plugin settings, please configure required options. Skipping this plugin. \n";
response.processFile = false; response.processFile = false;
return response; return response;
} else {
response.container = "." + inputs.container;
} }
response.container = `.${inputs.container}`;
// 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;
} }
// 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. // Check if duration info is filled, if so times it by 0.0166667 to get time in minutes.
if (typeof file.meta.Duration != "undefined") { // If not filled then get duration of stream 0 and do the same.
var duration = file.meta.Duration * 0.0166667; if (typeof file.meta.Duration !== 'undefined') {
duration = file.meta.Duration * 0.0166667;
} else { } else {
var duration = file.ffProbeData.streams[0].duration * 0.0166667; duration = file.ffProbeData.streams[0].duration * 0.0166667;
} }
// Set up required variables. // Set up required variables.
var videoIdx = -1; let videoIdx = -1;
var extraArguments = ""; let extraArguments = '';
var bitrateSettings = ""; let 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/ // Work out currentBitrate using "Bitrate = file size / (number of minutes * .0075)"
var currentBitrate = ~~(file.file_size / (duration * 0.0075)); // Used from here https://blog.frame.io/2017/03/06/calculate-video-bitrates/
// 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. const currentBitrate = ~~(file.file_size / (duration * 0.0075));
var targetBitrate = ~~(file.file_size / (duration * 0.0075) / 2); // 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.
const targetBitrate = ~~(file.file_size / (duration * 0.0075) / 2);
// Allow some leeway under and over the targetBitrate. // Allow some leeway under and over the targetBitrate.
var minimumBitrate = ~~(targetBitrate * 0.7); const minimumBitrate = ~~(targetBitrate * 0.7);
var maximumBitrate = ~~(targetBitrate * 1.3); const 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 comes out as 0 then something has gone wrong and bitrates could not be calculcated.
if (targetBitrate == "0") { // Cancel plugin completely.
if (targetBitrate === '0') {
response.processFile = false; response.processFile = false;
response.infoLog += response.infoLog += 'Target bitrate could not be calculated. Skipping this plugin. \n';
"☒Target bitrate could not be calculated. Skipping this plugin. \n";
return response; return response;
} }
// Check if inputs.bitrate cutoff has something entered (Entered means user actually wants something to happen, empty would disable this). // Check if inputs.bitrate cutoff has something entered.
if (inputs.bitrate_cutoff != "") { // (Entered means user actually wants something to happen, empty would disable this).
// Checks if currentBitrate is below inputs.bitrate_cutoff, if so then cancel plugin without touching original files. 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) { if (currentBitrate <= inputs.bitrate_cutoff) {
response.processFile = false; response.processFile = false;
response.infoLog += `☑Current bitrate is below configured bitrate cutoff of ${inputs.bitrate_cutoff}. Nothing to do, cancelling plugin. \n`; response.infoLog += `Current bitrate is below set bitrate cutoff of ${inputs.bitrate_cutoff}. Nothing to do, cancelling plugin. \n`;
return response; return response;
} }
} }
// Check if force_conform option is checked. If so then check streams and add any extra parameters required to make file conform with output format. // Check if force_conform option is checked.
if (inputs.force_conform == "true") { // If so then check streams and add any extra parameters required to make file conform with output format.
if (inputs.container.toLowerCase() == "mkv") { if (inputs.force_conform === 'true') {
extraArguments += `-map -0:d `; if (inputs.container.toLowerCase() === 'mkv') {
for (var i = 0; i < file.ffProbeData.streams.length; i++) extraArguments += '-map -0:d ';
try { for (let i = 0; i < file.ffProbeData.streams.length; i++) {
if ( try {
file.ffProbeData.streams[i].codec_name if (
.toLowerCase() == "mov_text" || file.ffProbeData.streams[i].codec_name
file.ffProbeData.streams[i].codec_name .toLowerCase() === 'mov_text'
.toLowerCase() == "eia_608" || || file.ffProbeData.streams[i].codec_name
file.ffProbeData.streams[i].codec_name .toLowerCase() === 'eia_608'
.toLowerCase() == "timed_id3" || file.ffProbeData.streams[i].codec_name
) { .toLowerCase() === 'timed_id3'
extraArguments += `-map -0:${i} `; ) {
} extraArguments += `-map -0:${i} `;
} catch (err) {} }
} catch (err) {
// Error
}
}
} }
if (inputs.container.toLowerCase() == "mp4") { if (inputs.container.toLowerCase() === 'mp4') {
for (var i = 0; i < file.ffProbeData.streams.length; i++) for (let i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
if ( if (
file.ffProbeData.streams[i].codec_name file.ffProbeData.streams[i].codec_name
.toLowerCase() == "hdmv_pgs_subtitle" || .toLowerCase() === 'hdmv_pgs_subtitle'
file.ffProbeData.streams[i].codec_name || file.ffProbeData.streams[i].codec_name
.toLowerCase() == "eia_608" || .toLowerCase() === 'eia_608'
file.ffProbeData.streams[i].codec_name || file.ffProbeData.streams[i].codec_name
.toLowerCase() == "subrip" || .toLowerCase() === 'subrip'
file.ffProbeData.streams[i].codec_name || file.ffProbeData.streams[i].codec_name
.toLowerCase() == "timed_id3" .toLowerCase() === 'timed_id3'
) { ) {
extraArguments += `-map -0:${i} `; extraArguments += `-map -0:${i} `;
} }
} catch (err) {} } catch (err) {
// Error
}
}
} }
} }
// Check if 10bit variable is true. // Check if 10bit variable is true.
if (inputs.enable_10bit == "true") { if (inputs.enable_10bit === 'true') {
// If set to true then add 10bit argument // If set to true then add 10bit argument
extraArguments += `-pix_fmt p010le `; extraArguments += '-pix_fmt p010le ';
} }
// 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 (let i = 0; i < file.ffProbeData.streams.length; i++) {
// Check if stream is a video. // Check if stream is a video.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'video') {
// Check if codec of stream is mjpeg/png, if so then remove this "video" stream. mjpeg/png are usually embedded pictures that can cause havoc with plugins. // Check if codec of stream is mjpeg/png.
if (file.ffProbeData.streams[i].codec_name == "mjpeg" || file.ffProbeData.streams[i].codec_name == "png") { // If so then remove this "video" stream.
extraArguments += `-map -v:${videoIdx} `; // mjpeg/png are usually embedded pictures that can cause havoc with plugins.
} if (file.ffProbeData.streams[i].codec_name === 'mjpeg' || file.ffProbeData.streams[i].codec_name === 'png') {
// Check if codec of stream is hevc or vp9 AND check if file.container matches inputs.container. If so nothing for plugin to do. extraArguments += `-map -v:${videoIdx} `;
}
// Check if codec of stream is hevc or vp9
// AND check if file.container matches inputs.container.
// If so nothing for plugin to do.
if ( if (
file.ffProbeData.streams[i].codec_name == "hevc" || file.ffProbeData.streams[i].codec_name == "vp9" && (file.ffProbeData.streams[i].codec_name === 'hevc' || file.ffProbeData.streams[i].codec_name === 'vp9')
file.container == inputs.container && file.container === `${inputs.container}`
) { ) {
response.processFile = false; response.processFile = false;
response.infoLog += `File is already hevc or vp9 & in ${inputs.container}. \n`; response.infoLog += `File is already hevc or vp9 & in ${inputs.container}. \n`;
return response; return response;
} }
// Check if codec of stream is hevc or vp9 AND check if file.container does NOT match inputs.container. If so remux file. // Check if codec of stream is hevc or vp9
// AND check if file.container does NOT match inputs.container.
// If so remux file.
if ( if (
file.ffProbeData.streams[i].codec_name == "hevc" || file.ffProbeData.streams[i].codec_name == "vp9" && (file.ffProbeData.streams[i].codec_name === 'hevc' || file.ffProbeData.streams[i].codec_name === 'vp9')
file.container != "${inputs.container}" && file.container !== `${inputs.container}`
) { ) {
response.infoLog += `File is hevc or vp9 but is not in ${inputs.container} container. Remuxing. \n`; response.infoLog += `File is hevc or vp9 but is not in ${inputs.container} container. Remuxing. \n`;
response.preset = `, -map 0 -c copy ${extraArguments}`; response.preset = `, -map 0 -c copy ${extraArguments}`;
response.processFile = true; response.processFile = true;
return response; return response;
} }
// Increment videoIdx. // Increment videoIdx.
videoIdx++; videoIdx += 1;
} }
} }
// Set bitrateSettings variable using bitrate information calulcated earlier. // Set bitrateSettings variable using bitrate information calulcated earlier.
bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k -maxrate ${maximumBitrate}k -bufsize ${currentBitrate}k`; bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k -maxrate ${maximumBitrate}k -bufsize ${currentBitrate}k`;
// Print to infoLog information around file & bitrate settings. // Print to infoLog information around file & bitrate settings.
response.infoLog += `Container for output selected as ${ response.infoLog += `Container for output selected as ${inputs.container}. \n`;
inputs.container response.infoLog += `Current bitrate = ${currentBitrate} \n`;
}. \n Current bitrate = ${~~( response.infoLog += 'Bitrate settings: \n';
file.file_size / response.infoLog += `Target = ${targetBitrate} \n`;
(duration * 0.0075) response.infoLog += `Minimum = ${minimumBitrate} \n`;
)} \n Bitrate settings: \nTarget = ${targetBitrate} \nMinimum = ${minimumBitrate} \nMaximum = ${maximumBitrate} \n`; response.infoLog += `Maximum = ${maximumBitrate} \n`;
response.preset += `,-map 0 -c:v libx265 ${bitrateSettings} -c:a copy -c:s copy -max_muxing_queue_size 9999 ${extraArguments}`; response.preset += `,-map 0 -c:v libx265 ${bitrateSettings} -c:a copy -c:s copy -max_muxing_queue_size 9999 ${extraArguments}`;
response.processFile = true; response.processFile = true;
response.infoLog += `☒File is not hevc or vp9. Transcoding. \n`; response.infoLog += 'File is not hevc or vp9. Transcoding. \n';
return response; return response;
} }
module.exports.details = details; module.exports.details = details;

@ -0,0 +1,130 @@
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
function details() {
return {
id: 'Tdarr_Plugin_MC93_Migz1Remux',
Stage: 'Pre-processing',
Name: 'Migz-Remux container',
Type: 'Video',
Operation: 'Remux',
Description: 'Files will be remuxed into either mkv or mp4. \n\n',
Version: '1.1',
Link: 'https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz1Remux.js',
Tags: 'pre-processing,ffmpeg,video only,configurable',
Inputs: [{
name: 'container',
tooltip: `Specify output container of file
\\nEnsure that all stream types you may have are supported by your chosen container.
\\nmkv is recommended.
\\nExample:\\n
mkv
\\nExample:\\n
mp4`,
},
{
name: 'force_conform',
tooltip: `Make the file conform to output containers requirements.
\\n Drop hdmv_pgs_subtitle/eia_608/subrip/timed_id3 for MP4.
\\n Drop data streams/mov_text/eia_608/timed_id3 for MKV.
\\n Default is false.
\\nExample:\\n
true
\\nExample:\\n
false`,
},
],
};
}
function plugin(file, librarySettings, inputs) {
const response = {
processFile: false,
preset: '',
handBrakeMode: false,
FFmpegMode: true,
reQueueAfter: true,
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, please configure required options. Skipping this plugin. \n';
response.processFile = false;
return response;
}
response.container = `.${inputs.container}`;
// 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;
}
// Set up required variables.
let extraArguments = '';
let convert = false;
// Check if force_conform option is checked.
// If so then check streams and add any extra parameters required to make file conform with output format.
if (inputs.force_conform === 'true') {
if (inputs.container.toLowerCase() === 'mkv') {
extraArguments += '-map -0:d ';
for (let i = 0; i < file.ffProbeData.streams.length; i++) {
try {
if (
file.ffProbeData.streams[i].codec_name
.toLowerCase() === 'mov_text'
|| file.ffProbeData.streams[i].codec_name
.toLowerCase() === 'eia_608'
|| file.ffProbeData.streams[i].codec_name
.toLowerCase() === 'timed_id3'
) {
extraArguments += `-map -0:${i} `;
}
} catch (err) {
// Error
}
}
}
if (inputs.container.toLowerCase() === 'mp4') {
for (let i = 0; i < file.ffProbeData.streams.length; i++) {
try {
if (
file.ffProbeData.streams[i].codec_name
.toLowerCase() === 'hdmv_pgs_subtitle'
|| file.ffProbeData.streams[i].codec_name
.toLowerCase() === 'eia_608'
|| file.ffProbeData.streams[i].codec_name
.toLowerCase() === 'subrip'
|| file.ffProbeData.streams[i].codec_name
.toLowerCase() === 'timed_id3'
) {
extraArguments += `-map -0:${i} `;
}
} catch (err) {
// Error
}
}
}
}
// Check if file.container does NOT match inputs.container. If so remux file.
if (file.container !== inputs.container) {
response.infoLog += `☒File is ${file.container} but requested to be ${inputs.container} container. Remuxing. \n`;
convert = true;
} else if (file.container === inputs.container) {
response.infoLog += `☑File is already in ${inputs.container} container. \n`;
return response;
}
if (convert === true) {
response.preset += `, -map 0 -c copy -max_muxing_queue_size 9999 ${extraArguments}`;
response.processFile = true;
return response;
}
}
module.exports.details = details;
module.exports.plugin = plugin;

@ -1,164 +1,193 @@
/* eslint-disable */ /* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
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.\n\n',
Version: "1.7", Version: '1.9',
Link: Link: 'https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz2CleanTitle.js',
"https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz2CleanTitle.js", Tags: 'pre-processing,ffmpeg,configurable',
Tags: "pre-processing,ffmpeg,configurable", Inputs: [{
Inputs: [ name: 'clean_audio',
{ tooltip: `Specify if audio titles should be checked & cleaned. Optional.
name: "clean_audio", \\nExample:\\n
tooltip: `Specify if audio titles should be checked & cleaned. Optional. true
\\nExample:\\n
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`,
}, },
{ {
name: "custom_title_matching", name: 'custom_title_matching',
tooltip: `By default if you enable audio or subtitle cleaning the plugin only looks for titles with more then 3 full stops, this is what i think is the safest way to identify junk metadata without removing real metadata that you might want to keep. Here you can specify your own text for it to also search for to match and remove. Comma separated. Optional. tooltip: `If you enable audio or subtitle cleaning the plugin only looks for titles with more then 3 full stops.
\\nExample:\\n //nThis is one way to identify junk metadata without removing real metadata that you might want.
MiNX - Small HD episodes //nHere you can specify your own text for it to also search for to match and remove.
//nComma separated. Optional.
\\nExample:\\n
MiNX - Small HD episodes
\\nExample:\\n \\nExample:\\n
MiNX - Small HD episodes,GalaxyTV - small excellence!`, MiNX - Small HD episodes,GalaxyTV - small excellence!`,
}, },
], ],
}; };
} }
function plugin(file, librarySettings, inputs) { function plugin(file, librarySettings, inputs) {
var response = { const 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. // Set up required variables.
var ffmpegCommandInsert = ""; let ffmpegCommandInsert = '';
var videoIdx = 0; let videoIdx = 0;
var audioIdx = 0; let audioIdx = 0;
var subtitleIdx = 0; let subtitleIdx = 0;
var convert = false; let convert = false;
let custom_title_matching = '';
// Check if inputs.custom_title_matching has been configured. If it has then set variable
if (typeof inputs.custom_title_matching != "undefined") // Check if inputs.custom_title_matching has been configured. If it has then set variable
{ if (typeof inputs.custom_title_matching !== 'undefined') {
var custom_title_matching = inputs.custom_title_matching.toLowerCase().split(","); custom_title_matching = inputs.custom_title_matching.toLowerCase().split(',');
} }
// 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 overall file metadata title is not empty, if it's not empty set to "". // Check if overall file metadata title is not empty, if it's not empty set to "".
if (typeof file.meta.Title != "undefined") if (typeof file.meta.Title !== 'undefined') {
try { try {
ffmpegCommandInsert += ` -metadata title="" `; ffmpegCommandInsert += ' -metadata title="" ';
convert = true; convert = true;
} catch (err) {} } catch (err) {
// Error
}
}
// 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 (let i = 0; i < file.ffProbeData.streams.length; i++) {
{ // Check if stream is a video.
// Check if stream is a video. if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'video') {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") { try {
// Check if stream title is not empty, if it's not empty set to "". // Check if stream title is not empty, if it's not empty set to "".
if (typeof file.ffProbeData.streams[i].tags.title != "undefined") if (typeof file.ffProbeData.streams[i].tags.title !== 'undefined') {
try { response.infoLog += `☒Video stream title is not empty. Removing title from stream ${i} \n`;
response.infoLog += `☒Video stream title is not empty, most likely junk metadata. Removing title from stream ${i} \n`;
ffmpegCommandInsert += ` -metadata:s:v:${videoIdx} title="" `; ffmpegCommandInsert += ` -metadata:s:v:${videoIdx} title="" `;
convert = true; convert = true;
} catch (err) {} }
// Increment videoIdx. // Increment videoIdx.
videoIdx++; videoIdx += 1;
} catch (err) {
// Error
} }
}
// 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. Then check if any audio streams match with user input custom_title_matching variable, if so then remove. // Check if title metadata of audio stream has more then 3 full stops.
if ( // If so then it's likely to be junk metadata so remove.
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && // Then check if any audio streams match with user input custom_title_matching variable, if so then remove.
inputs.clean_audio.toLowerCase() == "true" if (
) { file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio'
if (typeof file.ffProbeData.streams[i].tags.title != "undefined") { && inputs.clean_audio.toLowerCase() === 'true'
if (file.ffProbeData.streams[i].tags.title.split(".").length - 1 > 3) ) {
try { try {
response.infoLog += `☒More then 3 full stops detected in audio title, likely to be junk metadata. Removing title from stream ${i} \n`; if (typeof file.ffProbeData.streams[i].tags.title !== 'undefined') {
ffmpegCommandInsert += ` -metadata:s:a:${audioIdx} title="" `; if (file.ffProbeData.streams[i].tags.title.split('.').length - 1 > 3) {
convert = true; try {
} catch (err) {} response.infoLog += `☒More then 3 full stops in audio title. Removing title from stream ${i} \n`;
if (typeof inputs.custom_title_matching != "undefined")
try {
if (custom_title_matching.indexOf(file.ffProbeData.streams[i].tags.title.toLowerCase()) !== -1)
{
response.infoLog += `☒Audio matched custom input. Removing title from stream ${i} \n`;
ffmpegCommandInsert += ` -metadata:s:a:${audioIdx} title="" `; ffmpegCommandInsert += ` -metadata:s:a:${audioIdx} title="" `;
convert = true; convert = true;
} } catch (err) {
} catch (err) {} // Error
} }
// Increment audioIdx. }
audioIdx++; if (typeof inputs.custom_title_matching !== 'undefined') {
try {
if (custom_title_matching.indexOf(file.ffProbeData.streams[i].tags.title.toLowerCase()) !== -1) {
response.infoLog += `☒Audio matched custom input. Removing title from stream ${i} \n`;
ffmpegCommandInsert += ` -metadata:s:a:${audioIdx} title="" `;
convert = true;
}
} catch (err) {
// Error
}
}
}
// Increment audioIdx.
audioIdx += 1;
} catch (err) {
// Error
} }
}
// 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. Then check if any audio streams match with user input custom_title_matching variable, if so then remove. // Check if title metadata of subtitle stream has more then 3 full stops.
if ( // If so then it's likely to be junk metadata so remove.
file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" && // Then check if any streams match with user input custom_title_matching variable, if so then remove.
inputs.clean_subtitles.toLowerCase() == "true" if (
) { file.ffProbeData.streams[i].codec_type.toLowerCase() === 'subtitle'
if (typeof file.ffProbeData.streams[i].tags.title != "undefined") { && inputs.clean_subtitles.toLowerCase() === 'true'
if (file.ffProbeData.streams[i].tags.title.split(".").length - 1 > 3) ) {
try { try {
response.infoLog += `☒More then 3 full stops detected in subtitle title, likely to be junk metadata. Removing title from stream ${i} \n`; if (typeof file.ffProbeData.streams[i].tags.title !== 'undefined') {
ffmpegCommandInsert += ` -metadata:s:s:${subtitleIdx} title="" `; if (file.ffProbeData.streams[i].tags.title.split('.').length - 1 > 3) {
convert = true; try {
} catch (err) {} response.infoLog += `☒More then 3 full stops in subtitle title. Removing title from stream ${i} \n`;
if (typeof inputs.custom_title_matching != "undefined")
try {
if (custom_title_matching.indexOf(file.ffProbeData.streams[i].tags.title.toLowerCase()) !== -1) {
response.infoLog += `☒Subtitle matched custom input. Removing title from stream ${i} \n`;
ffmpegCommandInsert += ` -metadata:s:s:${subtitleIdx} title="" `; ffmpegCommandInsert += ` -metadata:s:s:${subtitleIdx} title="" `;
convert = true; convert = true;
} } catch (err) {
} catch (err) {} // Error
} }
}
if (typeof inputs.custom_title_matching !== 'undefined') {
try {
if (custom_title_matching.indexOf(file.ffProbeData.streams[i].tags.title.toLowerCase()) !== -1) {
response.infoLog += `☒Subtitle matched custom input. Removing title from stream ${i} \n`;
ffmpegCommandInsert += ` -metadata:s:s:${subtitleIdx} title="" `;
convert = true;
}
} catch (err) {
// Error
}
}
}
// Increment subtitleIdx. // Increment subtitleIdx.
subtitleIdx++; subtitleIdx += 1;
} catch (err) {
// Error
} }
} }
}
// 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 9999`; response.preset = `,${ffmpegCommandInsert} -c copy -map 0 -max_muxing_queue_size 9999`;
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;
} }

@ -1,141 +1,153 @@
/* eslint-disable */ /* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
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 tracks & can tags tracks with an unknown language. \n\n',
Version: "2.3", Version: '2.4',
Link: Link: 'https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz3CleanAudio.js',
"https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz3CleanAudio.js", Tags: 'pre-processing,ffmpeg,audio only,configurable',
Tags: "pre-processing,ffmpeg,audio only,configurable", Inputs: [{
Inputs: [ name: 'language',
{ tooltip: `Specify language tag/s here for the audio tracks you'd like to keep
name: "language", \\nRecommended to keep "und" as this stands for undertermined
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 \\nSome files may not have the language specified.
\\nExample:\\n \\nMust follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
eng \\nExample:\\n
eng
\\nExample:\\n
eng,und \\nExample:\\n
eng,und
\\nExample:\\n
eng,und,jap`, \\nExample:\\n
}, eng,und,jap`,
{ },
name: "commentary", {
tooltip: `Specify if audio tracks that contain commentary/description should be removed. name: 'commentary',
\\nExample:\\n tooltip: `Specify if audio tracks that contain commentary/description should be removed.
true \\nExample:\\n
true
\\nExample:\\n
false`, \\nExample:\\n
}, false`,
{ },
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 name: 'tag_language',
\\nExample:\\n tooltip: `Specify a single language for audio tracks with no language or unknown language to be tagged with.
eng \\nYou must have "und" in your list of languages to keep for this to function.
\\nMust follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
\\nExample:\\n \\nLeave empty to disable.
por`, \\nExample:\\n
}, eng
{
name: "tag_title", \\nExample:\\n
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. por`,
\\nExample:\\n },
true {
name: 'tag_title',
\\nExample:\\n tooltip: `Specify audio tracks with no title to be tagged with the number of channels they contain.
false`, \\nDo NOT use this with mp4, as mp4 does not support title tags.
}, \\nExample:\\n
true
\\nExample:\\n
false`,
},
], ],
}; };
} }
function plugin(file, librarySettings, inputs) { function plugin(file, librarySettings, inputs) {
var response = { const 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 += response.infoLog += '☒Language/s options not set, please configure required options. Skipping this plugin. \n';
"☒Language/s keep have not been configured within plugin settings, please configure required options. Skipping this plugin. \n";
response.processFile = false; response.processFile = false;
return response; return response;
} }
// Set up required variables. // Set up required variables.
var language = inputs.language.split(","); const language = inputs.language.split(',');
var ffmpegCommandInsert = ""; let ffmpegCommandInsert = '';
var convert = false; let convert = false;
var audioIdx = 0; let audioIdx = 0;
var audioStreamsRemoved = 0; let audioStreamsRemoved = 0;
var audioStreamCount = file.ffProbeData.streams.filter( const audioStreamCount = file.ffProbeData.streams.filter(
(row) => row.codec_type.toLowerCase() == "audio" (row) => row.codec_type.toLowerCase() === 'audio',
).length; ).length;
for (var i = 0; i < file.ffProbeData.streams.length; i++) { for (let i = 0; i < file.ffProbeData.streams.length; i++) {
// Catch error here incase the language metadata is completely missing. // Catch error here incase the language metadata is completely missing.
try { try {
// Check if stream is audio AND checks if the tracks language code does not match any of the languages entered in inputs.language. // Check if stream is audio
// AND checks if the tracks language code does not match any of the languages entered in inputs.language.
if ( if (
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio'
language.indexOf( && language.indexOf(
file.ffProbeData.streams[i].tags.language.toLowerCase() file.ffProbeData.streams[i].tags.language.toLowerCase(),
) === -1 ) === -1
) { ) {
audioStreamsRemoved++; audioStreamsRemoved += 1;
ffmpegCommandInsert += `-map -0:a:${audioIdx} `; ffmpegCommandInsert += `-map -0:a:${audioIdx} `;
response.infoLog += `☒Audio stream detected as being an unwanted language, removing. Audio stream 0:a:${audioIdx} - ${file.ffProbeData.streams[ response.infoLog += `☒Audio stream detected as being unwanted, removing. Audio stream 0:a:${audioIdx} \n`;
i
].tags.language.toLowerCase()} \n`;
convert = true; convert = true;
} }
} catch (err) {} } catch (err) {
// Error
}
// Catch error here incase the title metadata is completely missing. // Catch error here incase the title metadata is completely missing.
try { 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. // 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 ( if (
inputs.commentary.toLowerCase() == "true" && inputs.commentary.toLowerCase() === 'true'
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && && file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio'
(file.ffProbeData.streams[i].tags.title && (file.ffProbeData.streams[i].tags.title
.toLowerCase() .toLowerCase()
.includes("commentary") || .includes('commentary')
file.ffProbeData.streams[i].tags.title || file.ffProbeData.streams[i].tags.title
.toLowerCase() .toLowerCase()
.includes("description") || .includes('description')
file.ffProbeData.streams[i].tags.title.toLowerCase().includes("sdh")) || file.ffProbeData.streams[i].tags.title.toLowerCase().includes('sdh'))
) { ) {
audioStreamsRemoved++; audioStreamsRemoved += 1;
ffmpegCommandInsert += `-map -0:a:${audioIdx} `; 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`; response.infoLog += `☒Audio stream detected as being descriptive, removing. Stream 0:a:${audioIdx} \n`;
convert = true; convert = true;
} }
} catch (err) {} } catch (err) {
// Error
}
// 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. // 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 ( if (
inputs.tag_language != "" && inputs.tag_language !== ''
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio'
) { ) {
// Catch error here incase the metadata is completely missing. // Catch error here incase the metadata is completely missing.
try { try {
@ -143,64 +155,69 @@ function plugin(file, librarySettings, inputs) {
if ( if (
file.ffProbeData.streams[i].tags.language file.ffProbeData.streams[i].tags.language
.toLowerCase() .toLowerCase()
.includes("und") .includes('und')
) { ) {
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} language=${inputs.tag_language} `; 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`; response.infoLog += `☒Audio stream detected as having no language, tagging as ${inputs.tag_language}. \n`;
convert = true; convert = true;
} }
} catch (err) {} } catch (err) {
// Error
}
// 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. // Checks if the tags metadata is completely missing.
if (typeof file.ffProbeData.streams[i].tags == "undefined") { // 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} `; 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`; response.infoLog += `☒Audio stream detected as having no language, tagging as ${inputs.tag_language}. \n`;
convert = true;
} else if (typeof file.ffProbeData.streams[i].tags.language === 'undefined') {
// 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.
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} language=${inputs.tag_language} `;
response.infoLog += `☒Audio stream detected as having no language, tagging as ${inputs.tag_language}. \n`;
convert = true; 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;
}
} }
} }
try { try {
// 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. // 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.
if ( if (
typeof file.ffProbeData.streams[i].tags.title == "undefined" && typeof file.ffProbeData.streams[i].tags.title === 'undefined'
inputs.tag_title.toLowerCase() == "true" && && inputs.tag_title.toLowerCase() === 'true'
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio'
) { ) {
if (file.ffProbeData.streams[i].channels == "8") { if (file.ffProbeData.streams[i].channels === '8') {
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} title="7.1" `; 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`; response.infoLog += `☒Audio stream detected as 8 channel with no title, tagging. Stream 0:a:${audioIdx} \n`;
convert = true; convert = true;
} }
if (file.ffProbeData.streams[i].channels == "6") { if (file.ffProbeData.streams[i].channels === '6') {
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} title="5.1" `; 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`; response.infoLog += `☒Audio stream detected as 6 channel with no title, tagging. Stream 0:a:${audioIdx} \n`;
convert = true; convert = true;
} }
if (file.ffProbeData.streams[i].channels == "2") { if (file.ffProbeData.streams[i].channels === '2') {
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} title="2.0" `; 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`; response.infoLog += `☒Audio stream detected as 2 channel with no title, tagging. Stream 0:a:${audioIdx} \n`;
convert = true; convert = true;
} }
} }
} catch (err) {} } catch (err) {
// Error
}
// Check if stream type is audio and increment audioIdx if true. // Check if stream type is audio and increment audioIdx if true.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio') {
audioIdx++; audioIdx += 1;
} }
} }
// Failsafe to cancel processing if all streams would be removed following this plugin. We don't want no audio. // Failsafe to cancel processing if all streams would be removed following this plugin. We don't want no audio.
if (audioStreamsRemoved == audioStreamCount) { if (audioStreamsRemoved === audioStreamCount) {
response.infoLog += response.infoLog += '☒Cancelling plugin otherwise all audio tracks would be removed. \n';
"☒Cancelling plugin otherwise all audio tracks would be removed. \n";
response.processFile = false; response.processFile = false;
return response; return response;
} }
@ -209,12 +226,11 @@ function plugin(file, librarySettings, inputs) {
if (convert === true) { if (convert === true) {
response.processFile = true; response.processFile = true;
response.preset = `, -map 0 ${ffmpegCommandInsert} -c copy -max_muxing_queue_size 9999`; response.preset = `, -map 0 ${ffmpegCommandInsert} -c copy -max_muxing_queue_size 9999`;
response.container = "." + file.container; response.container = `.${file.container}`;
response.reQueueAfter = true; response.reQueueAfter = true;
} else { } else {
response.processFile = false; response.processFile = false;
response.infoLog += response.infoLog += "☑File doesn't contain audio tracks which are unwanted or that require tagging.\n";
"☑File doesn't contain audio tracks which are unwanted or that require tagging.\n";
} }
return response; return response;
} }

@ -1,124 +1,131 @@
/* eslint-disable */ /* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
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 tracks & can tag tracks with an unknown language. \n\n',
Version: "2.3", Version: '2.4',
Link: Link: 'https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz4CleanSubs.js',
"https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz4CleanSubs.js", Tags: 'pre-processing,ffmpeg,subtitle only,configurable',
Tags: "pre-processing,ffmpeg,subtitle only,configurable", Inputs: [{
Inputs: [ name: 'language',
{ tooltip: `Specify language tag/s here for the subtitle tracks you'd like to keep.
name: "language", \\nMust follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
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.
\\nExample:\\n \\nMust follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
eng \\nLeave empty to disable.
\\nExample:\\n
eng
\\nExample:\\n \\nExample:\\n
por`, por`,
}, },
], ],
}; };
} }
function plugin(file, librarySettings, inputs) { function plugin(file, librarySettings, inputs) {
var response = { const 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 += response.infoLog += '☒Language/s to keep have not been configured, please configure required options. Skipping this plugin. \n';
"☒Language/s keep have not been configured within plugin settings, please configure required options. Skipping this plugin. \n";
response.processFile = false; response.processFile = false;
return response; return response;
} }
// Set up required variables. // Set up required variables.
var language = inputs.language.split(","); const language = inputs.language.split(',');
var ffmpegCommandInsert = ""; let ffmpegCommandInsert = '';
var subtitleIdx = 0; let subtitleIdx = 0;
var convert = false; let 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 (let i = 0; i < file.ffProbeData.streams.length; i++) {
// Catch error here incase the language metadata is completely missing. // Catch error here incase the language 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 stream is subtitle
// AND checks if the tracks language code does not match any of the languages entered in inputs.language.
if ( if (
file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" && file.ffProbeData.streams[i].codec_type.toLowerCase() === 'subtitle'
language.indexOf( && language.indexOf(
file.ffProbeData.streams[i].tags.language.toLowerCase() file.ffProbeData.streams[i].tags.language.toLowerCase(),
) === -1 ) === -1
) { ) {
ffmpegCommandInsert += `-map -0:s:${subtitleIdx} `; ffmpegCommandInsert += `-map -0:s:${subtitleIdx} `;
response.infoLog += `☒Subtitle stream detected as being an unwanted language, removing. Subtitle stream 0:s:${subtitleIdx} - ${file.ffProbeData.streams[ response.infoLog += `☒Subtitle stream detected as being unwanted, removing. Stream 0:s:${subtitleIdx} \n`;
i
].tags.language.toLowerCase()} \n`;
convert = true; convert = true;
} }
} catch (err) {} } catch (err) {
// Error
}
// Catch error here incase the title metadata is completely missing. // Catch error here incase the title metadata is completely missing.
try { try {
// 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. // Check if inputs.commentary is set to true
// AND if stream is subtitle
// AND then checks for stream titles with the following "commentary or description".
// Removing any streams that are applicable.
if ( if (
inputs.commentary.toLowerCase() == "true" && inputs.commentary.toLowerCase() === 'true'
file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" && && file.ffProbeData.streams[i].codec_type.toLowerCase() === 'subtitle'
(file.ffProbeData.streams[i].tags.title && (file.ffProbeData.streams[i].tags.title
.toLowerCase() .toLowerCase()
.includes("commentary") || .includes('commentary')
file.ffProbeData.streams[i].tags.title || file.ffProbeData.streams[i].tags.title
.toLowerCase() .toLowerCase()
.includes("description") || .includes('description'))
file.ffProbeData.streams[i].tags.title.toLowerCase().includes("sdh"))
) { ) {
ffmpegCommandInsert += `-map -0:s:${subtitleIdx} `; 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`; response.infoLog += `☒Subtitle stream detected as being descriptive, removing. Stream 0:s:${subtitleIdx} \n`;
convert = true; convert = true;
} }
} catch (err) {} } catch (err) {
// Error
}
// 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. // 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.
if ( if (
inputs.tag_language != "" && inputs.tag_language !== ''
file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" && file.ffProbeData.streams[i].codec_type.toLowerCase() === 'subtitle'
) { ) {
// Catch error here incase the metadata is completely missing. // Catch error here incase the metadata is completely missing.
try { try {
@ -126,33 +133,36 @@ function plugin(file, librarySettings, inputs) {
if ( if (
file.ffProbeData.streams[i].tags.language file.ffProbeData.streams[i].tags.language
.toLowerCase() .toLowerCase()
.includes("und") .includes('und')
) { ) {
ffmpegCommandInsert += `-metadata:s:s:${subtitleIdx} language=${inputs.tag_language} `; 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`; response.infoLog += `☒Subtitle stream detected as having no language, tagging as ${inputs.tag_language}. \n`;
convert = true; convert = true;
} }
} catch (err) {} } catch (err) {
// Error
}
// 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. // Checks if the tags metadata is completely missing.
if (typeof file.ffProbeData.streams[i].tags == "undefined") { // 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} `; 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`; response.infoLog += `☒Subtitle stream detected as having no language, tagging as ${inputs.tag_language}. \n`;
convert = true;
} else if (typeof file.ffProbeData.streams[i].tags.language === 'undefined') {
// 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
ffmpegCommandInsert += `-metadata:s:s:${subtitleIdx} language=${inputs.tag_language} `;
response.infoLog += `☒Subtitle stream detected as having no language, tagging as ${inputs.tag_language}. \n`;
convert = true; 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;
}
} }
} }
// Check if stream type is subtitle and increment subtitleIdx if true. // Check if stream type is subtitle and increment subtitleIdx if true.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'subtitle') {
subtitleIdx++; subtitleIdx += 1;
} }
} }
@ -160,12 +170,11 @@ function plugin(file, librarySettings, inputs) {
if (convert === true) { if (convert === true) {
response.processFile = true; response.processFile = true;
response.preset = `, -map 0 ${ffmpegCommandInsert} -c copy -max_muxing_queue_size 9999`; response.preset = `, -map 0 ${ffmpegCommandInsert} -c copy -max_muxing_queue_size 9999`;
response.container = "." + file.container; response.container = `.${file.container}`;
response.reQueueAfter = true; response.reQueueAfter = true;
} else { } else {
response.processFile = false; response.processFile = false;
response.infoLog += response.infoLog += "☑File doesn't contain subtitle tracks which are unwanted or that require tagging.\n";
"☑File doesn't contain subtitle tracks which are unwanted or that require tagging.\n";
} }
return response; return response;
} }

@ -1,149 +1,153 @@
/* eslint-disable */ /* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
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.2", Version: '2.3',
Link: "", Link: '',
Tags: "pre-processing,ffmpeg,audio only,configurable", Tags: 'pre-processing,ffmpeg,audio only,configurable',
Inputs: [ Inputs: [{
{ name: 'aac_stereo',
name: "aac_stereo", tooltip: `Specify if any 2.0 audio tracks should be converted to aac for maximum compatability with devices.
tooltip: `Specify if any 2.0 audio tracks should be converted to aac for maximum compatability with devices. Optional. \\nOptional.
\\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.
\\nExample:\\n \\nI.e if you have an 8ch but no 2ch or 6ch, create the missing audio tracks from the 8 ch.
true \\nLikewise if you only have 6ch, create the missing 2ch from it. Optional.
\\nExample:\\n
true
\\nExample:\\n \\nExample:\\n
false`, false`,
}, },
], ],
}; };
} }
function plugin(file, librarySettings, inputs) { function plugin(file, librarySettings, inputs) {
var response = { const 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. // 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 == "") { if (inputs && inputs.aac_stereo === '' && inputs.downmix === '') {
response.infoLog += response.infoLog += '☒Plugin has not been configured, please configure required options. Skipping this plugin. \n';
"☒Neither aac_stereo or downmix options have been configured within plugin settings, please configure required options. Skipping this plugin. \n";
response.processFile = false; response.processFile = false;
return response; return response;
} }
// 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;
} }
// Set up required variables. // Set up required variables.
var ffmpegCommandInsert = ""; let ffmpegCommandInsert = '';
var audioIdx = 0; let audioIdx = 0;
var has2Channel = false; let has2Channel = false;
var has6Channel = false; let has6Channel = false;
var has8Channel = false; let has8Channel = false;
var convert = false; let 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 (let i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
// Go through all audio streams and check if 2,6 & 8 channel tracks exist or not. // Go through all audio streams and check if 2,6 & 8 channel tracks exist or not.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio') {
if (file.ffProbeData.streams[i].channels == "2") { if (file.ffProbeData.streams[i].channels === '2') {
has2Channel = true; has2Channel = true;
} }
if (file.ffProbeData.streams[i].channels == "6") { if (file.ffProbeData.streams[i].channels === '6') {
has6Channel = true; has6Channel = true;
} }
if (file.ffProbeData.streams[i].channels == "8") { if (file.ffProbeData.streams[i].channels === '8') {
has8Channel = true; has8Channel = true;
} }
} }
} catch (err) {} } catch (err) {
// Error
}
} }
// 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 (let i = 0; i < file.ffProbeData.streams.length; i++) {
// 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') {
// Catch error here incase user left inputs.downmix empty. // Catch error here incase user left inputs.downmix empty.
try { try {
// Check if inputs.downmix is set to true. // Check if inputs.downmix is set to true.
if (inputs.downmix.toLowerCase() == "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. // Check if file has 8 channel audio but no 6 channel, if so then create extra downmix from the 8 channel.
if ( if (
has8Channel == true && has8Channel === true
has6Channel == false && && has6Channel === false
file.ffProbeData.streams[i].channels == "8" && file.ffProbeData.streams[i].channels === '8'
) { ) {
ffmpegCommandInsert += `-map 0:${i} -c:a:${audioIdx} ac3 -ac 6 -metadata:s:a:${audioIdx} title="5.1 " `; ffmpegCommandInsert += `-map 0:${i} -c:a:${audioIdx} ac3 -ac 6 -metadata:s:a:${audioIdx} title="5.1 " `;
response.infoLog += response.infoLog += '☒Audio track is 8 channel, no 6 channel exists. Creating 6 channel from 8 channel. \n';
"☒Audio track is 8 channel, no 6 channel exists. Creating 6 channel from 8 channel. \n";
convert = true; convert = true;
} }
// Check if file has 6 channel audio but no 2 channel, if so then create extra downmix from the 6 channel. // Check if file has 6 channel audio but no 2 channel, if so then create extra downmix from the 6 channel.
if ( if (
has6Channel == true && has6Channel === true
has2Channel == false && && has2Channel === false
file.ffProbeData.streams[i].channels == "6" && file.ffProbeData.streams[i].channels === '6'
) { ) {
ffmpegCommandInsert += `-map 0:${i} -c:a:${audioIdx} aac -ac 2 -metadata:s:a:${audioIdx} title="2.0 " `; ffmpegCommandInsert += `-map 0:${i} -c:a:${audioIdx} aac -ac 2 -metadata:s:a:${audioIdx} title="2.0 " `;
response.infoLog += response.infoLog += '☒Audio track is 6 channel, no 2 channel exists. Creating 2 channel from 6 channel. \n';
"☒Audio track is 6 channel, no 2 channel exists. Creating 2 channel from 6 channel. \n";
convert = true; convert = true;
} }
} }
} catch (err) {} } catch (err) {
// Error
}
// Catch error here incase user left inputs.downmix empty. // Catch error here incase user left inputs.downmix empty.
try { try {
// Check if inputs.aac_stereo is set to true. // Check if inputs.aac_stereo is set to true.
if (inputs.aac_stereo.toLowerCase() == "true") { if (inputs.aac_stereo.toLowerCase() === 'true') {
// Check if codec_name for stream is NOT aac AND check if channel ammount is 2. // Check if codec_name for stream is NOT aac AND check if channel ammount is 2.
if ( if (
file.ffProbeData.streams[i].codec_name != "aac" && file.ffProbeData.streams[i].codec_name !== 'aac'
file.ffProbeData.streams[i].channels == "2" && file.ffProbeData.streams[i].channels === '2'
) { ) {
ffmpegCommandInsert += `-c:a:${audioIdx} aac `; ffmpegCommandInsert += `-c:a:${audioIdx} aac `;
response.infoLog += response.infoLog += '☒Audio track is 2 channel but is not AAC. Converting. \n';
"☒Audio track is 2 channel but is not AAC. Converting. \n";
convert = true; convert = true;
} }
} }
} catch (err) {} } catch (err) {
audioIdx++; // Error
}
audioIdx += 1;
} }
} }
// 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.processFile = true; response.processFile = true;
response.preset = `, -map 0 -c:v copy -c:a copy ${ffmpegCommandInsert} -strict -2 -c:s copy -max_muxing_queue_size 9999 `; response.preset = `, -map 0 -c:v copy -c:a copy ${ffmpegCommandInsert} -strict -2 -c:s copy -max_muxing_queue_size 9999 `;
} else { } else {
response.infoLog += "☑File contains all required audio formats. \n"; response.infoLog += '☑File contains all required audio formats. \n';
response.processFile = false; response.processFile = false;
} }
return response; return response;

@ -1,185 +1,201 @@
/* eslint-disable */ /* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
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.2", Version: '1.3',
Link: Link:
"https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz6OrderStreams.js", 'https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz6OrderStreams.js',
Tags: "pre-processing,ffmpeg,", Tags: 'pre-processing,ffmpeg,',
}; };
} }
function plugin(file) { function plugin(file) {
var response = { const 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 = ""; let ffmpegCommandInsert = '';
var videoIdx = 0; let audioIdx = 0;
var audioIdx = 0; let audio6Idx = 0;
var audio2Idx = 0; let audio8Idx = 0;
var audio6Idx = 0; let subtitleIdx = 0;
var audio8Idx = 0; let convert = false;
var subtitleIdx = 0;
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 (let 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 (audioIdx != "0" || subtitleIdx != "0") { // If so 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') {
convert = true; convert = true;
response.infoLog += "☒ Video not first. \n"; response.infoLog += '☒ Video not first. \n';
} }
// Increment 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 (subtitleIdx != "0") { // If so then it means a subtitle track has already appeared before an audio track
// So file needs to be organized.
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 += 1;
// Check if audio track is 2 channel. // Check if audio track is 2 channel.
if (file.ffProbeData.streams[i].channels == "2") { 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. // Check if audio6Idx or audio8Idx do NOT equal 0.
if (audio6Idx != "0" || audio8Idx != "0") { // If so then it means a 6 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; convert = true;
response.infoLog += "☒ Audio 2ch not first. \n"; response.infoLog += '☒ Audio 2ch not first. \n';
} }
// Increment audio2Idx.
audio2Idx++;
} }
// Check if audio track is 6 channel. // Check if audio track is 6 channel.
if (file.ffProbeData.streams[i].channels == "6") { 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. // Check if audio8Idx does NOT equal 0.
if (audio8Idx != "0") { // If so 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; convert = true;
response.infoLog += "☒ Audio 6ch not second. \n"; response.infoLog += '☒ Audio 6ch not second. \n';
} }
// Increment audio6Idx. // Increment audio6Idx.
audio6Idx++; audio6Idx += 1;
} }
// Check if audio track is 8 channel. // Check if audio track is 8 channel.
if (file.ffProbeData.streams[i].channels == "8") { if (file.ffProbeData.streams[i].channels === '8') {
// Increment audio8Idx. // Increment audio8Idx.
audio8Idx++; audio8Idx += 1;
} }
} }
// Check if stream is subtitle. // Check if stream is subtitle.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'subtitle') {
// Increment subtitleIdx // Increment subtitleIdx
subtitleIdx++; subtitleIdx += 1;
} }
} catch (err) {} } catch (err) {
// Error
}
} }
// 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 (let i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
// Check if stream is video AND is not a mjpeg. // Check if stream is video AND is not a mjpeg.
if ( if (
file.ffProbeData.streams[i].codec_type.toLowerCase() == "video" && file.ffProbeData.streams[i].codec_type.toLowerCase() === 'video'
file.ffProbeData.streams[i].codec_name.toLowerCase() != "mjpeg" && file.ffProbeData.streams[i].codec_name.toLowerCase() !== 'mjpeg'
) { ) {
ffmpegCommandInsert += `-map 0:${i} `; ffmpegCommandInsert += `-map 0:${i} `;
} }
} catch (err) {} } catch (err) {
// Error
}
} }
// 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 (let i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
// Check if stream is audio AND 2 channel. // Check if stream is audio AND 2 channel.
if ( if (
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio'
file.ffProbeData.streams[i].channels == "2" && file.ffProbeData.streams[i].channels === '2'
) { ) {
ffmpegCommandInsert += `-map 0:${i} `; ffmpegCommandInsert += `-map 0:${i} `;
} }
} catch (err) {} } catch (err) {
// Error
}
} }
// 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 (let i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
// Check if stream is audio AND 6 channel. // Check if stream is audio AND 6 channel.
if ( if (
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio'
file.ffProbeData.streams[i].channels == "6" && file.ffProbeData.streams[i].channels === '6'
) { ) {
ffmpegCommandInsert += `-map 0:${i} `; ffmpegCommandInsert += `-map 0:${i} `;
} }
} catch (err) {} } catch (err) {
// Error
}
} }
// 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 (let i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
// Check if stream is audio AND 8 channel. // Check if stream is audio AND 8 channel.
if ( if (
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio'
file.ffProbeData.streams[i].channels == "8" && file.ffProbeData.streams[i].channels === '8'
) { ) {
ffmpegCommandInsert += `-map 0:${i} `; ffmpegCommandInsert += `-map 0:${i} `;
} }
} catch (err) {} } catch (err) {
// Error
}
} }
// 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 (let 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 not 2, 6 or 8 channel.
if ( if (
file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio'
file.ffProbeData.streams[i].channels != "2" && && file.ffProbeData.streams[i].channels !== '2'
file.ffProbeData.streams[i].channels != "6" && && file.ffProbeData.streams[i].channels !== '6'
file.ffProbeData.streams[i].channels != "8" && file.ffProbeData.streams[i].channels !== '8'
) { ) {
ffmpegCommandInsert += `-map 0:${i} `; ffmpegCommandInsert += `-map 0:${i} `;
} }
} catch (err) {} } catch (err) {
// Error
}
} }
// 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 (let i = 0; i < file.ffProbeData.streams.length; i++) {
try { try {
// Check if stream is subtitle. // Check if stream is subtitle.
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") { if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'subtitle') {
ffmpegCommandInsert += `-map 0:${i} `; ffmpegCommandInsert += `-map 0:${i} `;
} }
} catch (err) {} } catch (err) {
// Error
}
} }
// 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.processFile = true; response.processFile = true;
response.preset = `,${ffmpegCommandInsert} -c copy -max_muxing_queue_size 9999`; response.preset = `,${ffmpegCommandInsert} -c copy -max_muxing_queue_size 9999`;
response.reQueueAfter = true; response.reQueueAfter = true;
response.infoLog += response.infoLog
"☒ Streams are out of order, reorganizing streams. Video, Audio, Subtitles. \n"; += '☒ Streams are out of order, reorganizing streams. Video, Audio, Subtitles. \n';
} else { } else {
response.infoLog += "☑ Streams are in expected order. \n "; response.infoLog += '☑ Streams are in expected order. \n ';
response.processFile = false; response.processFile = false;
} }
return response; return response;

@ -1,68 +1,68 @@
/* eslint-disable */ /* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
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.2", Version: '1.3',
Link: Link:
"https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_MigzImageRemoval.js", 'https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_MigzImageRemoval.js',
Tags: "pre-processing,ffmpeg,video only", Tags: 'pre-processing,ffmpeg,video only',
}; };
} }
function plugin(file, librarySettings, inputs) { function plugin(file, librarySettings) {
var response = { const 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; let videoIdx = 0;
var extraArguments = ""; let extraArguments = '';
var convert = false; let 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 (let 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 ( if (
file.ffProbeData.streams[i].codec_name == "mjpeg" || file.ffProbeData.streams[i].codec_name === 'mjpeg'
file.ffProbeData.streams[i].codec_name == "png" || file.ffProbeData.streams[i].codec_name === 'png'
) { ) {
convert = true; convert = true;
extraArguments += `-map -v:${videoIdx} `; extraArguments += `-map -v:${videoIdx} `;
} }
// Increment videoIdx. // Increment videoIdx.
videoIdx++; videoIdx += 1;
} }
} }
// 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 9999 ${extraArguments}`; response.preset += `,-map 0 -c copy -max_muxing_queue_size 9999 ${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 += response.infoLog
"☑File doesn't contain any unwanted image format streams.\n"; += "☑File doesn't contain any unwanted image format streams.\n";
} }
return response; return response;
} }

@ -1,95 +1,89 @@
/* eslint-disable */ /* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
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.2',
Link: Link: 'https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_MigzPlex_Autoscan.js',
"https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_MigzPlex_Autoscan.js", Tags: '3rd party,post-processing,configurable',
Tags: "3rd party,post-processing,configurable",
Inputs: [ Inputs: [{
{ name: 'autoscan_address',
name: "autoscan_address", tooltip: `
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
http://192.168.0.10
\\nExample:\\n
https://subdomain.domain.tld`,
},
{
name: "autoscan_port",
tooltip: `
Enter the port Autoscan is using, default is 3468
\\nExample:\\n \\nExample:\\n
3468`, http://192.168.0.10
},
{ \\nExample:\\n
name: "autoscan_passkey", https://subdomain.domain.tld`,
tooltip: ` },
{
Enter the autoscan passkey. name: 'autoscan_port',
tooltip: `
\\nExample:\\n Enter the port Autoscan is using, default is 3468
9c4b81fe234e4d6eb9011cefe514d915`,
}, \\nExample:\\n
3468`,
},
{
name: 'autoscan_passkey',
tooltip: `
Enter the autoscan passkey.
\\nExample:\\n
9c4b81fe234e4d6eb9011cefe514d915`,
},
], ],
}; };
}; };
module.exports.plugin = function plugin(file, librarySettings, inputs) { module.exports.plugin = function plugin(file, librarySettings, inputs) {
// Set up required variables.
const request = require('request');
const ADDRESS = inputs.autoscan_address;
const PORT = inputs.autoscan_port;
const PASSKEY = inputs.autoscan_passkey;
let filepath = '';
const response = '';
filepath = `${file.file}`;
// 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
inputs.autoscan_address == "" && && inputs.autoscan_address === ''
inputs.autoscan_port == "" && && inputs.autoscan_port === ''
inputs.autoscan_passkey == "" && inputs.autoscan_passkey === ''
) { ) {
response.infoLog += response.infoLog += '☒Plugin options have not been configured, please configure options. Skipping this plugin. \n';
"☒Autoscan options have not been configured, please configure all options. Skipping this plugin. \n";
response.processFile = false; response.processFile = false;
return response; return response;
} }
// Take variable inputs and turn them into read only variable
const request = require("request");
const ADDRESS = inputs.autoscan_address;
const PORT = inputs.autoscan_port;
const PASSKEY = inputs.autoscan_passkey;
// Set up required variables.
var response = "";
filepath = `${file.file}`;
// Set content of request/post. // Set content of request/post.
request.post( request.post({
{ headers: {
headers: { 'content-type': 'application/json',
"content-type": "application/json", },
}, url: `${ADDRESS}:${PORT}/${PASSKEY}`,
url: `${ADDRESS}:${PORT}/${PASSKEY}`, form: {
form: { eventType: 'Manual',
eventType: "Manual", filepath: `${filepath}`,
filepath: `${filepath}`,
},
}, },
(error, res, body) => { },
if (error) { (error, res, body) => {
console.error(error); if (error) {
} console.error(error);
console.log(`statusCode: ${res.statusCode}`);
console.log(body);
} }
); console.log(`statusCode: ${res.statusCode}`);
console.log(body);
});
console.log("request next"); console.log('request next');
console.log(request.post); console.log(request.post);
}; };

Loading…
Cancel
Save