@ -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)' ,
@ -80,15 +85,12 @@ function plugin(file, librarySettings, inputs) {
return response ;
return response ;
}
}
const os = require ( 'os' ) ;
// VIDEO SECTION
// VIDEO SECTION
let bitRateMultiplier = 1.00 ;
let bitRateMultiplier = 1.00 ;
let videoIdx = - 1 ;
let videoIdx = - 1 ;
let willBeResized = false ;
let willBeResized = false ;
let videoOptions = ` -map 0:v -c:v copy ` ;
let videoOptions = '-map 0:v -c:v copy ' ;
// video options
// video options
// hevc, 1080, false - do nothing
// hevc, 1080, false - do nothing
@ -106,36 +108,42 @@ let videoOptions = `-map 0:v -c:v copy `;
// 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
/* / / no video conversion if : hevc , 1080 , false OR hevc , not 1080
if ( file . ffProbeData . streams [ i ] . codec _name === 'hevc'
if ( file . ffProbeData . streams [ i ] . codec _name === 'hevc'
&& ( ( file . video _resolution === '1080p' && inputs . resize === 'no' ) || ( file . video _resolution !== '1080p' ) ) ) {
&& ( ( 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
// 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 ) ) {
if ( file . ffProbeData . streams [ i ] . codec _name === 'hevc' && ( file . ffProbeData . streams [ i ] . width < 1800 || file . ffProbeData . streams [ i ] . width > 2000 ) ) {
convertVideo = false ; }
convertVideo = false ;
}
// resize video if: hevc, 1080, true
// 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' ) {
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
// 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' ) {
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
// 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' ) {
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
// no resize video if: not hevc, not 1080
if ( file . ffProbeData . streams [ i ] . codec _name !== 'hevc' && file . ffProbeData . streams [ i ] . width < 1800 ) {
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.
// Increment videoIdx.
videoIdx += 1 ;
videoIdx += 1 ;
@ -176,14 +184,14 @@ let videoOptions = `-map 0:v -c:v copy `;
// 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.
// Set up required variables.
let audioOptions = ` -map 0:a -c:a copy ` ;
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,7 +205,7 @@ 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 ;
@ -230,34 +238,34 @@ let videoOptions = `-map 0:v -c:v copy `;
}
}
}
}
// 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 ) {
@ -265,35 +273,35 @@ let videoOptions = `-map 0:v -c:v copy `;
}
}
}
}
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
inputs . audio _channels = '2' ; }
// eslint-disable-next-line no-param-reassign
inputs . audio _channels = '2' ;
}
}
}
// Are we processing for 2 channels?
// Are we processing for 2 channels?
if ( inputs . audio _channels == 2 ) {
if ( inputs . audio _channels = == 2 ) {
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 == 2 ) {
if ( file . ffProbeData . streams [ i ] . channels == = 2 ) {
if ( file . ffProbeData . streams [ i ] . codec _name . toLowerCase ( ) === 'aac' || file . ffProbeData . streams [ i ] . codec _name . toLowerCase ( ) === 'ac3' ) {
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`;
// response.infoLog += `Found 2 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 2 channel audio in proper language, need to re-encode, audio stream ${audioIdx}\n`;
// response.infoLog += `Found 2 channel audio in proper language, need to re-encode, audio stream ${audioIdx}\n`;
if ( encodeAudioIdx === - 1 ) {
encodeAudioIdx = audioIdx ;
encodeAudioIdx = audioIdx ;
encodeAudioStream = i ; }
encodeAudioStream = i ;
}
}
} else {
} else if ( encodeAudioIdx === - 1 ) {
// 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 ) {
encodeAudioIdx = audioIdx ;
encodeAudioIdx = audioIdx ;
encodeAudioStream = i ; }
encodeAudioStream = i ;
}
}
}
}
// response.infoLog += `a ${audioIdx}. k ${keepAudioIdx}. e ${encodeAudioIdx}\n `;
// response.infoLog += `a ${audioIdx}. k ${keepAudioIdx}. e ${encodeAudioIdx}\n `;
@ -304,7 +312,6 @@ let videoOptions = `-map 0:v -c:v copy `;
}
}
}
}
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
@ -315,9 +322,9 @@ let videoOptions = `-map 0:v -c:v copy `;
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 ) {
} else if ( encodeAudioIdx !== - 1 ) {
// encode this audio
// encode this audio
convertAudio = true ;
convertAudio = true ;
audioMessage += ` encoding audio stream ${ encodeAudioIdx } . ` ;
audioMessage += ` encoding audio stream ${ encodeAudioIdx } . ` ;
@ -326,26 +333,22 @@ let videoOptions = `-map 0:v -c:v copy `;
} else {
} else {
// do not encode audio
// do not encode audio
convertAudio = false ;
convertAudio = false ;
audioMessage += ` no audio to encode. ` ;
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.
@ -353,36 +356,38 @@ let videoOptions = `-map 0:v -c:v copy `;
+ ` -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 ` ;