@ -9,8 +9,9 @@ function details() {
Type : "Video" ,
Operation : "Transcode" ,
Description : ` Uses iiDrakeii's filter, and crops video files when letterboxing is detected. \n This uses the FFMPEG NVENC transcoding(hw). \n If a file is 4K it will be scaled down to 1080p. \n Now with user definable bitrates!(since 1.104 beta) \n Created by @control#0405 ` ,
Version : "1. 4 ",
Version : "1. 3 ",
Link : "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_e5c3_CnT_Remove_Letterbox.js" ,
Tags : 'pre-processing,ffmpeg,nvenc h265,configurable,h265,video only' ,
Inputs : [
{
name : 'bitrate' ,
@ -20,13 +21,12 @@ function details() {
name : 'container' ,
tooltip : ` Enter the output container of the new file. \\ n Default: .mkv \\ nExample: \\ n.mkv `
} ,
] ,
Tags : 'pre-processing,video only,ffmpeg,configurable' ,
]
}
}
function plugin ( file , librarySettings , inputs , otherArguments ) {
if ( inputs . bitrate == "" || inputs . special == 'undefined' ) {
if ( inputs . bitrate == "" || inputs . bitrate == 'undefined' ) {
var min _bitrate = 6600 ;
var avg _rate = 3000 ;
var max _rate = 6000 ;
@ -36,14 +36,6 @@ function plugin(file, librarySettings, inputs, otherArguments) {
var max _rate = inputs . bitrate * 2 ;
}
var source = file . meta . SourceFile ; //source file
var stats = fs . statSync ( source ) ;
var size = stats [ "size" ] / 1000000000 ;
size = size . toFixed ( 2 ) ;
var decoder = decoder _string ( file ) ; //decoder, before the input
var encoder = encoder _string _full ( file , highres ( file ) , crop _decider ( file , create _crop _values ( file ) . crop _height ) . crop , avg _rate , max _rate ) ; //encoder
var process = 0 ; //decides if it should be processed
//default values that will be returned
var response = {
processFile : false ,
@ -57,12 +49,20 @@ function plugin(file, librarySettings, inputs, otherArguments) {
if ( inputs . container !== undefined ) {
response . container = inputs . container ;
console . log ( ` C hanged c ontainer to: ` + inputs . container ) ;
console . log ( ` C ontainer was set to: ` + inputs . container ) ;
}
var source = file . meta . SourceFile ; //source file
var stats = fs . statSync ( source ) ;
var size = stats [ "size" ] / 1000000000 ;
size = size . toFixed ( 2 ) ;
var decoder = decoder _string ( file ) ; //decoder, before the input
var encoder = encoder _string _full ( highres ( file ) , crop _decider ( file , generate _crop _values ( file , otherArguments ) . crop _height ) . crop , encoder _string ( file , avg _rate , max _rate , response . container ) ) ; //encoder
var process = 0 ; //decides if it should be processed
var returns = {
create _crop : create _crop _values ( file ) ,
crop : crop _decider ( file , create _crop _values ( file ) . crop _height ) ,
create _crop : gener ate_crop _values ( file , otherArguments ) ,
crop : crop _decider ( file , gener ate_crop _values ( file , otherArguments ) . crop _height ) ,
size : size _check ( file , min _bitrate )
}
@ -90,7 +90,7 @@ function plugin(file, librarySettings, inputs, otherArguments) {
log . resolution += ` ☒ - Resolution <= 1080p \n ` ;
}
if ( crop _decider ( file , cre ate_crop _values ( file ) . crop _height ) . crop != "0" ) {
if ( crop _decider ( file , gener ate_crop _values ( file , otherArguments ) . crop _height ) . crop != "0" ) {
process = 1 ;
}
}
@ -109,10 +109,6 @@ function plugin(file, librarySettings, inputs, otherArguments) {
} else if ( file . forceProcessing === true ) {
response . processFile = true ;
response . infoLog += ` Force processing! \n ` ;
} else if ( response . container !== ` . ` + file . container ) {
response . infoLog += ` Container is not correct \n Muxing to ${ response . container } ! \n ` ;
response . preset = ` ${ decoder } , -c copy ` ;
response . processFile = true ;
} else {
response . infoLog += ` Processing not necessary \n ` ;
}
@ -129,7 +125,7 @@ function highres(file) {
}
}
function cre ate_crop _values ( file ) {
function gener ate_crop _values ( file , otherArguments ) {
var source = file . meta . SourceFile ; //source file
var dir = file . meta . Directory ; //source directory
var sourcename = file . meta . FileName . substring ( 0 , file . meta . FileName . lastIndexOf ( "." ) ) ; //filename without extension
@ -142,11 +138,11 @@ function create_crop_values(file) {
//create crop value
if ( ! fs . existsSync ( ` ${ cropfile } ` ) ) {
returns . log += ` Creating crop values... \n ` ;
execSync ( otherArguments . ffmpegPath + ` -ss 300 -i \" ${ source } \" -frames:v 240 -vf cropdetect -f null - 2>&1 | awk \' /crop/ { print $ NF } \' | tail -240 > \" ${ cropfile } \" ` ) ;
execSync ( otherArguments . ffmpegPath + ` -ss 1200 -i \" ${ source } \" -frames:v 240 -vf cropdetect -f null - 2>&1 | awk \' /crop/ { print $ NF } \' | tail -240 >> \" ${ cropfile } \" ` ) ;
execSync ( ` ${ otherArguments . ffmpegPath } -ss 300 -i \" ${ source } \" -frames:v 240 -vf cropdetect -f null - 2>&1 | awk \' /crop/ { print $ NF } \' | tail -240 > \" ${ cropfile } \" ` ) ;
execSync ( ` ${ otherArguments . ffmpegPath } -ss 1200 -i \" ${ source } \" -frames:v 240 -vf cropdetect -f null - 2>&1 | awk \' /crop/ { print $ NF } \' | tail -240 >> \" ${ cropfile } \" ` ) ;
} else {
returns . log += ` Crop values already exist \n ` ;
}
}
//get data from copvalue.txt
var data = fs . readFileSync ( ` ${ cropfile } ` ) . toString ( ) . split ( "\n" ) ; //full data from cropvalue.txt
@ -154,9 +150,11 @@ function create_crop_values(file) {
//get height of the supposed cropped video
//var crop_height = parseInt(data[0].substring(10, 14));
for ( var c = 0 ; c < data . length ; c ++ ) {
if ( parseInt ( data [ c ] . substring ( 10 , 14 ) ) > returns . crop _height ) {
returns . crop _height = parseInt ( data [ c ] . substring ( 10 , 14 ) ) ;
returns . log += ` New cropheight: ${ parseInt ( data [ c ] . substring ( 10 , 14 ) ) } \n ` ;
crop = data [ c ] . split ( ":" ) ;
crop _height = Math . abs ( parseInt ( crop [ 1 ] ) ) ;
if ( crop _height > returns . crop _height ) {
returns . crop _height = crop _height ;
returns . log += ` New cropheight: ${ crop _height } \n ` ;
}
}
return returns ;
@ -303,7 +301,7 @@ function size_check(file, min_bitrate) {
return returns ;
}
function error _fix ( file ) {
function error _fix ( file , container ) {
var fix = {
sub _codec : 0 , //changes to 1 if unwanted codec is found
muxing : 0
@ -313,7 +311,7 @@ function error_fix(file) {
//these subtitle codecs don't fit in a mkv container
if ( file . ffProbeData . streams [ i ] . codec _name && file . ffProbeData . streams [ i ] . codec _type ) {
if ( file . ffProbeData . streams [ i ] . codec _name . toLowerCase ( ) == "eia_608" || file . ffProbeData . streams [ i ] . codec _name . toLowerCase ( ) == "mov_text" && file . ffProbeData . streams [ i ] . codec _type . toLowerCase .includes ( "sub" ) && response . container == '.mkv' ) {
if ( file . ffProbeData . streams [ i ] . codec _name . toLowerCase ( ) == "eia_608" || file . ffProbeData . streams [ i ] . codec _name . toLowerCase ( ) == "mov_text" && file . ffProbeData . streams [ i ] . codec _type . toLowerCase () .includes ( "sub" ) && container == '.mkv' ) {
fix . sub _codec = 1 ;
}
@ -327,9 +325,9 @@ function error_fix(file) {
return fix ;
}
function encoder _string ( file , avg _rate , max _rate ) {
function encoder _string ( file , avg _rate , max _rate , container ) {
var encoder = ` ` ; //encoder
var fix = error _fix ( file );
var fix = error _fix ( file , container );
var sub = ` ` ;
//tree for resolution : quality
@ -339,6 +337,8 @@ function encoder_string(file, avg_rate, max_rate) {
encoder += ` -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 26 -b:v ${ avg _rate / 2 } k -maxrate:v ${ max _rate / 2 } k ` ; //-qp 28
} else if ( file . video _resolution === "480p" || file . video _resolution === "576p" ) { //file will be encoded if the resolution is 480p or 576p
encoder += ` -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 26 -b:v ${ avg _rate / 4 } k -maxrate:v ${ max _rate / 4 } k ` ; //-qp 30
} else { //fallback option to 1080p quality
encoder += ` -pix_fmt p010le -rc:v vbr_hq -qmin 0 -cq:v 26 -b:v ${ avg _rate } k -maxrate:v ${ max _rate } k ` ; //-qp 26
}
encoder += ` -c:v hevc_nvenc -preset slow -rc-lookahead 32 -spatial_aq:v 1 -aq-strength:v 8 -a53cc 0 -dn ` ;
@ -363,14 +363,11 @@ function encoder_string(file, avg_rate, max_rate) {
if ( fix . muxing == 1 ) {
encoder += ` -max_muxing_queue_size 2048 ` ;
}
return encoder + ` -c:a copy ` + sub ;
}
function encoder _string _full ( file , highres , crop , avg _rate , max _rate ) {
var encoder = encoder _string ( file , avg _rate , max _rate ) ;
console . log ( ` crop filter: ` + crop )
function encoder _string _full ( highres , crop , encoder ) {
console . log ( ` crop filter: ` + crop ) ;
if ( highres == 1 && crop != "0" ) {
return crop + ` ,scale=-1:1920 ` + encoder ;
@ -383,5 +380,17 @@ function encoder_string_full(file, highres, crop, avg_rate, max_rate) {
}
}
function execCommand ( cmd ) {
const exec = require ( 'child_process' ) . exec ;
return new Promise ( ( resolve , reject ) => {
exec ( cmd , ( error , stdout , stderr ) => {
if ( error ) {
console . warn ( error ) ;
}
resolve ( stdout ? stdout : stderr ) ;
} ) ;
} ) ;
}
module . exports . details = details ;
module . exports . plugin = plugin ;