Modified the plugins to use the built in file object rather than

creating their own mediainfo and ffprobe objects.
make-only-subtitle-default
Zach Gelnett 5 years ago
parent 51e3461c04
commit 114c574716

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// Author: JarBinks, Zachg99, Jeff47 // Author: JarBinks, Zachg99, Jeff47
// Date: 08/19/2020 // Date: 04/11/2021
// //
// This is my attempt to create an all in one routine that will maintain my library in optimal format !!!!FOR MY REQUIREMENTS!!!! // This is my attempt to create an all in one routine that will maintain my library in optimal format !!!!FOR MY REQUIREMENTS!!!!
// Chances are very good you will need to make some changes to this routine and it's partner in order to make it work for you // Chances are very good you will need to make some changes to this routine and it's partner in order to make it work for you
@ -33,7 +33,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 dont 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
// //
@ -52,7 +52,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 dont 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)
@ -84,46 +84,67 @@
// Tdarr_Plugin_JB69_JBHEVCQSV_MinimalFile (JB - H265, AAC, MKV, bitrate optimized) // Tdarr_Plugin_JB69_JBHEVCQSV_MinimalFile (JB - H265, AAC, MKV, bitrate optimized)
// Tdarr_Plugin_JB69_JBHEVCQSZ_PostFix (JB - MKV Stats, Chapters, Audio Language) // Tdarr_Plugin_JB69_JBHEVCQSZ_PostFix (JB - MKV Stats, Chapters, Audio Language)
// //
// I am running the docker image provided for Tdarr, however there are some additions that must be added in order for the script to run // I am running the docker image provided for Tdarr
// This is to add mediainfo and mkvtoolnix because these are used to get more media info and update the file without running a transcode
// //
// Here is my docker config (I am running compose so yours might be a little different) // Here is my docker config (I am running compose so yours might be a little different)
// Tdarr: // tdarr_server:
// image: haveagitgat/tdarr_aio:qsv // container_name: tdarr_server
// container_name: tdarr // image: haveagitgat/tdarr:latest
// privileged: true
// restart: unless-stopped // restart: unless-stopped
// network_mode: host
// ports:
// - "8265:8265"
// environment: // environment:
// - PUID=${PUID} # default user id, defined in .env // - PUID=${PUID} # default user id, defined in .env
// - PGID=${PGID} # default group id, defined in .env // - PGID=${PGID} # default group id, defined in .env
// - TZ=${TZ} # timezone, defined in .env // - TZ=${TZ} # timezone, defined in .env
// - serverIP=tdarr_server #using internal docker networking. This should at least work when the nodes are on the same docker compose as the server
// - serverPort=8266
// - webUIPort=8265
// volumes:
// - ${ROOT}/tdarr/server:/app/server/Tdarr # Tdarr server files
// - ${ROOT}/tdarr/configs:/app/configs # config files - can be same as NODE (unless separate server)
// - ${ROOT}/tdarr/logs:/app/logs # Tdarr log files
// - ${ROOT}/tdarr/cache:/temp # Cache folder, Should be same path mapped on NODE
// - ${ROOT}/tdarr/testmedia:/home/Tdarr/testmedia # Should be same path mapped on NODE if using a test folder
// - ${ROOT}/tdarr/scripts:/home/Tdarr/scripts # my random way of saving script files
// - /volume1/video:/media # video library Should be same path mapped on NODE
// ports:
// - 8265:8265 #Exposed to access webui externally
// - 8266:8266 #Exposed to allow external nodes to reach the server
// logging:
// options:
// max-size: "2m"
// max-file: "3"
//
// tdarr_node:
// container_name: tdarr_node
// image: haveagitgat/tdarr_node:latest
// privileged: true
// restart: unless-stopped
// devices: // devices:
// - /dev/dri:/dev/dri // - /dev/dri:/dev/dri
// environment:
// - PUID=${PUID} # default user id, defined in .env
// - PGID=${PGID} # default group id, defined in .env
// - TZ=${TZ} # timezone, defined in .env
// - serverIP=192.168.x.x #container name of the server, should be modified if server is on another machine
// - serverPort=8266
// - nodeID=TDARRNODE_2
// - nodeIP=192.168.x.x #container name of the node
// - nodePort=9267 #not exposed via a "ports: " setting as the server/node communication is done on the internal docker network and can communicate on all ports
// volumes: // volumes:
// - "${ROOT}/complete:/home/Tdarr/Media:rw" // - ${ROOT}/tdarr/configs:/app/configs # config files - can be same as server (unless separate server)
// - /transtemp:/transtemp // - ${ROOT}/tdarr/logs:/app/logs # config files - can be same as server (unless separate server)
// - "${ROOT}/config/Tdarr:/home/Tdarr/Documents/Tdarr:rw" // - ${ROOT}/tdarr/testmedia:/home/Tdarr/testmedia # Should be same path mapped on server if using a test folder
// - "/etc/localtime:/etc/localtime:ro" // - ${ROOT}/tdarr/scripts:/home/Tdarr/scripts # my random way of saving script files
// // - ${ROOT}/tdarr/cache:/temp # Cache folder, Should be same path mapped on server
// I then connect to the docker container by using the following command // - /mnt/video:/media # video library Should be same path mapped on server
// sudo docker exec -it tdarr /bin/bash // ports:
// // - 9267:9267
// **THIS IS NOT NEEDED** if mediainfo and mkvtoolnix are already installed in the container. The pro_latest works fine without this. // logging:
// // options:
// Here is the script that I run after the docker container is up and running (This requires a couple of (y)es'es to complete) // max-size: "2m"
// // max-file: "3"
// //It is important to get mediainfo from a custom repository because it is a newer version that includes JSON output
// sudo apt-get install wget
// sudo wget https://mediaarea.net/repo/deb/repo-mediaarea_1.0-12_all.deb && sudo dpkg -i repo-mediaarea_1.0-12_all.deb && sudo apt-get update
// sudo apt-get install mediainfo
// //
// sudo wget -q -O - https://mkvtoolnix.download/gpg-pub-moritzbunkus.txt | sudo apt-key add -
// sudo sh -c 'echo "deb https://mkvtoolnix.download/ubuntu/ bionic main" >> /etc/apt/sources.list.d/bunkus.org.list'
// sudo sh -c 'echo "deb-src https://mkvtoolnix.download/ubuntu/ bionic main" >> /etc/apt/sources.list.d/bunkus.org.list'
// sudo apt update
// sudo apt install mkvtoolnix
// //
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
@ -135,7 +156,7 @@ function details() {
Type: "Video", Type: "Video",
Operation: "Transcode", Operation: "Transcode",
Description: "***You should not use this*** until you read the comments at the top of the code and understand how it works **this does alot** and is 1 of 2 routines you should to run **Part 1** \n", Description: "***You should not use this*** until you read the comments at the top of the code and understand how it works **this does alot** and is 1 of 2 routines you should to run **Part 1** \n",
Version: "1.6", Version: "2.0",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_JB69_JBHEVCQSV_MinimalFile.js", Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_JB69_JBHEVCQSV_MinimalFile.js",
Tags: "pre-processing,ffmpeg,video,audio,qsv h265,aac" Tags: "pre-processing,ffmpeg,video,audio,qsv h265,aac"
} }
@ -163,11 +184,13 @@ function plugin(file, librarySettings, inputs, otherArguments) {
//Video //Video
var targetvideocodec = "hevc"; //This is the basis of the routine, if you want to change it you probably want to use a different script var targetvideocodec = "hevc"; //This is the basis of the routine, if you want to change it you probably want to use a different script
var boluse10bit = true; //This will encode in 10 bit var boluse10bit = true; //This will encode in 10 bit
var targetframerate = 25; //Any frame rate greater than this will be adjusted
var minsizedifffortranscode = 1.2 //If the existing bitrate is this much more than the target bitrate it is ok to transcode, otherwise there might not be enough extra to get decent quality var minsizedifffortranscode = 1.2 //If the existing bitrate is this much more than the target bitrate it is ok to transcode, otherwise there might not be enough extra to get decent quality
var targetreductionforcodecswitchonly = 0.8; //When a video codec change happens and the source bitrate is lower than optimal, we still lower the bitrate by this since hevc is ok with a lower rate var targetreductionforcodecswitchonly = 0.8; //When a video codec change happens and the source bitrate is lower than optimal, we still lower the bitrate by this since hevc is ok with a lower rate
var maxvideoheight = 1080; //Any thing over this size, I.E. 4K, will be reduced to this var maxvideoheight = 2160; //Any thing over this size, I.E. 4K, will be reduced to this
var targetcodeccompression = 0.075; //This effects the target bitrate by assuming a compresion ratio var targetcodeccompression = 0.08; //This effects the target bitrate by assuming a compression ratio
//Since videos can have many widths and heights we need to convert to pixels (WxH) to understand what we are dealing with and set a minimal optimal bitrate to not go below //Since videos can have many widths and heights we need to convert to pixels (WxH) to understand what we are dealing with and set a minimal optimal bitrate to not go below
var minvideopixels4K = 6500000; var minvideopixels4K = 6500000;
@ -188,7 +211,7 @@ function plugin(file, librarySettings, inputs, otherArguments) {
var targetaudiochannels = 6; //Any thing above this number of channels will be reduced to it, because I cannot listen to it var targetaudiochannels = 6; //Any thing above this number of channels will be reduced to it, because I cannot listen to it
//Subtitles //Subtitles
var bolIncludeSubs = false; var bolIncludeSubs = true;
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
var proc = require("child_process"); var proc = require("child_process");
@ -196,16 +219,16 @@ function plugin(file, librarySettings, inputs, otherArguments) {
//Run MediaInfo and load the results it into an object //Run MediaInfo and load the results it into an object
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
response.infoLog += "Getting Media Info.\n"; //response.infoLog += "Getting Media Info.\n";
var objMedInfo = ""; //var objMedInfo = "";
objMedInfo = JSON.parse(proc.execSync('mediainfo "' + currentfilename + '" --output=JSON').toString()); //objMedInfo = JSON.parse(proc.execSync('mediainfo "' + currentfilename + '" --output=JSON').toString());
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
//Run ffprobe with full info and load the results it into an object //Run ffprobe with full info and load the results it into an object
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
response.infoLog += "Getting FFProbe Info.\n"; //response.infoLog += "Getting FFProbe Info.\n";
var objFFProbeInfo = ""; //var objFFProbeInfo = "";
objFFProbeInfo = JSON.parse(proc.execSync('ffprobe -v error -print_format json -show_format -show_streams -show_chapters "' + currentfilename + '"').toString()); //objFFProbeInfo = JSON.parse(proc.execSync('ffprobe -v error -print_format json -show_format -show_streams -show_chapters "' + currentfilename + '"').toString());
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
// response.processFile = false; // response.processFile = false;
@ -220,7 +243,7 @@ function plugin(file, librarySettings, inputs, otherArguments) {
//response.infoLog += "filename:" + require("crypto").createHash("md5").update(file._id).digest("hex") + "\n"; //response.infoLog += "filename:" + require("crypto").createHash("md5").update(file._id).digest("hex") + "\n";
//response.infoLog += "MediaInfo:" + JSON.stringify(objMedInfo, null, 4) + "\n"; //response.infoLog += "MediaInfo:" + JSON.stringify(objMedInfo, null, 4) + "\n";
//response.infoLog += "FFProbeInfo:" + JSON.stringify(objFFProbeInfo, null, 4) + "\n"; //response.infoLog += "FFProbeInfo:" + JSON.stringify(objFFProbeInfo, null, 4) + "\n";
//response.infoLog += "file.ffProbeData:" + JSON.stringify(file.ffProbeData, null, 4) + "\n"; //response.infoLog += "objFFProbeInfo:" + JSON.stringify(objFFProbeInfo, null, 4) + "\n";
//response.processFile = false; //response.processFile = false;
//return response; //return response;
@ -233,21 +256,21 @@ function plugin(file, librarySettings, inputs, otherArguments) {
} }
//If the file has already been processed we dont need to do more //If the file has already been processed we dont need to do more
// if (file.container == "mkv" && (objMedInfo.media.track[0].extra != undefined && objMedInfo.media.track[0].extra.JBDONEVERSION != undefined && objMedInfo.media.track[0].extra.JBDONEVERSION == "1")) { if (file.container == "mkv" && (file.mediaInfo.track[0].extra != undefined && file.mediaInfo.track[0].extra.JBDONEVERSION != undefined && file.mediaInfo.track[0].extra.JBDONEVERSION == "1")) {
// response.processFile = false; response.processFile = false;
// response.infoLog += "File already Processed! \n"; response.infoLog += "File already Processed! \n";
// return response; return response;
// } }
//If the existing container is mkv there is a possbility the stats were not updated during any previous transcode, lets make sure //If the existing container is mkv there is a possibility the stats were not updated during any previous transcode, lets make sure
if (file.container == "mkv") { if (file.container == "mkv") {
var datStats = Date.parse(new Date(70, 1).toISOString()); var datStats = Date.parse(new Date(70, 1).toISOString());
if (objFFProbeInfo.streams[0].tags != undefined && objFFProbeInfo.streams[0].tags["_STATISTICS_WRITING_DATE_UTC-eng"] != undefined) { if (file.ffProbeData.streams[0].tags != undefined && file.ffProbeData.streams[0].tags["_STATISTICS_WRITING_DATE_UTC-eng"] != undefined) {
datStats = Date.parse(objFFProbeInfo.streams[0].tags["_STATISTICS_WRITING_DATE_UTC-eng"] + " GMT"); datStats = Date.parse(file.ffProbeData.streams[0].tags["_STATISTICS_WRITING_DATE_UTC-eng"] + " GMT");
} }
if (objMedInfo.media.track[0].extra != undefined && objMedInfo.media.track[0].extra.JBDONEDATE != undefined) { if (file.mediaInfo.track[0].extra != undefined && file.mediaInfo.track[0].extra.JBDONEDATE != undefined) {
var JBDate = Date.parse(objMedInfo.media.track[0].extra.JBDONEDATE); var JBDate = Date.parse(file.mediaInfo.track[0].extra.JBDONEDATE);
response.infoLog += "JBDate: " + JBDate + ", StatsDate: " + datStats + "\n"; response.infoLog += "JBDate: " + JBDate + ", StatsDate: " + datStats + "\n";
if (datStats >= JBDate) { if (datStats >= JBDate) {
@ -271,14 +294,15 @@ function plugin(file, librarySettings, inputs, otherArguments) {
response.infoLog += "Error Updating Status Probably Bad file, A remux will probably fix, will continue\n"; response.infoLog += "Error Updating Status Probably Bad file, A remux will probably fix, will continue\n";
} }
response.infoLog += "Getting Stats Objects, again!\n"; response.infoLog += "Getting Stats Objects, again!\n";
objMedInfo = JSON.parse(proc.execSync('mediainfo "' + currentfilename + '" --output=JSON').toString()); //objMedInfo = JSON.parse(proc.execSync('mediainfo "' + currentfilename + '" --output=JSON').toString());
objFFProbeInfo = JSON.parse(proc.execSync('ffprobe -v error -print_format json -show_format -show_streams -show_chapters "' + currentfilename + '"').toString()); //objFFProbeInfo = JSON.parse(proc.execSync('ffprobe -v error -print_format json -show_format -show_streams -show_chapters "' + currentfilename + '"').toString());
} }
} }
//Logic Controls //Logic Controls
var bolscaleVideo = false; var bolscaleVideo = false;
var boltranscodeVideo = false; var boltranscodeVideo = false;
var bolchangeframerateVideo = false;
var optimalbitrate = 0; var optimalbitrate = 0;
var videonewwidth = 0; var videonewwidth = 0;
var bolSource10bit = false; var bolSource10bit = false;
@ -294,7 +318,7 @@ function plugin(file, librarySettings, inputs, otherArguments) {
var audioIdxBitrate = 0; var audioIdxBitrate = 0;
var boldosubs = false; var boldosubs = false;
var bolforcenosubs = true; var bolforcenosubs = false;
var boldosubsconvert = false; var boldosubsconvert = false;
var boldochapters = true; var boldochapters = true;
@ -308,22 +332,22 @@ function plugin(file, librarySettings, inputs, otherArguments) {
var strstreamType = ""; var strstreamType = "";
// Go through each stream in the file. // Go through each stream in the file.
for (var i = 0; i < objFFProbeInfo.streams.length; i++) { for (var i = 0; i < file.ffProbeData.streams.length; i++) {
strstreamType = objFFProbeInfo.streams[i].codec_type.toLowerCase(); strstreamType = file.ffProbeData.streams[i].codec_type.toLowerCase();
//Looking For Video //Looking For Video
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
if (strstreamType == "video") { if (strstreamType == "video") {
//First we need to check if it is included in the MediaInfo struture, it might not be (mjpeg??, others??) //First we need to check if it is included in the MediaInfo struture, it might not be (mjpeg??, others??)
var MILoc = findMediaInfoItem(objMedInfo, i); var MILoc = findMediaInfoItem(file, i);
if (MILoc > -1) { if (MILoc > -1) {
var streamheight = objFFProbeInfo.streams[i].height * 1; var streamheight = file.ffProbeData.streams[i].height * 1;
var streamwidth = objFFProbeInfo.streams[i].width * 1; var streamwidth = file.ffProbeData.streams[i].width * 1;
var streamFPS = objMedInfo.media.track[MILoc].FrameRate * 1; var streamFPS = file.mediaInfo.track[MILoc].FrameRate * 1;
var streamBR = objMedInfo.media.track[MILoc].BitRate * 1; var streamBR = file.mediaInfo.track[MILoc].BitRate * 1;
response.infoLog += "Video stream " + i + ":" + Math.floor(objFFProbeInfo.format.duration / 60) + ":" + objFFProbeInfo.streams[i].codec_name + ((bolSource10bit) ? "(10)" : ""); response.infoLog += "Video stream " + i + ":" + Math.floor(file.meta.Duration / 60) + ":" + file.ffProbeData.streams[i].codec_name + ((bolSource10bit) ? "(10)" : "");
response.infoLog += ":" + streamwidth + "x" + streamheight + "x" + streamFPS + ":" + streamBR + "bps \n"; response.infoLog += ":" + streamwidth + "x" + streamheight + "x" + streamFPS + ":" + streamBR + "bps \n";
if (videoIdxFirst == -1) { if (videoIdxFirst == -1) {
@ -333,11 +357,11 @@ function plugin(file, librarySettings, inputs, otherArguments) {
if (videoIdx == -1) { if (videoIdx == -1) {
videoIdx = i; videoIdx = i;
} else { } else {
var MILocC = findMediaInfoItem(objMedInfo,videoIdx); var MILocC = findMediaInfoItem(file,videoIdx);
var curstreamheight = objFFProbeInfo.streams[videoIdx].height * 1; var curstreamheight = file.ffProbeData.streams[videoIdx].height * 1;
var curstreamwidth = objFFProbeInfo.streams[videoIdx].width * 1; var curstreamwidth = file.ffProbeData.streams[videoIdx].width * 1;
var curstreamFPS = objMedInfo.media.track[MILocC].FrameRate * 1; var curstreamFPS = file.mediaInfo.track[MILocC].FrameRate * 1;
var curstreamBR = objMedInfo.media.track[MILocC].BitRate * 1; var curstreamBR = file.mediaInfo.track[MILocC].BitRate * 1;
//Only check here based on bitrate and video width //Only check here based on bitrate and video width
if (streamBR > curstreamBR && streamwidth >= curstreamwidth) { if (streamBR > curstreamBR && streamwidth >= curstreamwidth) {
@ -357,23 +381,19 @@ function plugin(file, librarySettings, inputs, otherArguments) {
//response.infoLog += JSON.stringify(objFFProbeInfo.streams[i]) + " \n"; //response.infoLog += JSON.stringify(objFFProbeInfo.streams[i]) + " \n";
//console.log("value of audio i: " + i + "; findmediainfoitem return value: " + findMediaInfoItem(objMedInfo, i)); audioChannels = file.ffProbeData.streams[i].channels * 1;
audioBitrate = file.mediaInfo.track[findMediaInfoItem(file, i)].BitRate * 1;
//console.log("streamorder: " + objMedInfo.media.track[i].StreamOrder);
audioChannels = objFFProbeInfo.streams[i].channels * 1;
audioBitrate = objMedInfo.media.track[findMediaInfoItem(objMedInfo, i)].BitRate * 1;
if (objFFProbeInfo.streams[i].tags != undefined && objFFProbeInfo.streams[i].tags.language == targetaudiolanguage) { if (file.ffProbeData.streams[i].tags != undefined && file.ffProbeData.streams[i].tags.language == targetaudiolanguage) {
response.infoLog += "Audio stream " + i + ":" + targetaudiolanguage + ":" + objFFProbeInfo.streams[i].codec_name + ":" + audioChannels + ":" + audioBitrate + "bps:"; response.infoLog += "Audio stream " + i + ":" + targetaudiolanguage + ":" + file.ffProbeData.streams[i].codec_name + ":" + audioChannels + ":" + audioBitrate + "bps:";
if (audioIdx == -1) { if (audioIdx == -1) {
response.infoLog += "First Audio Stream \n"; response.infoLog += "First Audio Stream \n";
audioIdx = i; audioIdx = i;
} else { } else {
audioIdxChannels = objFFProbeInfo.streams[audioIdx].channels * 1; audioIdxChannels = file.ffProbeData.streams[audioIdx].channels * 1;
audioIdxBitrate = objMedInfo.media.track[findMediaInfoItem(objMedInfo, audioIdx)].BitRate; audioIdxBitrate = file.mediaInfo.track[findMediaInfoItem(file, audioIdx)].BitRate;
if (audioChannels > audioIdxChannels) { if (audioChannels > audioIdxChannels) {
response.infoLog += "More Audio Channels \n"; response.infoLog += "More Audio Channels \n";
@ -384,14 +404,14 @@ function plugin(file, librarySettings, inputs, otherArguments) {
} }
} }
} else { } else {
response.infoLog += "Audio stream " + i + ":???:" + objFFProbeInfo.streams[i].codec_name + ":" + audioChannels + ":" + audioBitrate + "bps:"; response.infoLog += "Audio stream " + i + ":???:" + file.ffProbeData.streams[i].codec_name + ":" + audioChannels + ":" + audioBitrate + "bps:";
if (audioIdxOther == -1) { if (audioIdxOther == -1) {
response.infoLog += "First Audio Stream \n"; response.infoLog += "First Audio Stream \n";
audioIdxOther = i; audioIdxOther = i;
} else { } else {
audioIdxChannels = objFFProbeInfo.streams[audioIdxOther].channels * 1; audioIdxChannels = file.ffProbeData.streams[audioIdxOther].channels * 1;
audioIdxBitrate = objMedInfo.media.track[findMediaInfoItem(objMedInfo, audioIdxOther)].BitRate; audioIdxBitrate = file.mediaInfo.track[findMediaInfoItem(file, audioIdxOther)].BitRate;
if (audioChannels > audioIdxChannels) { if (audioChannels > audioIdxChannels) {
response.infoLog += "More Audio Channels \n"; response.infoLog += "More Audio Channels \n";
@ -408,9 +428,10 @@ function plugin(file, librarySettings, inputs, otherArguments) {
//Looking For Subtitles //Looking For Subtitles
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
if (!bolforcenosubs && !boldosubs && (strstreamType == "text" || strstreamType == "subtitle")) { if (!bolforcenosubs && !boldosubs && (strstreamType == "text" || strstreamType == "subtitle")) {
if (objMedInfo.media.track[findMediaInfoItem(objMedInfo, i)].CodecID != "S_TEXT/WEBVTT") { //A sub has an S_TEXT/WEBVTT codec, ffmpeg will fail with it //if (file.mediaInfo.track[findMediaInfoItem(file, i)].CodecID != "S_TEXT/WEBVTT") { //A sub has an S_TEXT/WEBVTT codec, ffmpeg will fail with it
if (file.mediaInfo.track[findMediaInfoItem(file, i)].CodecID != "S_TEXT/WEBVTT") { //A sub has an S_TEXT/WEBVTT codec, ffmpeg will fail with it
boldosubs = true; boldosubs = true;
if (objFFProbeInfo.streams[i].codec_name == "mov_text") { if (file.ffProbeData.streams[i].codec_name == "mov_text") {
boldosubsconvert = true; boldosubsconvert = true;
response.infoLog += "SubTitles Found (mov_text), will convert \n"; response.infoLog += "SubTitles Found (mov_text), will convert \n";
} else { } else {
@ -424,43 +445,28 @@ function plugin(file, librarySettings, inputs, otherArguments) {
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
} }
//If the file has already been processed we dont need to do more
if (file.container == "mkv" && objFFProbeInfo.streams[videoIdx].codec_name == targetvideocodec && (objMedInfo.media.track[0].extra != undefined && objMedInfo.media.track[0].extra.JBDONEVERSION != undefined && objMedInfo.media.track[0].extra.JBDONEVERSION == "1")) {
var audioIdxChk = 0;
if (audioIdx != -1)
audioIdxChk = audioIdx;
else audioIdxChk = audioIdxOther;
if (objFFProbeInfo.streams[audioIdxChk].codec_name == targetaudiocodec) {
response.processFile = false;
response.infoLog += "File already Processed! \n";
return response;
}
}
//return response; //return response;
// Go through chapters in the file looking for badness // Go through chapters in the file looking for badness
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
for (var i = 0; i < objFFProbeInfo.chapters.length; i++) { // Not processing chapters - fileobject doesn't seem to have the chapters section
//////////////////////////////////////////////////////////////////////////////////////////////////////
//for (var i = 0; i < objFFProbeInfo.chapters.length; i++) {
//Bad start times //Bad start times
if (objFFProbeInfo.chapters[i].start_time < 0) { // if (objFFProbeInfo.chapters[i].start_time < 0) {
boldochapters = false; // boldochapters = false;
break; //Dont need to continue because we know they are bad // break; //Dont need to continue because we know they are bad
} // }
//Duplicate start times //Duplicate start times
for (var x = 0; i < objFFProbeInfo.chapters.length; i++) { // for (var x = 0; i < objFFProbeInfo.chapters.length; i++) {
if (i != x && objFFProbeInfo.chapters[i].start_time == objFFProbeInfo.chapters[x].start_time) { // if (i != x && objFFProbeInfo.chapters[i].start_time == objFFProbeInfo.chapters[x].start_time) {
boldochapters = false; // boldochapters = false;
break; //Dont need to continue because we know they are bad // break; //Dont need to continue because we know they are bad
} // }
} // }
} //}
//Video Decision section //Video Decision section
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
@ -471,17 +477,24 @@ function plugin(file, librarySettings, inputs, otherArguments) {
} }
boltranscodeVideo = true; //We will assume we will be transcoding boltranscodeVideo = true; //We will assume we will be transcoding
var MILoc = findMediaInfoItem(objMedInfo, videoIdx); var MILoc = findMediaInfoItem(file, videoIdx);
var videoheight = objFFProbeInfo.streams[videoIdx].height * 1; var videoheight = file.ffProbeData.streams[videoIdx].height * 1;
var videowidth = objFFProbeInfo.streams[videoIdx].width * 1; var videowidth = file.ffProbeData.streams[videoIdx].width * 1;
var videoFPS = objMedInfo.media.track[MILoc].FrameRate * 1; var videoFPS = file.mediaInfo.track[MILoc].FrameRate * 1;
var videoBR = objMedInfo.media.track[MILoc].BitRate * 1; var videoBR = file.mediaInfo.track[MILoc].BitRate * 1;
if (objFFProbeInfo.streams[videoIdx].profile.includes("10")) { if (file.ffProbeData.streams[videoIdx].profile != undefined && file.ffProbeData.streams[videoIdx].profile.includes != undefined && file.ffProbeData.streams[videoIdx].profile.includes("10")) {
bolSource10bit = true; bolSource10bit = true;
} }
if (file.mediaInfo.track[MILoc].FrameRate_Mode == 'VFR')
videoFPS = 9999 //Source is Variable Frame rate but we will transcode to fixed
if (videoFPS > targetframerate) {
bolchangeframerateVideo = true; //Need to fix this it does not work :-(
}
//Lets see if we need to scal down the video size //Lets see if we need to scal down the video size
if (videoheight > maxvideoheight) { if (videoheight > maxvideoheight) {
bolscaleVideo = true; bolscaleVideo = true;
@ -492,7 +505,8 @@ function plugin(file, librarySettings, inputs, otherArguments) {
} }
//Figure out the desired bitrate //Figure out the desired bitrate
optimalvideobitrate = Math.floor((videoheight * videowidth * videoFPS) * targetcodeccompression); optimalvideobitrate = Math.floor((videoheight * videowidth * targetframerate) * targetcodeccompression);
response.infoLog += "Pre Video Calc: " + videoheight + ", " + videowidth + ", " + videoFPS + ", " + optimalvideobitrate + " \n"
//We need to check for a minimum bitrate //We need to check for a minimum bitrate
if ((videoheight * videowidth) > minvideopixels4K && optimalvideobitrate < minvideopixels4K) { if ((videoheight * videowidth) > minvideopixels4K && optimalvideobitrate < minvideopixels4K) {
@ -510,24 +524,24 @@ function plugin(file, librarySettings, inputs, otherArguments) {
} }
//Check if it is already hvec, if not then we must transcode //Check if it is already hvec, if not then we must transcode
if (objFFProbeInfo.streams[videoIdx].codec_name != targetvideocodec) { if (file.ffProbeData.streams[videoIdx].codec_name != targetvideocodec) {
response.infoLog += "Video existing Codex is " + objFFProbeInfo.streams[videoIdx].codec_name + ((bolSource10bit) ? "(10)" : ""); response.infoLog += "Video existing Codex is " + file.ffProbeData.streams[videoIdx].codec_name + ((bolSource10bit) ? "(10)" : "");
response.infoLog += ", need to convert to " + targetvideocodec + ((boluse10bit) ? "(10)" : "") + " \n"; response.infoLog += ", need to convert to " + targetvideocodec + ((boluse10bit) ? "(10)" : "") + " \n";
if (objFFProbeInfo.streams[videoIdx].codec_name == "mpeg4") { if (file.ffProbeData.streams[videoIdx].codec_name == "mpeg4") {
boltranscodeSoftwareDecode = true; boltranscodeSoftwareDecode = true;
response.infoLog += "Video existing Codex is " + objFFProbeInfo.streams[videoIdx].codec_name + ", need to decode with software codec \n"; response.infoLog += "Video existing Codex is " + file.ffProbeData.streams[videoIdx].codec_name + ", need to decode with software codec \n";
} else if (objFFProbeInfo.streams[videoIdx].codec_name == "h264" && objFFProbeInfo.streams[videoIdx].profile.includes("10")) { } else if (file.ffProbeData.streams[videoIdx].codec_name == "h264" && file.ffProbeData.streams[videoIdx].profile.includes("10")) {
//If the source is 10 bit then we must software decode since qsv will not decode 264 10 bit?? //If the source is 10 bit then we must software decode since qsv will not decode 264 10 bit??
boltranscodeSoftwareDecode = true; boltranscodeSoftwareDecode = true;
response.infoLog += "Video existing Codex is " + objFFProbeInfo.streams[videoIdx].codec_name + " 10 bit, need to decode with software codec \n"; response.infoLog += "Video existing Codex is " + file.ffProbeData.streams[videoIdx].codec_name + " 10 bit, need to decode with software codec \n";
} }
} }
if (videoBR < (optimalvideobitrate * minsizedifffortranscode)) { if (videoBR < (optimalvideobitrate * minsizedifffortranscode)) {
//We need to be careful here are else we could produce a bad quality //We need to be careful here are else we could produce a bad quality
response.infoLog += "Low source bitrate! \n"; response.infoLog += "Low source bitrate! \n";
if (objFFProbeInfo.streams[videoIdx].codec_name == targetvideocodec) { if (file.ffProbeData.streams[videoIdx].codec_name == targetvideocodec) {
if (bolSource10bit == boluse10bit) { if (bolSource10bit == boluse10bit) {
response.infoLog += "Video existing Bitrate, " + videoBR + ", is close to target Bitrate, " + optimalvideobitrate + ", using existing stream \n"; response.infoLog += "Video existing Bitrate, " + videoBR + ", is close to target Bitrate, " + optimalvideobitrate + ", using existing stream \n";
boltranscodeVideo = false; boltranscodeVideo = false;
@ -547,6 +561,7 @@ function plugin(file, librarySettings, inputs, otherArguments) {
//boltranscodeVideo = true; //boltranscodeVideo = true;
response.infoLog += "Video existing Bitrate, " + videoBR + ", is higher than target, " + optimalvideobitrate + ", transcoding \n"; response.infoLog += "Video existing Bitrate, " + videoBR + ", is higher than target, " + optimalvideobitrate + ", transcoding \n";
} }
response.infoLog += "Post Video Calc: " + videoheight + ", " + videowidth + ", " + videoFPS + ", " + optimalvideobitrate + " \n"
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
//Audio Decision section //Audio Decision section
@ -562,14 +577,14 @@ function plugin(file, librarySettings, inputs, otherArguments) {
} }
} }
var audioBR = objMedInfo.media.track[findMediaInfoItem(objMedInfo, audioIdx)].BitRate * 1; var audioBR = file.mediaInfo.track[findMediaInfoItem(file, audioIdx)].BitRate * 1;
if (objFFProbeInfo.streams[audioIdx].channels > targetaudiochannels) { if (file.ffProbeData.streams[audioIdx].channels > targetaudiochannels) {
boldownmixAudio = true; boldownmixAudio = true;
audionewchannels = targetaudiochannels; audionewchannels = targetaudiochannels;
response.infoLog += "Audio existing Channels, " + objFFProbeInfo.streams[audioIdx].channels + ", is higher than target, " + targetaudiochannels + " \n"; response.infoLog += "Audio existing Channels, " + file.ffProbeData.streams[audioIdx].channels + ", is higher than target, " + targetaudiochannels + " \n";
} else { } else {
audionewchannels = objFFProbeInfo.streams[audioIdx].channels; audionewchannels = file.ffProbeData.streams[audioIdx].channels;
} }
var optimalaudiobitrate = audionewchannels * targetaudiobitrateperchannel; var optimalaudiobitrate = audionewchannels * targetaudiobitrateperchannel;
@ -581,16 +596,16 @@ function plugin(file, librarySettings, inputs, otherArguments) {
} }
//If the audio codec is not what we want then we should transcode //If the audio codec is not what we want then we should transcode
if (objFFProbeInfo.streams[audioIdx].codec_name != targetaudiocodec) { if (file.ffProbeData.streams[audioIdx].codec_name != targetaudiocodec) {
boltranscodeAudio = true; boltranscodeAudio = true;
response.infoLog += "Audio Codec, " + objFFProbeInfo.streams[audioIdx].codec_name + ", is different than target, " + targetaudiocodec + ", Changing \n"; response.infoLog += "Audio Codec, " + file.ffProbeData.streams[audioIdx].codec_name + ", is different than target, " + targetaudiocodec + ", Changing \n";
} }
//If the source bitrate is less than out target bitrate we should not ever go up //If the source bitrate is less than out target bitrate we should not ever go up
if (audioBR < optimalaudiobitrate) { if (audioBR < optimalaudiobitrate) {
response.infoLog += "Audio existing Bitrate, " + audioBR + ", is lower than target, " + optimalaudiobitrate + ", using existing "; response.infoLog += "Audio existing Bitrate, " + audioBR + ", is lower than target, " + optimalaudiobitrate + ", using existing ";
optimalaudiobitrate = audioBR; optimalaudiobitrate = audioBR;
if (objFFProbeInfo.streams[audioIdx].codec_name != targetaudiocodec) { if (file.ffProbeData.streams[audioIdx].codec_name != targetaudiocodec) {
response.infoLog += "rate"; response.infoLog += "rate";
}else{ }else{
response.infoLog += "stream"; response.infoLog += "stream";
@ -609,6 +624,7 @@ function plugin(file, librarySettings, inputs, otherArguments) {
var strtranscodevideotranscoding = " -c:v:0 hevc_vaapi "; var strtranscodevideotranscoding = " -c:v:0 hevc_vaapi ";
var strtranscodevideooptions = ' -vf "{0}" '; //Used to make the output 10bit, I think the quotes need to be this way for ffmpeg var strtranscodevideooptions = ' -vf "{0}" '; //Used to make the output 10bit, I think the quotes need to be this way for ffmpeg
var strtranscodevideoscaling = "w=-1:h=1080"; //Used when video is above our target of 1080 var strtranscodevideoscaling = "w=-1:h=1080"; //Used when video is above our target of 1080
var strtranscodeframerate = "fps={0}"; //Used to change the framerate to the target framerate
var strtranscodevideoformathw = "scale_vaapi="; //Used to make the output 10bit var strtranscodevideoformathw = "scale_vaapi="; //Used to make the output 10bit
var strtranscodevideoformat = "format={0}"; //Used to add filters to the hardware transcode var strtranscodevideoformat = "format={0}"; //Used to add filters to the hardware transcode
var strtranscodevideo10bit = "p010"; //Used to make the output 10bit var strtranscodevideo10bit = "p010"; //Used to make the output 10bit
@ -640,21 +656,31 @@ function plugin(file, librarySettings, inputs, otherArguments) {
if (boltranscodeVideo) { if (boltranscodeVideo) {
strFFcmd += strtranscodevideotranscoding; strFFcmd += strtranscodevideotranscoding;
if (bolscaleVideo || boluse10bit || boltranscodeSoftwareDecode) { if (bolscaleVideo || boluse10bit || boltranscodeSoftwareDecode || bolchangeframerateVideo) {
var stroptions = ""; var stroptions = "";
var strformat = ""; var strformat = "";
if (bolscaleVideo) { if (bolscaleVideo) {
stroptions += strtranscodevideoscaling; stroptions += strtranscodevideoscaling;
} }
var strChangeVideoRateString = "";
if (bolchangeframerateVideo) {
strChangeVideoRateString = strtranscodeframerate.replace("{0}",targetframerate) + ",";
}
if (strformat.length > 0) { if (strformat.length > 0) {
strformat += "="; strformat += "=";
} }
if (boluse10bit && !bolSource10bit) { if (boluse10bit && !bolSource10bit) {
strformat += strtranscodevideo10bit; strformat += strtranscodevideo10bit;
} }
if (!boluse10bit && bolSource10bit) { if (!boluse10bit && bolSource10bit) {
strformat += strtranscodevideo8bit; strformat += strtranscodevideo8bit;
} }
if (boltranscodeSoftwareDecode) { if (boltranscodeSoftwareDecode) {
if (bolSource10bit) { if (bolSource10bit) {
if (strformat.length > 0) { if (strformat.length > 0) {
@ -667,6 +693,7 @@ function plugin(file, librarySettings, inputs, otherArguments) {
} }
strformat += strtranscodevideoswdecode; strformat += strtranscodevideoswdecode;
} }
if (strformat.length > 0) { if (strformat.length > 0) {
if (stroptions.length > 0) { if (stroptions.length > 0) {
stroptions += ","; stroptions += ",";
@ -675,11 +702,10 @@ function plugin(file, librarySettings, inputs, otherArguments) {
} }
if (boltranscodeSoftwareDecode) { if (boltranscodeSoftwareDecode) {
strFFcmd += strtranscodevideooptions.replace("{0}",stroptions); strFFcmd += strtranscodevideooptions.replace("{0}",strChangeVideoRateString + stroptions);
} else { } else {
strFFcmd += strtranscodevideooptions.replace("{0}",strtranscodevideoformathw + stroptions); strFFcmd += strtranscodevideooptions.replace("{0}",strChangeVideoRateString + strtranscodevideoformathw + stroptions);
} }
} }
strFFcmd += strtranscodevideobitrate.replace("{0}",optimalvideobitrate); strFFcmd += strtranscodevideobitrate.replace("{0}",optimalvideobitrate);
@ -724,10 +750,17 @@ function plugin(file, librarySettings, inputs, otherArguments) {
return response; return response;
} }
function findMediaInfoItem(objMedInfo, index) { function findMediaInfoItem(file, index) {
for (var i = 0; i < objMedInfo.media.track.length; i++) { var currMIOrder = 0;
//console.log("streamorder: " + objMedInfo.media.track[i].StreamOrder);
if (objMedInfo.media.track[i].StreamOrder != null && (objMedInfo.media.track[i].StreamOrder == index || objMedInfo.media.track[i].StreamOrder == "0-" + index)) { for (var i = 0; i < file.mediaInfo.track.length; i++) {
if (file.mediaInfo.track[i].StreamOrder != null || file.mediaInfo.track[i].StreamOrder != undefined) {
currMIOrder = file.mediaInfo.track[i].StreamOrder;
} else {
currMIOrder = file.mediaInfo.track[i].ID - 1;
}
if (currMIOrder == index|| currMIOrder == "0-" + index) {
return i; return i;
} }
} }

@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// Author: JarBinks, Zachg99, Jeff47 // Author: JarBinks, Zachg99, Jeff47
// Date: 06/29/2020 // Date: 04/11/2021
// //
// This is my attempt to create an all in one routine that will maintain my library in optimal format !!!!FOR MY REQUIREMENTS!!!! // This is my attempt to create an all in one routine that will maintain my library in optimal format !!!!FOR MY REQUIREMENTS!!!!
// Chances are very good you will need to make some changes to this routine and it's partner in order to make it work for you // Chances are very good you will need to make some changes to this routine and it's partner in order to make it work for you
@ -84,44 +84,66 @@
// Tdarr_Plugin_JB69_JBHEVCQSV_MinimalFile (JB - H265, AAC, MKV, bitrate optimized) // Tdarr_Plugin_JB69_JBHEVCQSV_MinimalFile (JB - H265, AAC, MKV, bitrate optimized)
// Tdarr_Plugin_JB69_JBHEVCQSZ_PostFix (JB - MKV Stats, Chapters, Audio Language) // Tdarr_Plugin_JB69_JBHEVCQSZ_PostFix (JB - MKV Stats, Chapters, Audio Language)
// //
// I am running the docker image provided for Tdarr, however there are some additions that must be added in order for the script to run // I am running the docker image provided for Tdarr
// This is to add mediainfo and mkvtoolnix because these are used to get more media info and update the file without running a transcode
// //
// Here is my docker config (I am running compose so yours might be a little different) // Here is my docker config (I am running compose so yours might be a little different)
// Tdarr: // tdarr_server:
// image: haveagitgat/tdarr_aio:qsv // container_name: tdarr_server
// container_name: tdarr // image: haveagitgat/tdarr:latest
// privileged: true
// restart: unless-stopped // restart: unless-stopped
// network_mode: host
// ports:
// - "8265:8265"
// environment: // environment:
// - PUID=${PUID} # default user id, defined in .env // - PUID=${PUID} # default user id, defined in .env
// - PGID=${PGID} # default group id, defined in .env // - PGID=${PGID} # default group id, defined in .env
// - TZ=${TZ} # timezone, defined in .env // - TZ=${TZ} # timezone, defined in .env
// - serverIP=tdarr_server #using internal docker networking. This should at least work when the nodes are on the same docker compose as the server
// - serverPort=8266
// - webUIPort=8265
// volumes:
// - ${ROOT}/tdarr/server:/app/server/Tdarr # Tdarr server files
// - ${ROOT}/tdarr/configs:/app/configs # config files - can be same as NODE (unless separate server)
// - ${ROOT}/tdarr/logs:/app/logs # Tdarr log files
// - ${ROOT}/tdarr/cache:/temp # Cache folder, Should be same path mapped on NODE
// - ${ROOT}/tdarr/testmedia:/home/Tdarr/testmedia # Should be same path mapped on NODE if using a test folder
// - ${ROOT}/tdarr/scripts:/home/Tdarr/scripts # my random way of saving script files
// - /volume1/video:/media # video library Should be same path mapped on NODE
// ports:
// - 8265:8265 #Exposed to access webui externally
// - 8266:8266 #Exposed to allow external nodes to reach the server
// logging:
// options:
// max-size: "2m"
// max-file: "3"
//
// tdarr_node:
// container_name: tdarr_node
// image: haveagitgat/tdarr_node:latest
// privileged: true
// restart: unless-stopped
// devices: // devices:
// - /dev/dri:/dev/dri // - /dev/dri:/dev/dri
// environment:
// - PUID=${PUID} # default user id, defined in .env
// - PGID=${PGID} # default group id, defined in .env
// - TZ=${TZ} # timezone, defined in .env
// - serverIP=192.168.x.x #container name of the server, should be modified if server is on another machine
// - serverPort=8266
// - nodeID=TDARRNODE_2
// - nodeIP=192.168.x.x #container name of the node
// - nodePort=9267 #not exposed via a "ports: " setting as the server/node communication is done on the internal docker network and can communicate on all ports
// volumes: // volumes:
// - "${ROOT}/complete:/home/Tdarr/Media:rw" // - ${ROOT}/tdarr/configs:/app/configs # config files - can be same as server (unless separate server)
// - /transtemp:/transtemp // - ${ROOT}/tdarr/logs:/app/logs # config files - can be same as server (unless separate server)
// - "${ROOT}/config/Tdarr:/home/Tdarr/Documents/Tdarr:rw" // - ${ROOT}/tdarr/testmedia:/home/Tdarr/testmedia # Should be same path mapped on server if using a test folder
// - "/etc/localtime:/etc/localtime:ro" // - ${ROOT}/tdarr/scripts:/home/Tdarr/scripts # my random way of saving script files
// // - ${ROOT}/tdarr/cache:/temp # Cache folder, Should be same path mapped on server
// I then connect to the docker container by using the following command // - /mnt/video:/media # video library Should be same path mapped on server
// sudo docker exec -it tdarr /bin/bash // ports:
// // - 9267:9267
// Here is the script that I run after the docker container is up and running (This requires a couple of (y)es'es to complete) // logging:
// // options:
// //It is important to get mediainfo from a custom repository because it is a newer version that includes JSON output // max-size: "2m"
// sudo apt-get install wget // max-file: "3"
// sudo wget https://mediaarea.net/repo/deb/repo-mediaarea_1.0-12_all.deb && sudo dpkg -i repo-mediaarea_1.0-12_all.deb && sudo apt-get update
// sudo apt-get install mediainfo
//
// sudo wget -q -O - https://mkvtoolnix.download/gpg-pub-moritzbunkus.txt | sudo apt-key add -
// sudo sh -c 'echo "deb https://mkvtoolnix.download/ubuntu/ bionic main" >> /etc/apt/sources.list.d/bunkus.org.list'
// sudo sh -c 'echo "deb-src https://mkvtoolnix.download/ubuntu/ bionic main" >> /etc/apt/sources.list.d/bunkus.org.list'
// sudo apt update
// sudo apt install mkvtoolnix
// //
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
@ -133,7 +155,7 @@ function details() {
Type: "Video", Type: "Video",
Operation: "Transcode", Operation: "Transcode",
Description: "***You should not use this*** until you read the comments at the top of the code and understand how it works **this does alot** and is 2 of 2 routines you should to run **Part 2** \n", Description: "***You should not use this*** until you read the comments at the top of the code and understand how it works **this does alot** and is 2 of 2 routines you should to run **Part 2** \n",
Version: "1.1", Version: "2.0",
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_JB69_JBHEVCQSZ_PostFix.js", Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_JB69_JBHEVCQSZ_PostFix.js",
Tags: "post-processing,ffmpeg,video" Tags: "post-processing,ffmpeg,video"
} }
@ -165,20 +187,20 @@ function plugin(file, librarySettings, inputs) {
} }
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
response.infoLog += "Getting Media Info.\n"; //response.infoLog += "Getting Media Info.\n";
var objMedInfo = ""; //var objMedInfo = "";
objMedInfo = JSON.parse(require("child_process").execSync('mediainfo "' + currentfilename + '" --output=JSON').toString()); //objMedInfo = JSON.parse(require("child_process").execSync('mediainfo "' + currentfilename + '" --output=JSON').toString());
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
if (objMedInfo.media.track[0].extra == undefined || objMedInfo.media.track[0].extra.JBDONEVERSION == undefined || objMedInfo.media.track[0].extra.JBDONEVERSION != "1") { if (file.mediaInfo.track[0].extra == undefined || file.mediaInfo.track[0].extra.JBDONEVERSION == undefined || file.mediaInfo.track[0].extra.JBDONEVERSION != "1") {
response.infoLog += "File not processed by first routine! \n"; response.infoLog += "File not processed by first routine! \n";
return response; return response;
} }
//Run ffprobe with full info and load the results it into an object //Run ffprobe with full info and load the results it into an object
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
response.infoLog += "Getting FFProbe Info.\n"; //response.infoLog += "Getting FFProbe Info.\n";
var objFFProbeInfo = ""; //var objFFProbeInfo = "";
objFFProbeInfo = JSON.parse(require("child_process").execSync('ffprobe -v error -print_format json -show_format -show_streams -show_chapters "' + currentfilename + '"').toString()); //objFFProbeInfo = JSON.parse(require("child_process").execSync('ffprobe -v error -print_format json -show_format -show_streams -show_chapters "' + currentfilename + '"').toString());
////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////
var datStats = Date.parse(new Date(70, 1).toISOString()) var datStats = Date.parse(new Date(70, 1).toISOString())
@ -186,11 +208,12 @@ function plugin(file, librarySettings, inputs) {
datStats = Date.parse(file.ffProbeData.streams[0].tags["_STATISTICS_WRITING_DATE_UTC-eng"] + " GMT") datStats = Date.parse(file.ffProbeData.streams[0].tags["_STATISTICS_WRITING_DATE_UTC-eng"] + " GMT")
} }
if (objFFProbeInfo.chapters.length != 0) { //Not processing chapters for now
bolHasChapters = true //if (objFFProbeInfo.chapters.length != 0) {
} else { // bolHasChapters = true
response.infoLog += "No Chapters! \n" //} else {
} // response.infoLog += "No Chapters! \n"
//}
if (file.ffProbeData.streams[1].tags != undefined && file.ffProbeData.streams[1].tags.language != undefined && file.ffProbeData.streams[1].tags.language == "eng") { if (file.ffProbeData.streams[1].tags != undefined && file.ffProbeData.streams[1].tags.language != undefined && file.ffProbeData.streams[1].tags.language == "eng") {
bolAudioIsEng = true; bolAudioIsEng = true;
@ -198,8 +221,8 @@ function plugin(file, librarySettings, inputs) {
response.infoLog += "Audio not marked as English! \n"; response.infoLog += "Audio not marked as English! \n";
} }
if (objMedInfo.media.track[0].extra.JBDONEDATE != undefined) { if (file.mediaInfo.track[0].extra.JBDONEDATE != undefined) {
var JBDate = Date.parse(objMedInfo.media.track[0].extra.JBDONEDATE); var JBDate = Date.parse(file.mediaInfo.track[0].extra.JBDONEDATE);
response.infoLog += "JBDate:" + JBDate + ", StatsDate:" + datStats + "\n"; response.infoLog += "JBDate:" + JBDate + ", StatsDate:" + datStats + "\n";
if (datStats >= JBDate) { if (datStats >= JBDate) {
@ -239,7 +262,7 @@ function plugin(file, librarySettings, inputs) {
var intChapNum = 0; var intChapNum = 0;
var strChapNum = ""; var strChapNum = "";
for (var i = 0; i < objFFProbeInfo.format.duration; i += chapterlengthlong) { for (var i = 0; i < file.meta.Duration; i += chapterlengthlong) {
intChapNum += 1; intChapNum += 1;
strChapNum = String(intChapNum).padStart(2, '0'); strChapNum = String(intChapNum).padStart(2, '0');
@ -253,7 +276,7 @@ function plugin(file, librarySettings, inputs) {
intChapNum += 1; intChapNum += 1;
strChapNum = String(intChapNum).padStart(2, "0"); strChapNum = String(intChapNum).padStart(2, "0");
var timeString = new Date((Math.floor(objFFProbeInfo.format.duration) - 1) * 1000).toISOString().substr(11, 12); var timeString = new Date((Math.floor(file.meta.Duration) - 1) * 1000).toISOString().substr(11, 12);
strChapterFile += "CHAPTER" + strChapNum + "=" + timeString + "\n"; strChapterFile += "CHAPTER" + strChapNum + "=" + timeString + "\n";
strChapterFile += "CHAPTER" + strChapNum + "NAME=CHAPTER " + intChapNum + "\n"; strChapterFile += "CHAPTER" + strChapNum + "NAME=CHAPTER " + intChapNum + "\n";

Loading…
Cancel
Save