Merge branch 'master' into patch-1

make-only-subtitle-default
HaveAGitGat 4 years ago committed by GitHub
commit 67e4f71b43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,5 +1,10 @@
/* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */ /* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
/* eslint-disable */ /* eslint-disable */
/* eslint max-len: 0 */
/* eslint no-bitwise: 0 */
/* eslint no-mixed-operators: 0 */
const os = require('os');
function details() { function details() {
return { return {
id: 'Tdarr_Plugin_ER01_Transcode audio and video with HW (PC and Mac)', id: 'Tdarr_Plugin_ER01_Transcode audio and video with HW (PC and Mac)',
@ -8,10 +13,10 @@ function details() {
Type: 'Video', Type: 'Video',
Operation: 'Transcode', Operation: 'Transcode',
Description: `Files not in H265 will be transcoded into H265 using hw with ffmpeg, assuming mkv container. Plugin uses QS if the node runs on a PC, or Videotoolbox if run on a Mac. Description: `Files not in H265 will be transcoded into H265 using hw with ffmpeg, assuming mkv container. Plugin uses QS if the node runs on a PC, or Videotoolbox if run on a Mac.
Much thanks to Migz for bulk of the important code. Much thanks to Migz for bulk of the important code.
Quality is controlled via bitrate adjustments - H264 to H265 assumes 0.5x bitrate. Resolution change from 1080p to 720p assumes 0.7x bitrate. Quality is controlled via bitrate adjustments - H264 to H265 assumes 0.5x bitrate. Resolution change from 1080p to 720p assumes 0.7x bitrate.
Audio conversion is either 2 channel ac3 or 6 channel ac3, for maximal compatibility and small file size. All subtitles removed. Audio conversion is either 2 channel ac3 or 6 channel ac3, for maximal compatibility and small file size. All subtitles removed.
The idea is to homogenize your collection to 1080p or higher movies with 5.1 audio, or 720p TV shows with 2.0 audio.`, The idea is to homogenize your collection to 1080p or higher movies with 5.1 audio, or 720p TV shows with 2.0 audio.`,
Tags: 'pre-processing,ffmpeg,video only,configurable,h265', Tags: 'pre-processing,ffmpeg,video only,configurable,h265',
Inputs: [{ Inputs: [{
@ -33,7 +38,7 @@ function details() {
\\nExample:\\n \\nExample:\\n
no`, no`,
}, },
{ {
name: 'bitrate_cutoff', name: 'bitrate_cutoff',
tooltip: `Specify bitrate cutoff, files with a current bitrate lower then this will not be transcoded. tooltip: `Specify bitrate cutoff, files with a current bitrate lower then this will not be transcoded.
\\n Rate is in kbps. \\n Rate is in kbps.
@ -65,7 +70,7 @@ function plugin(file, librarySettings, inputs) {
let convertAudio = false; let convertAudio = false;
let convertVideo = false; let convertVideo = false;
let extraArguments = ''; let extraArguments = '';
// 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 += 'Plugin has not been configured, please configure required options. Skipping this plugin. \n'; response.infoLog += 'Plugin has not been configured, please configure required options. Skipping this plugin. \n';
@ -80,23 +85,20 @@ function plugin(file, librarySettings, inputs) {
return response; return response;
} }
const os = require('os'); // VIDEO SECTION
let bitRateMultiplier = 1.00;
let videoIdx = -1;
let willBeResized = false;
let videoOptions = '-map 0:v -c:v copy ';
// VIDEO SECTION // video options
// hevc, 1080, false - do nothing
let bitRateMultiplier = 1.00; // hevc, not 1080 - do nothing
let videoIdx = -1; // hevc, 1080, true - resize, mult 0.5
let willBeResized = false; // not hevc, 1080, true - resize, mult 0.25
let videoOptions = `-map 0:v -c:v copy `; // not hevc, 1080, false - no resize, mult 0.5
// not hevc, not 1080 - no resize, mult 0.5
// video options
// hevc, 1080, false - do nothing
// hevc, not 1080 - do nothing
// hevc, 1080, true - resize, mult 0.5
// not hevc, 1080, true - resize, mult 0.25
// not hevc, 1080, false - no resize, mult 0.5
// not hevc, not 1080 - no resize, mult 0.5
// Go through each stream in the file. // Go through each stream in the file.
for (let i = 0; i < file.ffProbeData.streams.length; i++) { for (let i = 0; i < file.ffProbeData.streams.length; i++) {
@ -104,44 +106,50 @@ let videoOptions = `-map 0:v -c:v copy `;
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. // 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. // 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' ) { if (file.ffProbeData.streams[i].codec_name === 'mjpeg' || file.ffProbeData.streams[i].codec_name === 'png') {
extraArguments += `-map -v:${videoIdx} `; extraArguments += `-map -v:${videoIdx} `;
convertVideo = true; } convertVideo = true;
/* // no video conversion if: hevc, 1080, false OR hevc, not 1080 }
if (file.ffProbeData.streams[i].codec_name === 'hevc' /* // no video conversion if: hevc, 1080, false OR hevc, not 1080
&& ((file.video_resolution === '1080p' && inputs.resize === 'no' ) || (file.video_resolution !== '1080p' ))) { if (file.ffProbeData.streams[i].codec_name === 'hevc'
&& ((file.video_resolution === '1080p' && inputs.resize === 'no' ) || (file.video_resolution !== '1080p' ))) {
convertVideo = false; } */ convertVideo = false; } */
// no video conversion if: hevc, 1080, false // no video conversion if: hevc, 1080, false
if (file.ffProbeData.streams[i].codec_name === 'hevc' && file.ffProbeData.streams[i].width > 1800 && file.ffProbeData.streams[i].width < 2000 && inputs.resize === 'no' ) { if (file.ffProbeData.streams[i].codec_name === 'hevc' && file.ffProbeData.streams[i].width > 1800 && file.ffProbeData.streams[i].width < 2000 && inputs.resize === 'no') {
convertVideo = false; } convertVideo = false;
// no video conversion if: hevc, not 1080 }
if (file.ffProbeData.streams[i].codec_name === 'hevc' && (file.ffProbeData.streams[i].width < 1800 || file.ffProbeData.streams[i].width > 2000)) { // no video conversion if: hevc, not 1080
convertVideo = false; } if (file.ffProbeData.streams[i].codec_name === 'hevc' && (file.ffProbeData.streams[i].width < 1800 || file.ffProbeData.streams[i].width > 2000)) {
// resize video if: hevc, 1080, true convertVideo = false;
if (file.ffProbeData.streams[i].codec_name === 'hevc' && file.ffProbeData.streams[i].width > 1800 && file.ffProbeData.streams[i].width < 2000 && inputs.resize === 'yes' ) { }
// resize video if: hevc, 1080, true
if (file.ffProbeData.streams[i].codec_name === 'hevc' && file.ffProbeData.streams[i].width > 1800 && file.ffProbeData.streams[i].width < 2000 && inputs.resize === 'yes') {
convertVideo = true; convertVideo = true;
willBeResized = true; willBeResized = true;
bitRateMultiplier = 0.7; } bitRateMultiplier = 0.7;
// resize video if: not hevc, 1080, true }
if (file.ffProbeData.streams[i].codec_name !== 'hevc' && file.ffProbeData.streams[i].width > 1800 && file.ffProbeData.streams[i].width < 2000 && inputs.resize === 'yes' ) { // resize video if: not hevc, 1080, true
if (file.ffProbeData.streams[i].codec_name !== 'hevc' && file.ffProbeData.streams[i].width > 1800 && file.ffProbeData.streams[i].width < 2000 && inputs.resize === 'yes') {
convertVideo = true; convertVideo = true;
willBeResized = true; willBeResized = true;
bitRateMultiplier = 0.4; } bitRateMultiplier = 0.4;
// no resize video if: not hevc, 1080, false }
if (file.ffProbeData.streams[i].codec_name !== 'hevc' && file.ffProbeData.streams[i].width > 1800 && file.ffProbeData.streams[i].width < 2000 && inputs.resize === 'no' ) { // no resize video if: not hevc, 1080, false
if (file.ffProbeData.streams[i].codec_name !== 'hevc' && file.ffProbeData.streams[i].width > 1800 && file.ffProbeData.streams[i].width < 2000 && inputs.resize === 'no') {
convertVideo = true; convertVideo = true;
bitRateMultiplier = 0.5; } bitRateMultiplier = 0.5;
// no resize video if: not hevc, not 1080 }
if (file.ffProbeData.streams[i].codec_name !== 'hevc' && file.ffProbeData.streams[i].width < 1800 ) { // no resize video if: not hevc, not 1080
if (file.ffProbeData.streams[i].codec_name !== 'hevc' && file.ffProbeData.streams[i].width < 1800) {
convertVideo = true; convertVideo = true;
bitRateMultiplier = 0.5; } bitRateMultiplier = 0.5;
} }
// Increment videoIdx.
videoIdx += 1;
} }
// Increment videoIdx.
videoIdx += 1;
}
// figure out final bitrate // figure out final bitrate
// Check if duration info is filled, if so times it by 0.0166667 to get time in minutes. // Check if duration info is filled, if so times it by 0.0166667 to get time in minutes.
// If not filled then get duration of stream 0 and do the same. // If not filled then get duration of stream 0 and do the same.
if (typeof file.meta.Duration !== 'undefined') { if (typeof file.meta.Duration !== 'undefined') {
@ -169,21 +177,21 @@ let videoOptions = `-map 0:v -c:v copy `;
response.infoLog += 'Target bitrate could not be calculated. Skipping this plugin. \n'; response.infoLog += 'Target bitrate could not be calculated. Skipping this plugin. \n';
return response; return response;
} }
// Check if inputs.bitrate cutoff has something entered. // Check if inputs.bitrate cutoff has something entered.
// (Entered means user actually wants something to happen, empty would disable this). // (Entered means user actually wants something to happen, empty would disable this).
if (inputs.bitrate_cutoff !== '') { if (inputs.bitrate_cutoff !== '') {
// Checks if currentBitrate is below inputs.bitrate_cutoff // Checks if currentBitrate is below inputs.bitrate_cutoff
// If so then don't convert video. // If so then don't convert video.
if (currentBitrate <= inputs.bitrate_cutoff) { if (currentBitrate <= inputs.bitrate_cutoff) {
convertVideo = false; } convertVideo = false;
}
} }
// AUDIO SECTION
// AUDIO SECTION // Set up required variables.
let audioOptions = '-map 0:a -c:a copy ';
// Set up required variables.
let audioOptions = `-map 0:a -c:a copy `;
let audioIdx = 0; let audioIdx = 0;
let numberofAudioChannels = 0; let numberofAudioChannels = 0;
let has2Channels = false; let has2Channels = false;
@ -197,197 +205,194 @@ let videoOptions = `-map 0:v -c:v copy `;
let type8Channels = ''; let type8Channels = '';
let keepAudioIdx = -1; let keepAudioIdx = -1;
let keepIGuessAudioIdx = -1; // const keepIGuessAudioIdx = -1;
let encodeAudioIdx = -1; let encodeAudioIdx = -1;
let keepAudioStream = -1; let keepAudioStream = -1;
let encodeAudioStream = -1; let encodeAudioStream = -1;
let originalAudio = ''; let originalAudio = '';
// Go through each stream in the file. // Go through each stream in the file.
for (let 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') {
numberofAudioChannels += 1; numberofAudioChannels += 1;
if (file.ffProbeData.streams[i].channels === 2 && has2Channels === false) { if (file.ffProbeData.streams[i].channels === 2 && has2Channels === false) {
has2Channels = true; has2Channels = true;
lang2Channels = file.ffProbeData.streams[i].tags.language.toLowerCase(); lang2Channels = file.ffProbeData.streams[i].tags.language.toLowerCase();
type2Channels = file.ffProbeData.streams[i].codec_name.toLowerCase(); type2Channels = file.ffProbeData.streams[i].codec_name.toLowerCase();
} }
if (file.ffProbeData.streams[i].channels === 6 && has6Channels === false) { if (file.ffProbeData.streams[i].channels === 6 && has6Channels === false) {
has6Channels = true; has6Channels = true;
lang6Channels = file.ffProbeData.streams[i].tags.language.toLowerCase(); lang6Channels = file.ffProbeData.streams[i].tags.language.toLowerCase();
type6Channels = file.ffProbeData.streams[i].codec_name.toLowerCase(); type6Channels = file.ffProbeData.streams[i].codec_name.toLowerCase();
} }
if (file.ffProbeData.streams[i].channels === 8 && has8Channels === false) { if (file.ffProbeData.streams[i].channels === 8 && has8Channels === false) {
has8Channels = true; has8Channels = true;
lang8Channels = file.ffProbeData.streams[i].tags.language.toLowerCase(); lang8Channels = file.ffProbeData.streams[i].tags.language.toLowerCase();
type8Channels = file.ffProbeData.streams[i].codec_name.toLowerCase(); type8Channels = file.ffProbeData.streams[i].codec_name.toLowerCase();
} }
} }
} catch (err) { } catch (err) {
// Error // Error
} }
} }
// Are we processing for 6 channels?
// Are we processing for 6 channels? if (inputs.audio_channels === 6) {
if (inputs.audio_channels == 6) { audioIdx = -1;
audioIdx = -1; for (let i = 0; i < file.ffProbeData.streams.length; i++) {
for (let i = 0; i < file.ffProbeData.streams.length; i++) { try {
try { if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio') {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio') { audioIdx += 1;
audioIdx += 1; if (file.ffProbeData.streams[i].tags.language.toLowerCase() === 'eng' || file.ffProbeData.streams[i].tags.language.toLowerCase() === 'und') {
if (file.ffProbeData.streams[i].tags.language.toLowerCase() === 'eng' || file.ffProbeData.streams[i].tags.language.toLowerCase() === 'und') { if (file.ffProbeData.streams[i].channels === 6) {
if (file.ffProbeData.streams[i].channels == 6 ) { if (file.ffProbeData.streams[i].codec_name.toLowerCase() === 'ac3') {
if (file.ffProbeData.streams[i].codec_name.toLowerCase() === 'ac3') { // response.infoLog += `Found 6 channel audio in proper language and codec, audio stream ${audioIdx}\n`;
//response.infoLog += `Found 6 channel audio in proper language and codec, audio stream ${audioIdx}\n`; if (keepAudioIdx === -1) {
if (keepAudioIdx === -1) { keepAudioIdx = audioIdx;
keepAudioIdx = audioIdx; keepAudioStream = i;
keepAudioStream = i;} }
} else { } else if (encodeAudioIdx === -1) {
//response.infoLog += `Found 6 channel audio in proper language, need to re-encode, audio stream ${audioIdx}\n`; // response.infoLog += `Found 6 channel audio in proper language, need to re-encode, audio stream ${audioIdx}\n`;
if (encodeAudioIdx === -1) { encodeAudioIdx = audioIdx;
encodeAudioIdx = audioIdx; encodeAudioStream = i;
encodeAudioStream = i;} }
}} }
if (file.ffProbeData.streams[i].channels > 6 ) { if (file.ffProbeData.streams[i].channels > 6) {
//response.infoLog += `Found existing multi-channel audio in proper language, need to re-encode, audio stream ${audioIdx}\n`; // response.infoLog += `Found existing multi-channel audio in proper language, need to re-encode, audio stream ${audioIdx}\n`;
if (encodeAudioIdx === -1) { if (encodeAudioIdx === -1) {
encodeAudioIdx = audioIdx; encodeAudioIdx = audioIdx;
encodeAudioStream = i;} encodeAudioStream = i;
} }
}
} }
} }
} catch (err) { } catch (err) {
// Error // Error
}
} }
} if (keepAudioIdx === -1 && encodeAudioIdx === -1) { // didn't find any 5.1 or better audio streams in proper language, defaulting to using 2 channels
if (keepAudioIdx === -1 && encodeAudioIdx === -1) { // didn't find any 5.1 or better audio streams in proper language, defaulting to using 2 channels // eslint-disable-next-line no-param-reassign
inputs.audio_channels = '2';} inputs.audio_channels = '2';
}
// Are we processing for 2 channels?
if (inputs.audio_channels == 2) {
audioIdx = -1;
for (let i = 0; i < file.ffProbeData.streams.length; i++) {
try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio') {
audioIdx += 1;
if (file.ffProbeData.streams[i].tags.language.toLowerCase() === 'eng' || file.ffProbeData.streams[i].tags.language.toLowerCase() === 'und') {
if (file.ffProbeData.streams[i].channels == 2 ) {
if (file.ffProbeData.streams[i].codec_name.toLowerCase() === 'aac' || file.ffProbeData.streams[i].codec_name.toLowerCase() === 'ac3') {
//response.infoLog += `Found 2 channel audio in proper language and codec, audio stream ${audioIdx}\n`;
if (keepAudioIdx === -1) {
keepAudioIdx = audioIdx;
keepAudioStream = i;}
} else {
//response.infoLog += `Found 2 channel audio in proper language, need to re-encode, audio stream ${audioIdx}\n`;
if (encodeAudioIdx === -1) {
encodeAudioIdx = audioIdx;
encodeAudioStream = i;}
}
} else {
//response.infoLog += `Found existing multi-channel audio in proper language, need to re-encode, audio stream ${audioIdx}\n`;
if (encodeAudioIdx === -1) {
encodeAudioIdx = audioIdx;
encodeAudioStream = i;}
}
}
// response.infoLog += `a ${audioIdx}. k ${keepAudioIdx}. e ${encodeAudioIdx}\n `;
}
} catch (err) {
// Error
} }
} }
}
// Are we processing for 2 channels?
if (inputs.audio_channels === 2) {
audioIdx = -1;
for (let i = 0; i < file.ffProbeData.streams.length; i++) {
try {
if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'audio') {
audioIdx += 1;
if (file.ffProbeData.streams[i].tags.language.toLowerCase() === 'eng' || file.ffProbeData.streams[i].tags.language.toLowerCase() === 'und') {
if (file.ffProbeData.streams[i].channels === 2) {
if (file.ffProbeData.streams[i].codec_name.toLowerCase() === 'aac' || file.ffProbeData.streams[i].codec_name.toLowerCase() === 'ac3') {
// response.infoLog += `Found 2 channel audio in proper language and codec, audio stream ${audioIdx}\n`;
if (keepAudioIdx === -1) {
keepAudioIdx = audioIdx;
keepAudioStream = i;
}
} else if (encodeAudioIdx === -1) {
// response.infoLog += `Found 2 channel audio in proper language, need to re-encode, audio stream ${audioIdx}\n`;
encodeAudioIdx = audioIdx;
encodeAudioStream = i;
}
} else if (encodeAudioIdx === -1) {
// response.infoLog += `Found existing multi-channel audio in proper language, need to re-encode, audio stream ${audioIdx}\n`;
encodeAudioIdx = audioIdx;
encodeAudioStream = i;
}
}
// response.infoLog += `a ${audioIdx}. k ${keepAudioIdx}. e ${encodeAudioIdx}\n `;
}
} catch (err) {
// Error
}
}
}
let audioMessage = ''; let audioMessage = '';
// selecting channels to keep, only if 2 or 6 channels processed // selecting channels to keep, only if 2 or 6 channels processed
if (keepAudioIdx !== -1) { if (keepAudioIdx !== -1) {
//keep audio, exclude everything else // keep audio, exclude everything else
if (numberofAudioChannels !== 1) { if (numberofAudioChannels !== 1) {
convertAudio = true; convertAudio = true;
audioMessage += `keeping audio stream ${keepAudioIdx}.`; audioMessage += `keeping audio stream ${keepAudioIdx}.`;
audioOptions = `-map 0:a:${keepAudioIdx} -c:a copy `; audioOptions = `-map 0:a:${keepAudioIdx} -c:a copy `;
originalAudio += `${file.ffProbeData.streams[keepAudioStream].channels} channel ${file.ffProbeData.streams[keepAudioStream].codec_name} --> ${inputs.audio_channels} channel ac3`;} originalAudio += `${file.ffProbeData.streams[keepAudioStream].channels} channel ${file.ffProbeData.streams[keepAudioStream].codec_name} --> ${inputs.audio_channels} channel ac3`;
}
} else if (encodeAudioIdx !== -1) {
// encode this audio
convertAudio = true;
audioMessage += `encoding audio stream ${encodeAudioIdx}. `;
audioOptions = `-map 0:a:${encodeAudioIdx} -c:a ac3 -ac ${inputs.audio_channels} `; // 2 or 6 channels encoding
originalAudio += `${file.ffProbeData.streams[encodeAudioStream].channels} channel ${file.ffProbeData.streams[encodeAudioStream].codec_name} --> ${inputs.audio_channels} channel ac3`;
} else { } else {
if (encodeAudioIdx !== -1) { // do not encode audio
// encode this audio convertAudio = false;
convertAudio = true; audioMessage += 'no audio to encode.';
audioMessage += `encoding audio stream ${encodeAudioIdx}. `;
audioOptions = `-map 0:a:${encodeAudioIdx} -c:a ac3 -ac ${inputs.audio_channels} `; // 2 or 6 channels encoding
originalAudio += `${file.ffProbeData.streams[encodeAudioStream].channels} channel ${file.ffProbeData.streams[encodeAudioStream].codec_name} --> ${inputs.audio_channels} channel ac3`;
} else {
// do not encode audio
convertAudio = false;
audioMessage += `no audio to encode.`;
}
} }
// test for whether the file needs to be processed - separate for video and audio convertAudio, convertVideo
// test for whether the file needs to be processed - separate for video and audio convertAudio, convertVideo
if (convertAudio === false && convertVideo === false) { // if nothing to do, exit if (convertAudio === false && convertVideo === false) { // if nothing to do, exit
response.infoLog += `File is processed already, nothing to do`; response.infoLog += 'File is processed already, nothing to do';
response.processFile = false; response.processFile = false;
return response; } return response;
}
// Generate ffmpeg command line arguments in total // Generate ffmpeg command line arguments in total
// few defaults // few defaults
response.preset = `, -sn `; response.preset = ', -sn ';
if (convertVideo === true) { if (convertVideo === true) {
// Set bitrateSettings variable using bitrate information calculated earlier. // Set bitrateSettings variable using bitrate information calculated earlier.
bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k ` bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k `
+ `-maxrate ${maximumBitrate}k -bufsize ${currentBitrate}k`; + `-maxrate ${maximumBitrate}k -bufsize ${currentBitrate}k`;
if (willBeResized === true) { if (willBeResized === true) {
extraArguments += `-filter:v scale=1280:-1 `; } extraArguments += '-filter:v scale=1280:-1 ';
}
if (os.platform() === 'darwin') { if (os.platform() === 'darwin') {
videoOptions = `-map 0:v -c:v hevc_videotoolbox -profile main `; videoOptions = '-map 0:v -c:v hevc_videotoolbox -profile main ';
} }
if (os.platform() === 'win32') { if (os.platform() === 'win32') {
videoOptions = `-map 0:v -c:v hevc_qsv -load_plugin hevc_hw `; videoOptions = '-map 0:v -c:v hevc_qsv -load_plugin hevc_hw ';
} }
} }
response.preset += `${videoOptions} ${bitrateSettings} ${extraArguments} ${audioOptions} `; response.preset += `${videoOptions} ${bitrateSettings} ${extraArguments} ${audioOptions} `;
let outputResolution = file.video_resolution; let outputResolution = file.video_resolution;
if (willBeResized === true) { if (willBeResized === true) {
outputResolution = '720p';} outputResolution = '720p';
}
if (convertVideo === false) { if (convertVideo === false) {
response.infoLog += `NOT converting video ${file.video_resolution}, ${file.video_codec_name}, bitrate = ${currentBitrate} \n`; response.infoLog += `NOT converting video ${file.video_resolution}, ${file.video_codec_name}, bitrate = ${currentBitrate} \n`;
} else { } else {
response.infoLog += `Converting video, `; response.infoLog += 'Converting video, ';
if (willBeResized === false ) { response.infoLog += `NOT `; } if (willBeResized === false) { response.infoLog += 'NOT '; }
response.infoLog += `resizing. ${file.video_resolution}, ${file.video_codec_name} --> ${outputResolution}, hevc. bitrate = ${currentBitrate} --> ${targetBitrate}, multiplier ${bitRateMultiplier}. \n`; response.infoLog += `resizing. ${file.video_resolution}, ${file.video_codec_name} --> ${outputResolution}, hevc. bitrate = ${currentBitrate} --> ${targetBitrate}, multiplier ${bitRateMultiplier}. \n`;
} }
if (convertAudio === true) { if (convertAudio === true) {
response.infoLog += `Converting audio, ${audioMessage} ${originalAudio}. \n`; response.infoLog += `Converting audio, ${audioMessage} ${originalAudio}. \n`;
} else { } else {
response.infoLog += `Not converting audio. \n`;} response.infoLog += 'Not converting audio. \n';
}
response.infoLog += `2 channels - ${lang2Channels} ${type2Channels} \n`; response.infoLog += `2 channels - ${lang2Channels} ${type2Channels} \n`;
response.infoLog += `6 channels - ${lang6Channels} ${type6Channels} \n`; response.infoLog += `6 channels - ${lang6Channels} ${type6Channels} \n`;
response.infoLog += `8 channels - ${lang8Channels} ${type8Channels} `; response.infoLog += `8 channels - ${lang8Channels} ${type8Channels} `;
response.processFile = true; response.processFile = true;
return response; return response;
} }

@ -34,7 +34,7 @@
// If the source video is less than this rate the script will either: // If the source video is less than this rate the script will either:
// Copy the existing stream, if the codec is hevc // Copy the existing stream, if the codec is hevc
// Transcode the stream to hevc using 80% of the original streams bitrate // Transcode the stream to hevc using 80% of the original streams bitrate
// It could probably be less but if the source is of low bitrate we dont want to compromise too much on the transcode // It could probably be less but if the source is of low bitrate we don<EFBFBD>t want to compromise too much on the transcode
// //
// If the source media bitrate is close, within 10%, of the target bitrate and the codec is hevc, it will copy instead of transcode to preserve quality // If the source media bitrate is close, within 10%, of the target bitrate and the codec is hevc, it will copy instead of transcode to preserve quality
// //
@ -53,7 +53,7 @@
// If the source audio is less than this rate the script will either: // If the source audio is less than this rate the script will either:
// Copy the existing stream, if the codec is aac // Copy the existing stream, if the codec is aac
// Transcode the stream to aac using 100% of the original streams bitrate // Transcode the stream to aac using 100% of the original streams bitrate
// It could probably be less but if the source is of low bitrate but, we dont want to compromise too much on the transcode // It could probably be less but if the source is of low bitrate but, we don<EFBFBD>t want to compromise too much on the transcode
// //
// Subtitles: // Subtitles:
// All are removed?? (TODO: ensure this is correct and mention the flag to keep them if desired) // All are removed?? (TODO: ensure this is correct and mention the flag to keep them if desired)
@ -761,7 +761,7 @@ function findMediaInfoItem(file, index) {
currMIOrder = file.mediaInfo.track[i].ID - 1; currMIOrder = file.mediaInfo.track[i].ID - 1;
} }
if (currMIOrder == index || currMIOrder == "0-" + index) { if (currMIOrder == index|| currMIOrder == "0-" + index) {
return i; return i;
} }
} }

@ -123,7 +123,7 @@ function plugin(file, librarySettings, inputs) {
response.preset = response.preset =
", -map_metadata -1 -map 0:V " + ", -map_metadata -1 -map 0:V " +
subMap + subMap +
" -map 0:a -c:v libx264 -preset medium -c:a aac -strict -2 " + " -map 0:a -c:v libx264 -preset " + preset + " -c:a aac -strict -2 " +
subType; subType;
response.reQueueAfter = true; response.reQueueAfter = true;
response.processFile = true; response.processFile = true;

@ -10,7 +10,7 @@ const details = () => ({
(requires TMDB api key) and English. (requires TMDB api key) and English.
'Native' languages are the ones that are listed on imdb. It does an API call to 'Native' languages are the ones that are listed on imdb. It does an API call to
Radarr, Sonarr to check if the movie/series exists and grabs the IMDB id. As a last resort it Radarr, Sonarr to check if the movie/series exists and grabs the IMDB id. As a last resort it
falls back to '[imdb-ttDIGITS] in the filename.`, falls back to the IMDB id in the filename.`,
Version: '1.00', Version: '1.00',
Link: 'https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/' Link: 'https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/'
+ 'Tdarr_Plugin_henk_Keep_Native_Lang_Plus_Eng.js', + 'Tdarr_Plugin_henk_Keep_Native_Lang_Plus_Eng.js',
@ -32,7 +32,7 @@ const details = () => ({
}, },
{ {
name: 'api_key', name: 'api_key',
tooltip: 'Input your TMDB api key here. (https://www.themoviedb.org/)', tooltip: 'Input your TMDB api (v3) key here. (https://www.themoviedb.org/)',
}, },
{ {
name: 'radarr_api_key', name: 'radarr_api_key',
@ -139,7 +139,7 @@ const tmdbApi = async (filename, api_key, axios) => {
if (filename.substr(0, 2) === 'tt') { if (filename.substr(0, 2) === 'tt') {
fileName = filename; fileName = filename;
} else { } else {
const idRegex = /\[imdb-(tt\d*)]/; const idRegex = /(tt\d{7,8})/;
const fileMatch = filename.match(idRegex); const fileMatch = filename.match(idRegex);
// eslint-disable-next-line prefer-destructuring // eslint-disable-next-line prefer-destructuring
if (fileMatch) fileName = fileMatch[1]; if (fileMatch) fileName = fileMatch[1];

@ -72,6 +72,20 @@ function details() {
\\nExample:\\n \\nExample:\\n
veryfast`, veryfast`,
}, },
{
name: 'sdDisabled',
tooltip: `Input "true" if you want to skip SD (480p and 576p) files
\\nExample:\\n
true`,
},
{
name: 'uhdDisabled',
tooltip: `Input "true" if you want to skip 4k (UHD) files
\\nExample:\\n
true`,
},
], ],
}; };
} }
@ -97,6 +111,22 @@ function plugin(file, librarySettings, inputs) {
} }
response.infoLog += '☑File is a video! \n'; response.infoLog += '☑File is a video! \n';
// check if the file is SD and sdDisable is enabled
// skip this plugin if so
if (['480p', '576p'].includes(file.video_resolution) && inputs.sdDisabled) {
response.processFile = false;
response.infoLog += '☒File is SD, not processing\n';
return response;
}
// check if the file is 4k and 4kDisable is enabled
// skip this plugin if so
if (file.video_resolution === '4KUHD' && inputs.uhdDisabled) {
response.processFile = false;
response.infoLog += '☒File is 4k/UHD, not processing\n';
return response;
}
// check if the file is already hevc // check if the file is already hevc
// it will not be transcoded if true and the plugin will be stopped immediately // it will not be transcoded if true and the plugin will be stopped immediately
for (let i = 0; i < file.ffProbeData.streams.length; i += 1) { for (let i = 0; i < file.ffProbeData.streams.length; i += 1) {

@ -1,62 +1,51 @@
/* eslint-disable */
function details() { function details() {
return { return {
id: "Tdarr_Plugin_x7ac_Remove_Closed_Captions", id: 'Tdarr_Plugin_x7ac_Remove_Closed_Captions',
Stage: "Pre-processing", Stage: 'Pre-processing',
Name: "Remove closed captions", Name: 'Remove burned closed captions',
Type: "Video", Type: 'Video',
Operation: "Remux", Operation: 'Remux',
Description: Description:
"[Contains built-in filter] If detected, closed captions (XDS,608,708) will be removed.", '[Contains built-in filter] If detected, closed captions (XDS,608,708) will be removed from streams.',
Version: "1.00", Version: '1.01',
Link: Link:
"https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_x7ac_Remove_Closed_Captions.js", 'https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_x7ac_Remove_Closed_Captions.js',
Tags: "pre-processing,ffmpeg,subtitle only", Tags: 'pre-processing,ffmpeg,subtitle only',
}; };
} }
function plugin(file) { function plugin(file) {
//Must return this object const response = {
var response = {
processFile: false, processFile: false,
preset: "", // eslint-disable-next-line no-useless-escape
container: ".mp4", preset: ',-map 0 -codec copy -bsf:v \"filter_units=remove_types=6\"',
container: `.${file.container}`,
handBrakeMode: false, handBrakeMode: false,
FFmpegMode: false, FFmpegMode: true,
reQueueAfter: true, reQueueAfter: true,
infoLog: "", infoLog: '',
}; };
if (file.fileMedium !== 'video') {
if (file.fileMedium !== "video") { response.infoLog += '☒File is not video \n';
console.log("File is not video");
response.infoLog += "☒File is not video \n";
response.processFile = false;
return response; return response;
} else {
if (file.hasClosedCaptions === true) {
response = {
processFile: true,
preset: ',-map 0 -codec copy -bsf:v "filter_units=remove_types=6"',
container: "." + file.container,
handBrakeMode: false,
FFmpegMode: true,
reQueueAfter: true,
infoLog: "☒This file has closed captions \n",
};
return response;
} else {
response.infoLog +=
"☑Closed captions have not been detected on this file \n";
response.processFile = false;
return response;
}
} }
} // Check if Closed Captions are set at file level
if (file.hasClosedCaptions) {
response.processFile = true;
response.infoLog += '☒This file has closed captions \n';
return response;
}
// If not, check for Closed Captions in the streams
const { streams } = file.ffProbeData;
streams.forEach((stream) => {
if (stream.closed_captions) {
response.processFile = true;
}
});
response.infoLog += response.processFile ? '☒This file has burnt closed captions \n'
: '☑Closed captions have not been detected on this file \n';
return response;
}
module.exports.details = details; module.exports.details = details;
module.exports.plugin = plugin; module.exports.plugin = plugin;

@ -1,9 +1,5 @@
/* eslint-disable */ /* eslint-disable */
module.exports.dependencies = [
'fs-extra',
];
module.exports.details = function details() { module.exports.details = function details() {
return { return {
id: "Tdarr_Plugin_z18s_rename_files_based_on_codec", id: "Tdarr_Plugin_z18s_rename_files_based_on_codec",
@ -11,7 +7,7 @@ module.exports.details = function details() {
Name: "Rename based on codec", Name: "Rename based on codec",
Type: "Video", Type: "Video",
Operation: "", Operation: "",
Description: `[Contains built-in filter]This plugin renames 264 files to 265 or vice versa depending on codec. \n\n`, Description: `[Contains built-in filter] If the filename contains '264' or '265', this plugin renames 264 files to 265 or vice versa depending on codec. \n\n`,
Version: "1.00", Version: "1.00",
Link: "", Link: "",
Tags: "post-processing", Tags: "post-processing",
@ -21,15 +17,6 @@ module.exports.details = function details() {
module.exports.plugin = function plugin(file, librarySettings, inputs) { module.exports.plugin = function plugin(file, librarySettings, inputs) {
try { try {
var fs = require("fs"); var fs = require("fs");
var path = require("path");
if (fs.existsSync(path.join(process.cwd(), "/npm"))) {
var rootModules = path.join(process.cwd(), "/npm/node_modules/");
} else {
var rootModules = "";
}
var fsextra = require(rootModules + "fs-extra");
var fileNameOld = file._id; var fileNameOld = file._id;
if ( if (
@ -39,6 +26,15 @@ module.exports.plugin = function plugin(file, librarySettings, inputs) {
file._id = file._id.replace("264", "265"); file._id = file._id.replace("264", "265");
file.file = file.file.replace("264", "265"); file.file = file.file.replace("264", "265");
} }
//added handling for files with AVC in the name instead of h264/x264
if (
file.ffProbeData.streams[0].codec_name == "hevc" &&
file._id.includes("AVC")
) {
file._id = file._id.replace("AVC", "HEVC");
file.file = file.file.replace("AVC", "HEVC");
}
if ( if (
file.ffProbeData.streams[0].codec_name == "h264" && file.ffProbeData.streams[0].codec_name == "h264" &&
@ -57,7 +53,7 @@ module.exports.plugin = function plugin(file, librarySettings, inputs) {
} }
if (fileNameOld != file._id) { if (fileNameOld != file._id) {
fsextra.moveSync(fileNameOld, file._id, { fs.renameSync(fileNameOld, file._id, {
overwrite: true, overwrite: true,
}); });

@ -1,7 +1,3 @@
module.exports.dependencies = [
'fs-extra',
];
module.exports.details = function details() { module.exports.details = function details() {
return { return {
id: 'Tdarr_Plugin_z18t_rename_files_based_on_codec_and_resolution', id: 'Tdarr_Plugin_z18t_rename_files_based_on_codec_and_resolution',
@ -20,17 +16,6 @@ module.exports.plugin = function plugin(file) {
try { try {
// eslint-disable-next-line global-require // eslint-disable-next-line global-require
const fs = require('fs'); const fs = require('fs');
// eslint-disable-next-line global-require
const path = require('path');
let rootModules;
if (fs.existsSync(path.join(process.cwd(), '/npm'))) {
rootModules = path.join(process.cwd(), '/npm/node_modules/');
} else {
rootModules = '';
}
// eslint-disable-next-line global-require,import/no-dynamic-require
const fsextra = require(`${rootModules}fs-extra`);
const fileNameOld = file._id; const fileNameOld = file._id;
const resolutions = { const resolutions = {
@ -133,7 +118,7 @@ module.exports.plugin = function plugin(file) {
file.file = fileName; file.file = fileName;
if (fileNameOld !== file._id) { if (fileNameOld !== file._id) {
fsextra.moveSync(fileNameOld, file._id, { fs.renameSync(fileNameOld, file._id, {
overwrite: true, overwrite: true,
}); });

@ -6,7 +6,7 @@ module.exports.dependencies = [
module.exports.details = function details() { module.exports.details = function details() {
return { return {
id: 'Tdarr_Plugin_aaaa_Pre_Proc_Example', id: 'Tdarr_Plugin_aaaa_Pre_Proc_Example',
Stage: 'Pre-processing', // Preprocessing or Post-processing. Determines when the plugin will be executed. Stage: 'Pre-processing', // Pre-processing or Post-processing. Determines when the plugin will be executed.
Name: 'No title meta data ', Name: 'No title meta data ',
Type: 'Video', Type: 'Video',
Operation: 'Transcode', Operation: 'Transcode',

@ -0,0 +1,37 @@
module.exports.details = function details() {
return {
id: 'Tdarr_Plugin_a9he_New_file_size_check',
Stage: 'Pre-processing',
Name: 'New file size check',
Type: 'Video',
Operation: 'Transcode',
Description: 'Give an error if new file is larger than the original \n\n',
Version: '1.00',
Link: '',
Tags: '',
};
};
module.exports.plugin = function plugin(file, librarySettings, inputs, otherArguments) {
// Must return this object at some point in the function else plugin will fail.
const response = {
processFile: false,
preset: '',
handBrakeMode: false,
FFmpegMode: true,
reQueueAfter: true,
infoLog: '',
};
const newSize = file.file_size;
const oldSize = otherArguments.originalLibraryFile.file_size;
if (newSize > oldSize) {
// Item will be errored in UI
throw new Error(`Error! New file has size ${newSize} which is larger than original file ${oldSize}`);
} else if (newSize < oldSize) {
response.infoLog += `New file has size ${newSize} which is smaller than original file ${oldSize}`;
}
// if file sizes are exactly the same then file has not been transcoded yet
return response;
};

@ -0,0 +1,35 @@
module.exports.details = function details() {
return {
id: 'Tdarr_Plugin_bbbc_Filter_Example',
Stage: 'Pre-processing',
Name: 'Filter resolutions',
Type: 'Video',
Operation: 'Filter',
Description: 'This plugin prevents processing files with specified resolutions \n\n',
Version: '1.00',
Link: '',
Tags: '',
};
};
module.exports.plugin = function plugin(file) {
const response = {
processFile: true,
infoLog: '',
};
const resolutionsToSkip = [
'1080p',
'4KUHD',
];
for (let i = 0; i < resolutionsToSkip.length; i += 1) {
if (file.video_resolution === resolutionsToSkip[i]) {
response.processFile = false;
response.infoLog += `Filter preventing processing. File has resolution ${resolutionsToSkip[i]}`;
break;
}
}
return response;
};

@ -12,8 +12,8 @@
}, },
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"lint": "eslint Community methods --ext js", "lint": "eslint Community methods examples --ext js",
"lint:fix": "eslint Community methods --ext js --fix" "lint:fix": "eslint Community methods examples --ext js --fix"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

Loading…
Cancel
Save