diff --git a/Collected/Martin_Plugin_001_send_discord_notification.js b/Collected/Martin_Plugin_001_send_discord_notification.js new file mode 100644 index 000000000..afa7a391a --- /dev/null +++ b/Collected/Martin_Plugin_001_send_discord_notification.js @@ -0,0 +1,71 @@ +const details = () => ({ + id: 'Martin_Plugin_001_send_discord_notification', + Stage: 'Post-processing', + Name: 'Send Discord Notification', + Type: 'Video', + Operation: 'Notify', + Description: 'Sends a notification to Discord', + Version: '1.0', + Tags: 'post-processing,configurable', + Inputs: [ + { + name: 'discord_webhook_url', + type: 'string', + inputUI: { + type: 'text', + }, + tooltip: 'The Discord webhook URL', + }, + { + name: 'discord_message', + type: 'string', + defaultValue: 'The file transcoding is finished', + inputUI: { + type: 'text', + }, + tooltip: `The message to send to Discord. Use placeholders to use information from the file. + \\nExample:\\n + The file "{name}" has been transcoded to "{format}" + Currently available placeholders are {name} and {format}`, + } + ], +}); + +const plugin = (file, librarySettings, inputs, otherArguments) => { + const lib = require('../methods/lib')(); + inputs = lib.loadDefaultValues(inputs, details); + + const response = { + file, + removeFromDB: false, + updateDB: false, + processFile: false, + infoLog: '', + }; + + inputs.discord_message = inputs.discord_message.replace('{name}', file.meta.FileName); + inputs.discord_message = inputs.discord_message.replace('{format}', file.container); + + fetch(inputs.discord_webhook_url, { + body: JSON.stringify({ + content: inputs.discord_message, + }), + headers: { + "Content-Type": "application/json", + }, + method: "POST", + }) + .then(function (res) { + console.log('Discord notification sent'); + response.infoLog += 'Discord notification sent\n'; + }) + .catch(function (res) { + console.log('Discord notification failed'); + response.infoLog += 'Discord notification failed\n'; + }); + + return response; +}; + +module.exports.details = details; +module.exports.plugin = plugin; \ No newline at end of file diff --git a/Collected/Martin_Plugin_002_extract_cover.js b/Collected/Martin_Plugin_002_extract_cover.js new file mode 100644 index 000000000..a83382c99 --- /dev/null +++ b/Collected/Martin_Plugin_002_extract_cover.js @@ -0,0 +1,65 @@ +const details = () => ({ + id: 'Martin_Plugin_002_extract_cover', + Stage: 'Pre-processing', + Name: 'Extract cover image if existing', + Type: 'Video', + Operation: 'Extraction', + Description: 'If it exist, the cover image is extracted from the file and saved as a separate file. The video file is untouched.', + Version: '1.0', + Tags: 'pre-processing,configurable', + Inputs: [ + { + name: 'storage_path', + type: 'string', + inputUI: { + type: 'text', + }, + tooltip: 'The path to the storage folder', + }, + ], +}); + + +const plugin = (file, librarySettings, inputs, otherArguments) => { + const lib = require('../methods/lib')(); + inputs = lib.loadDefaultValues(inputs, details); + + const response = { + file, + removeFromDB: false, + updateDB: false, + processFile: false, + infoLog: '', + }; + + const fs = require('fs'); + const path = require('path'); + const fileName = path.parse(otherArguments.originalLibraryFile.meta.FileName).name; + const coverImagePath = path.join(inputs.storage_path, fileName + '.jpg'); + if (fs.existsSync(coverImagePath)) { + response.infoLog += 'Cover image already extracted. Skipping.\n'; + return response; + } + + + for (const stream of file.ffProbeData.streams) { + if (stream.disposition.attached_pic == 1) { + response.processFile = true; + response.preset = ` -map 0:v -map -0:V -c copy "${coverImagePath}" -map 0 -c copy `; + response.container = `.` + file.container; + response.handBrakeMode = false; + response.FFmpegMode = true; + response.reQueueAfter = true; + response.infoLog += 'Found cover image in file. Extracting it.\n'; + return response; + } + } + + response.infoLog += 'No cover image found in file. Skipping.\n'; + + return response; +}; + + +module.exports.details = details; +module.exports.plugin = plugin; \ No newline at end of file diff --git a/Collected/Martin_Plugin_003_add_cover.js b/Collected/Martin_Plugin_003_add_cover.js new file mode 100644 index 000000000..4f7ede147 --- /dev/null +++ b/Collected/Martin_Plugin_003_add_cover.js @@ -0,0 +1,81 @@ +const details = () => ({ + id: 'Martin_Plugin_003_add_cover', + Stage: 'Pre-processing', + Name: 'Add cover image if available', + Type: 'Video', + Operation: 'Extraction', + Description: 'If an image exist with the same as the video, it will be added to the video file. The image file is untouched.', + Version: '1.0', + Tags: 'pre-processing,configurable', + Inputs: [ + { + name: 'storage_path', + type: 'string', + inputUI: { + type: 'text', + }, + tooltip: 'The path to the storage folder', + }, + ], +}); + + +const plugin = (file, librarySettings, inputs, otherArguments) => { + const lib = require('../methods/lib')(); + inputs = lib.loadDefaultValues(inputs, details); + + const response = { + file, + removeFromDB: false, + updateDB: false, + processFile: false, + infoLog: '', + }; + + const fs = require('fs'); + const path = require('path'); + const fileName = path.parse(otherArguments.originalLibraryFile.meta.FileName).name; + const coverImagePath = path.join(inputs.storage_path, fileName + '.jpg'); + if (!fs.existsSync(coverImagePath)) { + response.infoLog += 'Cover image not found. Skipping.\n'; + return response; + } + + // Use execSync to run the ffmpeg command + const execSync = require('child_process').execSync; + const ffmpegPath = otherArguments.ffmpegPath; + + // Check if the video file already has a cover image + for (const stream of file.ffProbeData.streams) { + if (stream.disposition.attached_pic == 1) { + response.infoLog += 'Video file already has a cover image. Skipping.\n'; + return response; + } + } + + response.infoLog += 'Adding cover image to video file\n'; + + // Add the cover image to the video file + let command; + if (file.container == 'mp4') { + command = `"${ffmpegPath}" -i "${file.file}" -i "${coverImagePath}" -map 0 -map 1 -c copy -disposition:1 attached_pic "${file.file}_temp.${file.container}"`; + } else if (file.container == 'mkv') { + command = `"${ffmpegPath}" -i "${file.file}" -attach "${coverImagePath}" -metadata:s:t mimetype=image/jpeg -c copy "${file.file}_temp.${file.container}"`; + } else { + response.infoLog += 'Video file format not supported. Skipping.\n'; + return response; + } + execSync(command); + + // Delete the original video file + fs.unlinkSync(file.file); + + // Rename the new video file to the original name + fs.renameSync(`${file.file}_temp.${file.container}`, file.file); + + return response; +}; + + +module.exports.details = details; +module.exports.plugin = plugin; \ No newline at end of file diff --git a/Collected/ReadMe.MD b/Collected/ReadMe.MD new file mode 100644 index 000000000..74216b034 --- /dev/null +++ b/Collected/ReadMe.MD @@ -0,0 +1,4 @@ +Here I keep an collection of Plugins Found on the Internet +Some are modified some are Original as is. +I kept author info original, +credits go to original authors diff --git a/Collected/Tdarr_Plugin_bsh1_Boosh_FFMPEG_QSV_AV1_Test.js b/Collected/Tdarr_Plugin_bsh1_Boosh_FFMPEG_QSV_AV1_Test.js new file mode 100644 index 000000000..f5e8d8be0 --- /dev/null +++ b/Collected/Tdarr_Plugin_bsh1_Boosh_FFMPEG_QSV_AV1_Test.js @@ -0,0 +1,921 @@ +// All credit for original plugin logic goes to Migz. +// This Plugin started as his NVENC/CPU plugin modified to work with QSV & with extra av1 logic. +// Rewritten to control encoder quality/speed & to allow AV1 files to be reprocessed to reduce file size + +// White paper from intel regarding QSV performance on linux using FFMPEG here: +// eslint-disable-next-line max-len +// https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/cloud-computing-quicksync-video-ffmpeg-white-paper.pdf + +const details = () => ({ + id: 'Tdarr_Plugin_bsh1_Boosh_FFMPEG_QSV_AV1_Test', + Stage: 'Pre-processing', + Name: 'Boosh-Transcode using QSV GPU & FFMPEG to AV1 (TEST)', + Type: 'Video', + Operation: 'Transcode', + Description: `==DETAILS== This is a QSV plugin. 8th+ gen INTEL QSV enabled CPUs are recommended. VAAPI is NOT used. + \n\n==OS SUPPORT== This plugin supports Linux & Windows using QSV. Mac is supported though cannot use QSV and + relies on 'VideoToolBox' - Expect to see different encode speed & quality on Mac compared to other platforms. + Ensure you set your node settings accordingly! + \n\n==LOGIC== Files will be transcoded into AV1 using Quick Sync Video (QSV) via Intel GPU using ffmpeg. + Settings are dependant on file bitrate working by the logic that H265 can support the same amount of data at half + the bitrate of H264. This plugin will skip files already in HEVC, AV1 & VP9 unless "reconvert_av1" is marked as + true. If it is then these will be reconverted again if they exceed the bitrate specified in "av1_max_bitrate". + This plugin relies on understanding the accurate video bitrate of your files. It's highly recommended to remux + into MKV & enable "Run mkvpropedit on files before running plugins" under Tdarr>Options.`, + Version: '1.3', + Tags: 'pre-processing,ffmpeg,video only,qsv,av1,configurable', + Inputs: [ + { + name: 'container', + type: 'string', + defaultValue: 'mkv', + inputUI: { + type: 'dropdown', + options: [ + 'mkv', + 'mp4', + ], + }, + tooltip: `\\n + ==DESCRIPTION== + \\nSpecifies the output container of the file. + \\nEnsure that all stream types you may have are supported by your chosen container. + \\n + ==INFO== + \\nOnly MP4 & MKV are supported and MKV is recommended. + \\nExample:\\n + mkv + \\nExample:\\n + mp4`, + }, + { + name: 'force_conform', + type: 'boolean', + defaultValue: false, + inputUI: { + type: 'dropdown', + options: [ + 'false', + 'true', + ], + }, + tooltip: `\\n + ==DESCRIPTION== + \\nMake the file conform to output containers requirements. + Use if you need to ensure the encode works from mp4>mkv or mkv>mp4. \\n + ==WARNING== \\n + This will remove data of certain types so ensure you are happy with that, + or use another plugin to convert these data types first! + \\n + ==INFO== + \\nDrop hdmv_pgs_subtitle/eia_608/subrip/timed_id3 for MP4. + \\nDrop data streams/mov_text/eia_608/timed_id3 for MKV. + \\nDefault is false. + \\nExample:\\n + true + \\nExample:\\n + false`, + }, + { + name: 'enable_10bit', + type: 'boolean', + defaultValue: false, + inputUI: { + type: 'dropdown', + options: [ + 'false', + 'true', + ], + }, + tooltip: `\\n + ==DESCRIPTION== + \\nSpecify if we want to enable 10bit encoding. + \\nIf this is enabled files will be processed and converted into 10bit + AV1 using main10 profile and with p010le pixel format.\n + If you just want to retain files that are already 10 bit then this can be left as false, as + 10bit to 10bit in ffmpeg should be automatic. + \\n + ==INFO== + \\nDefault is "false". + \\nExample:\\n + true + \\nExample:\\n + false`, + }, + { + name: 'target_bitrate_modifier', + type: 'number', + defaultValue: 0.5, + inputUI: { + type: 'text', + }, + tooltip: `\\n + ==DESCRIPTION== + \\nSpecify the modifier for the target bitrate. The logic is that AV1 can obtain the same quality + at half the bitrate. + \\nIf you feel this isn't achieving the quality you want then increase this value. + \\nRecommended to leave at default. Setting to 1.0 or higher will achieve no size reduction. + \\nLook at the min & max bitrate options if you just want to set lower & upper limits for acceptable bitrate + \\n + ==INFO== + \\nDefault is "0.5". + \\nExample:\\n + 0.5 + \\nExample:\\n + 0.75`, + }, + { + name: 'encoder_speedpreset', + type: 'string', + defaultValue: 'slow', + inputUI: { + type: 'dropdown', + options: [ + 'veryfast', + 'faster', + 'fast', + 'medium', + 'slow', + 'slower', + 'veryslow', + ], + }, + tooltip: `\\n + ==DESCRIPTION== + \\nSpecify the encoder speed/preset to use. + Slower options mean a slower encode but better quality and faster options mean faster encodes but + worse quality. + \\nFor more information see intel white paper on ffmpeg results using QSV: \\n` + // eslint-disable-next-line max-len + + `https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/cloud-computing-quicksync-video-ffmpeg-white-paper.pdf + \\n + ==INFO== + \\nDefault is "slow". + \\nExample:\\n + medium + \\nExample:\\n + slower`, + }, + { + name: 'extra_qsv_options', + type: 'string', + defaultValue: '', + inputUI: { + type: 'text', + }, + tooltip: `\\n + ==DESCRIPTION== + \\nHere you can add extra options to the ffmpeg QSV ENCODE cmd. + This does not override the ffmpeg cmd, it just allows additions to it. + \\n + There are extra QSV options that can be + forced on/off as desired. See here for some possible cmds - + https://ffmpeg.org/ffmpeg-codecs.html#AV1-Options + \\n + ==WARNING== \\n + Be certain to verify the cmds work before adding to your workflow. \\n + Check Tdarr Help Tab. Enter ffmpeg cmd - "-h encoder=av1_qsv". This will give a list of supported commands. \\n + MAC SPECIFIC - This option is ignored on Mac because videotoolbox is used rather than qsv. + \\n + ==INFO== + \\nDefault is empty but the first example below has a suggested value. If unsure just leave empty. + \\nEnsure to only use cmds valid to encoding QSV as the script handles other ffmpeg cmds relating to + bitrate etc. Anything else entered here might be supported but could cause undesired results. + \\nIf you are using a "-vf" cmd, please put it at the end to avoid issues! + \\nExample:\\n + -look_ahead 1 -look_ahead_depth 100 -b_strategy 1 -adaptive_i 1 -adaptive_b 1 + \\n Above enables look ahead, b-frames, etc.\\n + \\nExample:\\n + -vf scale_qsv=w=1280:h=720 + \\nScale video resolution Method 1\\n + \\nExample:\\n + -vf scale_qsv=1280:-1 + \\nScale video resolution Method 2\\n`, + }, + { + name: 'bitrate_cutoff', + type: 'number', + defaultValue: 0, + inputUI: { + type: 'text', + }, + tooltip: `\\n + ==DESCRIPTION== + \\nSpecify bitrate cutoff, files with a video bitrate lower then this will not be processed.\n + \\n + ==INFO== + \\nRate is in kbps. + \\nDefaults to 0 which means this is disabled. + \\nEnter a valid number to enable. + \\nExample:\\n + 2500 + \\nExample:\\n + 1500`, + }, + { + name: 'max_average_bitrate', + type: 'number', + defaultValue: 0, + inputUI: { + type: 'text', + }, + tooltip: `\\n + ==DESCRIPTION== + \\nSpecify a maximum average video bitrate. When encoding we take the current video bitrate and halve it + to get an average target. This option sets a upper limit to that average + (i.e if you have a video bitrate of 10000, half is 5000, if your maximum desired average bitrate is 4000 + then we use that as the target instead of 5000). + \\n + ==INFO== + \\nBitrate here is referring to video bitrate as we want to set the video bitrate on encode. + \\nRate is in kbps. + \\nDefaults to 0 which means this is disabled. + \\nEnter a valid number to enable. + \\nExample:\\n + 4000 + \\nExample:\\n + 3000`, + }, + { + name: 'min_average_bitrate', + type: 'number', + defaultValue: 0, + inputUI: { + type: 'text', + }, + tooltip: `\\n + ==DESCRIPTION== + \\nSpecify a minimum average video bitrate. When encoding we take the current video bitrate and halve + it to get an average target. This option sets a lower limit to that average (i.e if you have a video bitrate + of 3000, half is 1500, if your minimum desired average bitrate is 2000 then we use that as the target instead + of 1500). + \\n + ==INFO== + \\nBitrate here is referring to video bitrate as we want to set the video bitrate on encode. + \\nRate is in kbps. + \\nDefaults to 0 which means this is disabled. + \\nEnter a valid number to enable. + \\nExample:\\n + 2000 + \\nExample:\\n + 1000`, + }, + { + name: 'reconvert_av1', + type: 'boolean', + defaultValue: false, + inputUI: { + type: 'dropdown', + options: [ + 'false', + 'true', + ], + }, + tooltip: `\\n + ==DESCRIPTION== + \\nSet to reprocess HEVC, VP9 or AV1 files (i.e reduce bitrate of files already in those codecs). + \\nSince this uses the same logic as normal, halving the current bitrate, this is NOT recommended + unless you know what you are doing, so please leave FALSE if unsure! + \\nNEEDS to be used in conjunction with "bitrate_cutoff" or "av1_max_bitrate" otherwise is ignored. + \\nThis is useful in certain situations, perhaps you have a file which is AV1 but has an extremely high + bitrate and you'd like to reduce it. + \\n + ==WARNING== \\n + IF YOU HAVE VP9 OR AV1 FILES YOU WANT TO KEEP IN THOSE FORMATS THEN DO NOT USE THIS OPTION. \\n + \\nThis option has the potential to LOOP your encodes! You can encode a file to AV1 and still + be above your cutoff and it would be converted again & again if this is set to true (since it's now AV1). + So if you use this be sure to set "av1_max_bitrate" & "max_average_bitrate" to help prevent the plugin looping. + Also it is highly suggested that you have your "av1_max_bitrate" higher than "max_average_bitrate". + \\nPlease be certain you want this enabled before setting it otherwise leave this as FALSE! + While the plugin will attempt to generate accurate video bitrate metadata, it can not always reliably do so + and will be forced to fall back onto estimates. Please bare this in mind when using the AV1 reprocess option. + \\n + \\nExample:\\n + true + \\nExample:\\n + false`, + }, + { + name: 'av1_max_bitrate', + type: 'number', + defaultValue: 0, + inputUI: { + type: 'text', + }, + tooltip: `\\n + ==DESCRIPTION== + \\nHas no effect unless "reconvert_av1" is set to true. This allows you to specify a maximum + allowed average OVERALL bitrate for AV1 or similar files. Much like the "bitrate_cutoff" option, but + specifically for AV1 files. It should be set HIGHER then your standard cutoff for safety. + \\nAlso, it's highly suggested you use the min & max average bitrate options in combination with this. You + will want those to control the encoded video bitrate, otherwise you may end up repeatedly reprocessing AV1 files. + i.e your file might have a overall bitrate of 20000, if your av1 cutoff is 5000 then it's going to reconvert + multiple times before it'll fall below that cutoff. While AV1 reprocessing can be useful this is why it is NOT + recommended! + \\n + ==WARNING== \\n + While the plugin will attempt to generate accurate video bitrate metadata, it can not always reliably do so + and will be forced to fall back onto estimates. Please bare this in mind when using the AV1 reprocess option. + \\n + ==INFO== + \\nRate is in kbps. + \\nDefaults to 0 which means this is disabled. + \\nEnter a valid number to enable, otherwise we use "bitrate_cutoff" and multiply x2 for a safe limit. + \\nExample:\\n + 4000 + \\nExample:\\n + 3000`, + }, + ], +}); + +// Set up required variables. +let currentBitrate = 0; +let overallBitRate = 0; +let targetBitrate = 0; +let minimumBitrate = 0; +let maximumBitrate = 0; +let duration = ''; +let videoIdx = 0; +let extraArguments = ''; +let bitrateSettings = ''; +let inflatedCutoff = 0; +let main10 = false; +let high10 = false; +let swDecode = false; +let videoBR = 0; +let hdrEnabled = false; +let pixelFormat = ''; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const plugin = (file, librarySettings, inputs, otherArguments) => { + const lib = require('../methods/lib')(); + const os = require('os'); + // eslint-disable-next-line @typescript-eslint/no-unused-vars,no-param-reassign + inputs = lib.loadDefaultValues(inputs, details); + const response = { + processFile: false, + preset: '', + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: true, + infoLog: '', + container: `.${inputs.container}`, + }; + + if (file.fileMedium !== 'video') { + response.processFile = false; + response.infoLog += `☒ File seems to be ${file.fileMedium} & not video. Exiting\n`; + return response; + } + + if (inputs.Target_bitrate_modifier >= 1) { + response.processFile = false; + response.infoLog += `☒ Target bitrate modifier has been set to 1 or higher. Will not encode. Exiting\n`; + return response; + } + + for (let i = 0; i < file.ffProbeData.streams.length; i += 1) { + const strstreamType = file.ffProbeData.streams[i].codec_type.toLowerCase(); + // Check if stream is a video. + if (strstreamType === 'video') { + if (file.ffProbeData.streams[i].codec_name !== 'mjpeg' + && file.ffProbeData.streams[i].codec_name !== 'png') { + if (videoBR <= 0) { // Process if videoBR is not yet valid + try { // Try checking file stats using Mediainfo first, then ffprobe. + videoBR = Number(file.mediaInfo.track[i + 1].BitRate) / 1000; + if (videoBR <= 0 || Number.isNaN(videoBR)) { + if (Number(file.ffProbeData.streams[i].tags.BPS) > 0) { + videoBR = file.ffProbeData.streams[i].tags.BPS / 1000; + } else if (Number(file.ffProbeData.streams[i].tags.BPS['-eng']) > 0) { + videoBR = file.ffProbeData.streams[i].tags.BPS['-eng'] / 1000; + } + } + } catch (err) { + // Catch error - Ignore & carry on - If check can bomb out if tags don't exist... + videoBR = 0; // Set videoBR to 0 for safety + } + } + if (duration <= 0) { // Process if duration is not yet valid + try { // Attempt to get duration info + if (Number.isNaN(file.meta.Duration)) { + duration = file.meta.Duration; + duration = (new Date(`1970-01-01T${duration}Z`).getTime() / 1000) / 60; + } else if (file.meta.Duration > 0) { + duration = file.meta.Duration / 60; + } + if (duration <= 0 || Number.isNaN(duration)) { + if (typeof file.mediaInfo.track[i + 1].Duration !== 'undefined') { + duration = file.mediaInfo.track[i + 1].Duration; + duration = (new Date(`1970-01-01T${duration}Z`).getTime() / 1000) / 60; + } else if (typeof file.ffProbeData.streams[i].tags.DURATION !== 'undefined') { + duration = file.ffProbeData.streams[i].tags.DURATION; + duration = (new Date(`1970-01-01T${duration}Z`).getTime() / 1000) / 60; + } + } + } catch (err) { + // Catch error - Ignore & carry on - If check can bomb out if tags don't exist... + duration = 0; // Set duration to 0 for safety + } + } + if ((videoBR <= 0 || Number.isNaN(videoBR)) || (duration <= 0 || Number.isNaN(duration))) { + // videoBR or duration not yet valid so Loop + } else { + break;// Exit loop if both valid + } + } + } + } + + if (Number.isNaN(videoBR) || videoBR <= 0) { + // Work out currentBitrate using "Bitrate = file size / (number of minutes * .0075)" + currentBitrate = Math.round(file.file_size / (duration * 0.0075)); + if (Number.isNaN(currentBitrate) || currentBitrate <= 0) { + response.infoLog += '==ERROR== Failed to get any bitrate data from this file!\n' + + 'This is highly likely due to some file problem. Highly suggested to run ' + + 'mkvpropedit via Tdarr options or in a Flow to ensure this file has correct stats!\n' + + 'THIS ENCODE WILL ERROR FOR VISIBILITY'; + } else { + response.infoLog += '==WARNING== Failed to get an accurate video bitrate, ' + + `falling back to old method to get OVERALL file bitrate of ${currentBitrate}kbps. ` + + 'Bitrate calculations for video encode will likely be inaccurate...\n'; + } + } else { + currentBitrate = Math.round(videoBR); + response.infoLog += `☑ It looks like the current video bitrate is ${currentBitrate}kbps.\n`; + } + + // Get overall bitrate for use with AV1 reprocessing + overallBitRate = Math.round(file.file_size / (duration * 0.0075)); + // Default will halve current bitrate for Target bitrate + // In theory h265 can be half the bitrate as h264 without losing quality. + targetBitrate = Math.round(currentBitrate * inputs.target_bitrate_modifier); + // Allow some leeway under and over the targetBitrate. + minimumBitrate = Math.round(targetBitrate * 0.75); + maximumBitrate = Math.round(targetBitrate * 1.25); + + // If targetBitrate or currentBitrate comes out as 0 then something + // has gone wrong and bitrates could not be calculated. + // Cancel plugin completely. + if (targetBitrate <= 0 || currentBitrate <= 0 || overallBitRate <= 0) { + response.infoLog += '☒ Target bitrates could not be calculated. Skipping this plugin.\n'; + return response; + } + + // If targetBitrate is equal or greater than currentBitrate then something + // has gone wrong as that is not what we want. + // Cancel plugin completely. + if (targetBitrate >= currentBitrate) { + response.infoLog += `☒ Target bitrate has been calculated as ${targetBitrate}kbps. This is equal or greater than ` + + "the current bitrate... Something has gone wrong and this shouldn't happen! Skipping this plugin.\n"; + return response; + } + + // Ensure that bitrate_cutoff is set if reconvert_av1 is true since we need some protection against a loop + // Cancel the plugin + if (inputs.reconvert_av1 === true && inputs.bitrate_cutoff <= 0 && inputs.av1_max_bitrate <= 0) { + response.infoLog += `Reconvert AV1 is ${inputs.reconvert_av1}, however there is no bitrate cutoff or AV1 ` + + 'specific cutoff set so we have no way to know when to stop processing this file.\n' + + 'Either set reconvert_AV1 to false or set a bitrate cutoff and set a av1_max_bitrate cutoff.\n' + + '☒ Skipping this plugin.\n'; + return response; + } + + // Check if inputs.bitrate cutoff has something entered. + // (Entered means user actually wants something to happen, empty would disable this). + if (inputs.bitrate_cutoff > 0) { + // Checks if currentBitrate is below inputs.bitrate_cutoff. + // If so then cancel plugin without touching original files. + if (currentBitrate <= inputs.bitrate_cutoff) { + response.infoLog += `☑ Current bitrate is below set cutoff of ${inputs.bitrate_cutoff}kbps.\n` + + 'Cancelling plugin.\n'; + return response; + } + // If above cutoff then carry on + if (currentBitrate > inputs.bitrate_cutoff && inputs.reconvert_av1 === false) { + response.infoLog += '☒ Current bitrate appears to be above the cutoff. Need to process\n'; + } + } + + if (inputs.max_average_bitrate > 0) { + // Checks if targetBitrate is above inputs.max_average_bitrate. + // If so then clamp target bitrate + if (targetBitrate > inputs.max_average_bitrate) { + response.infoLog += 'Our target bitrate is above the max_average_bitrate so clamping at max of ' + + `${inputs.max_average_bitrate}kbps.\n`; + targetBitrate = Math.round(inputs.max_average_bitrate); + minimumBitrate = Math.round(targetBitrate * 0.75); + maximumBitrate = Math.round(targetBitrate * 1.25); + } + } + + // Check if inputs.min_average_bitrate has something entered. + // (Entered means user actually wants something to happen, empty would disable this). + if (inputs.min_average_bitrate > 0) { + // Exit the plugin is the cutoff is less than the min average bitrate. Most likely user error + if (inputs.bitrate_cutoff > 0 && inputs.bitrate_cutoff < inputs.min_average_bitrate) { + response.infoLog += `☒ Bitrate cutoff ${inputs.bitrate_cutoff}k is less than the set minimum ` + + `average bitrate set of ${inputs.min_average_bitrate}kbps. We don't want this. Cancelling plugin.\n`; + return response; + } + // Checks if inputs.bitrate_cutoff is below inputs.min_average_bitrate. + // If so then set currentBitrate to the minimum allowed.) + if (targetBitrate < inputs.min_average_bitrate) { + response.infoLog += `Target average bitrate clamped at min of ${inputs.min_average_bitrate}kbps.\n`; + targetBitrate = Math.round(inputs.min_average_bitrate); + minimumBitrate = Math.round(targetBitrate * 0.75); + maximumBitrate = Math.round(targetBitrate * 1.25); + } + } + + // It's possible to remux or flat out convert from mp4 to mkv so we need to conform to standards + // So check streams and add any extra parameters required to make file conform with output format. + // i.e drop mov_text for mkv files and drop pgs_subtitles for mp4 + if (inputs.force_conform === true) { + if (inputs.container.toLowerCase() === 'mkv') { + extraArguments += '-map -0:d '; + for (let i = 0; i < file.ffProbeData.streams.length; i += 1) { + try { + if ( + file.ffProbeData.streams[i].codec_name + .toLowerCase() === 'mov_text' + || file.ffProbeData.streams[i].codec_name + .toLowerCase() === 'eia_608' + || file.ffProbeData.streams[i].codec_name + .toLowerCase() === 'timed_id3' + ) { + extraArguments += `-map -0:${i} `; + } + } catch (err) { + // Error + } + } + } + if (inputs.container.toLowerCase() === 'mp4') { + for (let i = 0; i < file.ffProbeData.streams.length; i += 1) { + try { + if ( + file.ffProbeData.streams[i].codec_name + .toLowerCase() === 'hdmv_pgs_subtitle' + || file.ffProbeData.streams[i].codec_name + .toLowerCase() === 'eia_608' + || file.ffProbeData.streams[i].codec_name + .toLowerCase() === 'subrip' + || file.ffProbeData.streams[i].codec_name + .toLowerCase() === 'timed_id3' + ) { + extraArguments += `-map -0:${i} `; + } + } catch (err) { + // Error + } + } + } + } + + // Go through each stream in the file. + for (let i = 0; i < file.ffProbeData.streams.length; i += 1) { + // Check if stream is a video. + if (file.ffProbeData.streams[i].codec_type.toLowerCase() === 'video') { + // Check if codec of stream is mjpeg/png, if so then remove this "video" stream. + // mjpeg/png are usually embedded pictures that can cause havoc with plugins. + if (file.ffProbeData.streams[i].codec_name === 'mjpeg' || file.ffProbeData.streams[i].codec_name === 'png') { + extraArguments += `-map -0:v:${videoIdx} `; + } else { // Ensure to only do further checks if video stream is valid for use + // Check for HDR in files. Attempt to use same color + if ((file.ffProbeData.streams[i].color_space === 'bt2020nc' + || file.ffProbeData.streams[i].color_space === 'bt2020n') + && (file.ffProbeData.streams[i].color_transfer === 'smpte2084' + || file.ffProbeData.streams[i].color_transfer === 'arib-std-b67') + && file.ffProbeData.streams[i].color_primaries === 'bt2020') { + hdrEnabled = true; + response.infoLog += '==WARNING== This looks to be a HDR file. HDR is supported but ' + + 'correct encoding is not guaranteed.\n'; + extraArguments += `-color_primaries ${file.ffProbeData.streams[i].color_primaries} ` + + `-color_trc ${file.ffProbeData.streams[i].color_transfer} ` + + `-colorspace ${file.ffProbeData.streams[i].color_space} `; + } + + // Check if codec of stream is HEVC, Vp9 or AV1 + // AND check if file.container does NOT match inputs.container. If so remux file. + if ((file.ffProbeData.streams[i].codec_name === 'av1' + || file.ffProbeData.streams[i].codec_name === 'vp9' + || file.ffProbeData.streams[i].codec_name === 'av1') && file.container !== inputs.container) { + response.infoLog += `☒ File is HEVC, VP9 or AV1 but is not in ${inputs.container} container. Remuxing.\n`; + response.preset = ` -map 0 -c copy ${extraArguments}`; + response.processFile = true; + return response; + } + + // Now check if we're reprocessing HEVC files, if not then ensure we don't convert HEVC again + if (inputs.reconvert_av1 === false && (file.ffProbeData.streams[i].codec_name === 'av1' + || file.ffProbeData.streams[i].codec_name === 'vp9' || file.ffProbeData.streams[i].codec_name === 'av1')) { + // Check if codec of stream is HEVC, VP9 or AV1 AND check if file.container matches inputs.container. + // If so nothing for plugin to do. + if ((file.ffProbeData.streams[i].codec_name === 'av1' || file.ffProbeData.streams[i].codec_name === 'vp9' + || file.ffProbeData.streams[i].codec_name === 'av1') && file.container === inputs.container) { + response.infoLog += `☑ File is already HEVC, VP9 or AV1 & in ${inputs.container}.\n`; + return response; + } + + // New logic for reprocessing HEVC. Mainly done for my own use. + // We attempt to get accurate stats earlier - If we can't we fall back onto overall bitrate + // which can be inaccurate. We may inflate the current bitrate check so we don't keep looping this logic. + } else if (inputs.reconvert_av1 === true && (file.ffProbeData.streams[i].codec_name === 'av1' + || file.ffProbeData.streams[i].codec_name === 'vp9' || file.ffProbeData.streams[i].codec_name === 'av1')) { + if (inputs.av1_max_bitrate > 0) { + if (currentBitrate > inputs.av1_max_bitrate) { + // If bitrate is higher then av1_max_bitrate then need to re-encode + response.infoLog += `Reconvert_av1 is ${inputs.reconvert_av1} & the file is already HEVC, VP9 or AV1. ` + + `Using HEVC specific cutoff of ${inputs.av1_max_bitrate}kbps.\n` + + '☒ The file is still above this new cutoff! Reconverting.\n'; + } else { + // Otherwise we're now below the av1 cutoff and we can exit + response.infoLog += `Reconvert_av1 is ${inputs.reconvert_av1} & the file is already HEVC, VP9 or AV1. ` + + `Using HEVC specific cutoff of ${inputs.av1_max_bitrate}kbps.\n` + + '☑ The file is NOT above this new cutoff. Exiting plugin.\n'; + return response; + } + + // If we're not using the av1 max bitrate then we need a safety net to try and ensure we don't keep + // looping this plugin. For maximum safety we simply multiply the cutoff by 2. + } else if (currentBitrate > (inputs.bitrate_cutoff * 2)) { + if (inputs.bitrate_cutoff > 0) { + inflatedCutoff = Math.round(inputs.bitrate_cutoff * 2); + response.infoLog += `Reconvert_av1 is ${inputs.reconvert_av1} & the file is already HEVC, VP9 or AV1. ` + + `Will use Overall file Bitrate for AV1 files as safety, bitrate is ${overallBitRate}kbps.\n` + + 'AV1 specific cutoff not set so bitrate_cutoff is multiplied by 2 for safety!\n' + + `Cutoff now temporarily ${inflatedCutoff}kbps.\n` + + '☒ The file is still above this new cutoff! Reconverting.\n'; + } else { + response.infoLog += `Reconvert_av1 is ${inputs.reconvert_av1} & the file is already HEVC, VP9 or AV1. ` + + `Will use Overall file Bitrate for AV1 files as safety, bitrate is ${overallBitRate}kbps.\n` + + 'AV1 specific cutoff not set & bitrate_cutoff is not set!\n' + + '☒ We have no safe way to prevent a transcode loop. Exiting.\n'; + return response; + } + } else { + // File is below cutoff so we can exit + inflatedCutoff = Math.round(inputs.bitrate_cutoff * 2); + response.infoLog += `Reconvert_av1 is ${inputs.reconvert_av1} & the file is already HEVC, VP9 or AV1. ` + + `Will use Overall file Bitrate for AV1 files as safety, bitrate is ${overallBitRate}kbps.\n` + + 'AV1 specific cutoff not set so bitrate_cutoff is multiplied by 2 for safety!\n' + + `Cutoff now temporarily ${inflatedCutoff}kbps.\n` + + '☑The file is NOT above this new cutoff. Exiting plugin.\n'; + return response; + } + } + + // Files in the High10 profile are not supported for HW Decode + if (file.ffProbeData.streams[i].profile === 'High 10') { + high10 = true; + main10 = true; + // If files are 10 bit or the enable_10bit setting is used mark to enable Main10. + } else if (file.ffProbeData.streams[i].profile === 'Main 10' + || file.ffProbeData.streams[i].bits_per_raw_sample === '10' || inputs.enable_10bit === true) { + main10 = true; + } + } + + // Increment video index. Needed to keep track of video id in case there is more than one video track. + // (i.e png or mjpeg which we would remove at the start of the loop) + videoIdx += 1; + } + } + + // Specify the output format + switch (inputs.container) { + case 'mkv': + extraArguments += '-f matroska '; + break; + case 'mp4': + extraArguments += '-f mp4 '; + break; + default: + } + + // Some video codecs don't support HW decode so mark these + // VC1 & VP8 are no longer supported on new HW, add cases here if your HW does support + switch (file.video_codec_name) { + case 'mpeg2': + break; + case 'h264': + if (high10 === true) { + swDecode = true; + response.infoLog += 'Input file is h264 High10. Hardware Decode not supported.\n'; + } + break; + case 'mjpeg': + break; + case 'hevc': + break; + case 'vp9':// Should be supported by 8th Gen + + break; + case 'av1':// Should be supported by 11th gen + + break; + default: + swDecode = true; + response.infoLog += `Input file is ${file.video_codec_name}. Hardware Decode not supported.\n`; + } + + // Are we encoding to 10 bit? If so enable correct profile & pixel format. + if (swDecode === true && main10 === true) { + // This is used if we have High10 or Main10 is enabled & odd format files. + // SW decode and use standard -pix_fmt p010le + extraArguments += ' -pix_fmt p010le '; + response.infoLog += '10 bit encode enabled. Setting 10 bit pixel format\n'; + } else if (main10 === true) { // Pixel formate method when using HW decode + if (inputs.extra_qsv_options.search('-vf scale_qsv') >= 0) { + // eslint-disable-next-line no-param-reassign + inputs.extra_qsv_options += ',format=p010le'; // Only add on the pixel format to existing scale_qsv cmd + } else { + extraArguments += ' -vf scale_qsv=format=p010le'; + } + response.infoLog += '10 bit encode enabled. Setting 10 bit pixel format\n'; + } + + // Set bitrateSettings variable using bitrate information calculated earlier. + bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k ` + + `-maxrate ${maximumBitrate}k -bufsize ${currentBitrate}k`; + // Print to infoLog information around file & bitrate settings. + response.infoLog += `Container for output selected as ${inputs.container}.\n` + + 'Encode variable bitrate settings:\n' + + `Target = ${targetBitrate}k\n` + + `Minimum = ${minimumBitrate}k\n` + + `Maximum = ${maximumBitrate}k\n`; + + // START PRESET + // -fflags +genpts should regenerate timestamps if they end up missing... + response.preset = '-fflags +genpts '; + + // HW ACCEL FLAGS + // Account for different OS + if (swDecode !== true) { + // Only enable hw decode for accepted formats + switch (os.platform()) { + case 'linux': // Linux - Full device, should fix child_device_type warnings + response.preset += '-hwaccel qsv -hwaccel_output_format qsv ' + + '-init_hw_device qsv:hw_any,child_device_type=vaapi '; + break; + case 'win32': // Windows - Full device, should fix child_device_type warnings + response.preset += '-hwaccel qsv -hwaccel_output_format qsv ' + + '-init_hw_device qsv:hw,child_device_type=d3d11va '; + break; + default: + response.preset += '-hwaccel qsv -hwaccel_output_format qsv -init_hw_device qsv:hw_any '; + } + } else { + switch (os.platform()) { + case 'linux': // Linux - Full device, should fix child_device_type warnings + response.preset += '-hwaccel_output_format qsv ' + + '-init_hw_device qsv:hw_any,child_device_type=vaapi '; + break; + case 'win32': // Windows - Full device, should fix child_device_type warnings + response.preset += '-hwaccel_output_format qsv ' + + '-init_hw_device qsv:hw,child_device_type=d3d11va '; + break; + default: + // Default to enabling hwaccel for output only + response.preset += '-hwaccel_output_format qsv -init_hw_device qsv:hw_any '; + } + } + + // DECODE FLAGS + // VC1 & VP8 are no longer supported on new HW, add cases here if your HW does support + switch (file.video_codec_name) { + case 'mpeg2': + response.preset += '-c:v mpeg2_qsv'; + break; + case 'h264': + if (high10 !== true) { // Don't enable for High10 + response.preset += '-c:v h264_qsv'; + } else { + response.preset += `-c:v ${file.video_codec_name}`; + } + break; + case 'mjpeg': + response.preset += '-c:v mjpeg_qsv'; + break; + case 'hevc': + response.preset += '-c:v hevc_qsv'; + break; + case 'vp9': // Should be supported by 8th Gen + + response.preset += '-c:v vp9_qsv'; + break; + case 'av1': // Should be supported by 11th gen + + response.preset += '-c:v av1_qsv'; + break; + default: + // Use incoming format for software decode + response.preset += `-c:v ${file.video_codec_name}`; + } + + // ENCODE FLAGS + response.preset += ' -map 0 -c:v '; + + // Account for different OS setup for QSV AV1 encode. + switch (os.platform()) { + case 'linux': + response.preset += 'av1_qsv'; + break; + case 'win32': + response.preset += 'av1_qsv'; + // Tested working on a Win 10 - i5-10505 + break; + default: + response.preset += 'av1_qsv'; // Default to QSV + } + + // Only add on for HW decoded formats + // VC1 & VP8 are no longer supported on new HW, add cases here if your HW does support + if (swDecode !== true) { + // Check if -vf cmd has already been used on user input + if (inputs.extra_qsv_options.search('-vf scale_qsv') >= 0) { + switch (file.video_codec_name) { + case 'mpeg2': + // eslint-disable-next-line no-param-reassign + inputs.extra_qsv_options += ',hwupload=extra_hw_frames=64,format=qsv '; + break; + case 'h264': + // eslint-disable-next-line no-param-reassign + inputs.extra_qsv_options += ',hwupload=extra_hw_frames=64,format=qsv '; + break; + case 'mjpeg': + // eslint-disable-next-line no-param-reassign + inputs.extra_qsv_options += ',hwupload=extra_hw_frames=64,format=qsv '; + break; + case 'av1': + // eslint-disable-next-line no-param-reassign + inputs.extra_qsv_options += ',hwupload=extra_hw_frames=64,format=qsv '; + break; + case 'vp9': // Should be supported by 8th Gen + + // eslint-disable-next-line no-param-reassign + inputs.extra_qsv_options += ',hwupload=extra_hw_frames=64,format=qsv '; + break; + case 'av1': // Should be supported by 11th gen + + // eslint-disable-next-line no-param-reassign + inputs.extra_qsv_options += ',hwupload=extra_hw_frames=64,format=qsv '; + break; + default: + } + } else if (extraArguments.search('-vf') === -1) { + // Check if -vf cmd has been used on the other var instead, if not add it & rest of cmd + switch (file.video_codec_name) { + case 'mpeg2': + extraArguments += '-vf hwupload=extra_hw_frames=64,format=qsv '; + break; + case 'h264': + extraArguments += '-vf hwupload=extra_hw_frames=64,format=qsv '; + break; + case 'mjpeg': + extraArguments += '-vf hwupload=extra_hw_frames=64,format=qsv '; + break; + case 'av1': + extraArguments += '-vf hwupload=extra_hw_frames=64,format=qsv '; + break; + case 'vp9': // Should be supported by 8th Gen + + extraArguments += '-vf hwupload=extra_hw_frames=64,format=qsv '; + break; + case 'av1': // Should be supported by 11th gen + + extraArguments += '-vf hwupload=extra_hw_frames=64,format=qsv '; + break; + default: + } + } else { + // Otherwise add the cmd onto the end + switch (file.video_codec_name) { + case 'mpeg2': + extraArguments += ',hwupload=extra_hw_frames=64,format=qsv '; + break; + case 'h264': + extraArguments += ',hwupload=extra_hw_frames=64,format=qsv '; + break; + case 'mjpeg': + extraArguments += ',hwupload=extra_hw_frames=64,format=qsv '; + break; + case 'av1': + extraArguments += ',hwupload=extra_hw_frames=64,format=qsv '; + break; + case 'vp9': // Should be supported by 8th Gen + + extraArguments += ',hwupload=extra_hw_frames=64,format=qsv '; + break; + case 'av1': // Should be supported by 11th gen + + extraArguments += ',hwupload=extra_hw_frames=64,format=qsv '; + break; + default: + } + } + } + + // Add the rest of the ffmpeg command + response.preset += ` ${bitrateSettings} ` + + `-preset ${inputs.encoder_speedpreset} ${inputs.extra_qsv_options} ` + + `-c:a copy -c:s copy -max_muxing_queue_size 9999 ${extraArguments}`; + + response.processFile = true; + response.infoLog += 'File Transcoding...\n'; + + return response; +}; +module.exports.details = details; +module.exports.plugin = plugin; diff --git a/Community/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_AMD.js b/Community/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_AMD.js new file mode 100644 index 000000000..5810f57b1 --- /dev/null +++ b/Community/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_AMD.js @@ -0,0 +1,324 @@ +const details = () => ({ + id: 'Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_AMD', + Stage: 'Pre-processing', + Name: 'DeNiX HandBrake UI Basic Options AMD', + Type: 'Video', + Operation: 'Transcode', + Description: ` + This plugin provides basic HandBrake transcode options through a user-friendly UI. + It allows you to set various video and audio encoding parameters using HandBrake, + including video encoder, frame rate mode, and audio settings. + + Key Features: + - Choose from a variety of AMD video encoders such as vce_h264, vce_h265, vce_h265_10bit, vce_av1, vce_av1_10bit. + - Configure encoder presets, profiles, and levels for AMD. + - Set frame rate modes, including constant (CFR), variable (VFR), peak-limited (PFR), and bitrate (VB). + - Specify video quality or bitrate values. + - Select audio and subtitle languages, with options to keep or delete original tracks. + - Enable or disable two-pass encoding for AMD bitrate mode. + + This plugin is ideal for users who want to leverage HandBrake's powerful encoding capabilities + through a simplified and intuitive interface. + + ### Instructions for the User + - **Frame Rate Mode:** + - **Additional Parameters:** + - If \`--cfr\` is selected, enter the quality value (e.g., \`-q 25\`). + - If \`--vb\` is selected, enter the bitrate value (e.g., \`4000kb\`). + - If \`--vfr\` or \`--pfr\` is selected, enter the quality value (e.g., \`-q 25\`). + - **Two-Pass Encoding:** Only enable when using \`--vb\` mode. Two-pass encoding provides better quality by analyzing the video in the first pass and encoding it in the second pass. + `, + Version: '1.01', + Tags: 'action', + Inputs: [ + { + name: 'container', + type: 'string', + defaultValue: 'mkv', + inputUI: { + type: 'dropdown', + options: [ + 'mkv', + 'mp4', + ], + }, + tooltip: 'Select the output container format. MKV supports more features and codecs than MP4, making it a versatile choice for high-quality videos.', + }, + { + name: 'videoEncoder', + type: 'string', + defaultValue: 'vce_av1', + inputUI: { + type: 'dropdown', + options: [ + 'vce_h264', + 'vce_h265', + 'vce_h265_10bit', + 'vce_av1', + 'vce_av1_10bit', + ], + }, + tooltip: 'Select the video encoder. Options include:\n' + + 'vce_h264: H.264 encoder using AMD VCE.\n' + + 'vce_h265: H.265 encoder using AMD VCE.\n' + + 'vce_h265_10bit: H.265 10-bit encoder using AMD VCE.\n' + + 'vce_av1: AV1 encoder using AMD VCE.\n' + + 'vce_av1_10bit: AV1 10-bit encoder using AMD VCE.', + }, + { + name: 'amfEncoderPreset', + type: 'string', + defaultValue: 'quality', + inputUI: { + type: 'dropdown', + options: [ + 'speed', + 'balanced', + 'quality', + ], + }, + tooltip: 'Select the encoder preset for AMD encoders. Options include:\n' + + 'speed: Prioritize encoding speed over quality.\n' + + 'balanced: Balance between speed and quality.\n' + + 'quality: Prioritize output quality over encoding speed.', + }, + { + name: 'amfEncoderProfile', + type: 'string', + defaultValue: 'auto', + inputUI: { + type: 'dropdown', + options: [ + 'main', + 'main10', + 'auto', + ], + }, + tooltip: 'Select the encoder profile for AMD encoders. Options include:\n' + + 'main: Suitable for most use cases with good compatibility.\n' + + 'main10: Supports 10-bit video encoding for higher color depth.\n' + + 'auto: Automatically choose the best profile based on input and output settings.', + }, + { + name: 'amfEncoderLevel', + type: 'string', + defaultValue: 'auto', + inputUI: { + type: 'dropdown', + options: [ + 'auto', + '1.0', + '1.1', + '1.2', + '1.3', + '2.0', + '2.1', + '2.2', + '3.0', + '3.1', + '3.2', + '4.0', + '4.1', + '4.2', + '5.0', + '5.1', + '5.2', + '6.0', + '6.1', + '6.2', + ], + }, + tooltip: 'Select the encoder level for AMD encoders. The level defines the maximum bitrate and resolution allowed. "auto" lets the encoder select the appropriate level based on the input video.', + }, + { + name: 'frameMode', + type: 'string', + defaultValue: '--cfr', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the frame rate mode. Options include:\n' + + '--cfr: Constant Frame Rate.\nEnsures the output video has a constant frame rate.\nUseful for compatibility with some devices.\n' + + '--vfr: Variable Frame Rate.\nAllows the frame rate to vary.\nUseful for reducing file size.\n' + + '--pfr: Peak-Limited Variable Frame Rate.\nEnsures the frame rate does not exceed a certain peak.\n' + + '--vb: Bitrate Variable Frame Rate.\nAdjusts the frame rate based on bitrate settings.\n' + + 'For --cfr, --vfr, or --pfr: Enter the quality value (e.g., "-q 25").', + }, + { + name: 'frameModeExtra', + type: 'string', + defaultValue: '-q 25', + inputUI: { + type: 'text', + }, + tooltip: 'Enter additional parameters for the selected frame rate mode. Examples:\n' + + 'For --cfr: Enter the quality value, e.g., "-q 25".\n' + + 'For --vb: Enter the bitrate value, e.g., "4000kb".\n' + + 'For --vfr or --pfr: Enter the quality value, e.g., "-q 25".', + }, + { + name: 'twoPass', + type: 'boolean', + defaultValue: false, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Enable or disable two-pass encoding for AMD bitrate mode. Two-pass encoding provides better quality by analyzing the video in the first pass and encoding it in the second pass. Useful for achieving a consistent bitrate. Note: Only enable when using --vb mode.', + }, + { + name: 'audioLanguage', + type: 'string', + defaultValue: 'eng,tur,nld,und', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the desired audio languages as comma-separated ISO 639-2 codes (e.g., eng,tur,nld,und). The plugin will include all audio tracks that match the specified languages.', + }, + { + name: 'subtitleLanguage', + type: 'string', + defaultValue: 'eng,tur,nld,und', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the desired subtitle languages as comma-separated ISO 639-2 codes (e.g., eng,tur,nld,und). The plugin will include all subtitle tracks that match the specified languages.', + }, + { + name: 'keepSubtitles', + type: 'boolean', + defaultValue: true, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Toggle to decide whether to keep all subtitles or only those matching the specified languages. "true" will keep only the specified languages. "false" will keep all subtitles.', + }, + { + name: 'audioLanguageOnly', + type: 'boolean', + defaultValue: true, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Toggle to decide whether to keep all audio in the given language or keep all audio from the input. "true" will keep all audio in the given language. "false" will keep all audio from the input.', + }, + { + name: 'customAudioOptions', + type: 'string', + defaultValue: '--audio-copy-mask aac,ac3,eac3,truehd,dts,dtshd,mp3,flac --audio-fallback copy', + inputUI: { + type: 'text', + }, + tooltip: 'Enter any custom audio options. Default is to copy all common audio formats.\n\n' + + '### Possible Commands:\n' + + '- **--audio-lang-list**: Specify audio languages to keep (e.g., "eng,spa").\n' + + '- **--audio-copy-mask**: Preserve specified audio codecs (e.g., "aac,ac3").\n' + + '- **--audio-fallback**: Fallback audio codec if none match the mask (e.g., "copy").\n' + + '- **--all-audio**: Keep all audio tracks.\n' + + '- **--no-audio**: Remove all audio tracks.\n' + + '- **--audio-bitrate**: Set the audio bitrate (e.g., "128k").\n' + + '- **--audio-quality**: Set the audio quality (e.g., "5").\n\n' + + '### Example Use Cases:\n' + + '- Keep all audio tracks: `--all-audio`\n' + + '- Keep only English and Spanish audio tracks: `--audio-lang-list eng,spa`\n' + + '- Preserve AAC and AC3 codecs, fallback to copy: `--audio-copy-mask aac,ac3 --audio-fallback copy`\n' + + '- Set audio bitrate to 128kbps: `--audio-bitrate 128k`\n' + + '- Set audio quality to 5: `--audio-quality 5`', + }, + { + name: 'customArguments', + type: 'string', + inputUI: { + type: 'text', + }, + tooltip: 'Enter any additional custom arguments to be passed to HandBrake. These arguments will be added to the command line for more advanced customization.\n\n' + + '### Possible Commands:\n' + + '- **--crop**: Set the crop values (e.g., "--crop 0:0:0:0").\n' + + '- **--scale**: Set the output resolution (e.g., "--width 1920 --height 1080").\n' + + '- **--rate**: Set the frame rate (e.g., "--rate 30").\n' + + '- **--rotate**: Rotate the video (e.g., "--rotate=4").\n' + + '- **--deinterlace**: Deinterlace the video (e.g., "--deinterlace").\n' + + '- **--denoise**: Apply denoise filter (e.g., "--denoise=weak").\n' + + '- **--deblock**: Apply deblock filter (e.g., "--deblock").\n' + + '- **--custom-anamorphic**: Set custom anamorphic settings.\n\n' + + '### Example Use Cases:\n' + + '- Crop the video: `--crop 0:0:0:0`\n' + + '- Scale to 1080p: `--width 1920 --height 1080`\n' + + '- Set frame rate to 30fps: `--rate 30`\n' + + '- Rotate video: `--rotate=4`\n' + + '- Apply deinterlace filter: `--deinterlace`\n' + + '- Apply denoise filter: `--denoise=weak`\n' + + '- Apply deblock filter: `--deblock`\n' + + '- Set custom anamorphic settings: `--custom-anamorphic`', + }, + ], +}); + +const plugin = (file, librarySettings, inputs, otherArguments) => { + const lib = require('../methods/lib')(); + inputs = lib.loadDefaultValues(inputs, details); + const response = { + processFile: false, + preset: '', + container: '', + handBrakeMode: true, + FFmpegMode: false, + reQueueAfter: false, + infoLog: '', + }; + + const frameRateOptions = inputs.frameModeExtra || ''; + + const audioLanguage = inputs.audioLanguage || 'eng,tur,nld,und'; + const subtitleLanguage = inputs.subtitleLanguage || 'eng,tur,nld,und'; + + let keepSubs = ''; + if (inputs.keepSubtitles) { + keepSubs = `--subtitle-lang-list ${subtitleLanguage}`; + } else { + keepSubs = '--all-subtitles'; + } + + let audioOptions = ''; + if (inputs.audioLanguageOnly) { + audioOptions = `--audio-lang-list ${audioLanguage}`; + } else { + audioOptions = '--all-audio'; + } + + const customAudioOptions = inputs.customAudioOptions || ''; + + const twoPass = inputs.twoPass ? '--two-pass' : ''; + + const videoEncoder = inputs.videoEncoder || 'vce_h264'; + const amfEncoderPreset = inputs.amfEncoderPreset || 'balanced'; + const amfEncoderProfile = inputs.amfEncoderProfile || 'auto'; + const amfEncoderLevel = inputs.amfEncoderLevel || 'auto'; + const container = inputs.container || 'mkv'; + + const customArguments = inputs.customArguments || ''; + + response.preset = `-e ${videoEncoder} --encoder-preset ${amfEncoderPreset} --encoder-profile ${amfEncoderProfile} --encoder-level ${amfEncoderLevel} ${inputs.frameMode} ${frameRateOptions} ${audioOptions} ${customAudioOptions} ${keepSubs} ${twoPass} ${customArguments}`; + response.container = `.${container}`; + response.handBrakeMode = true; + response.FFmpegMode = false; + response.reQueueAfter = true; + response.processFile = true; + response.infoLog += 'File is being transcoded using HandBrake \n'; + + return response; +}; + +module.exports.details = details; +module.exports.plugin = plugin; diff --git a/Community/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_CPU.js b/Community/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_CPU.js new file mode 100644 index 000000000..a7cec9fb9 --- /dev/null +++ b/Community/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_CPU.js @@ -0,0 +1,351 @@ +const details = () => ({ + id: 'Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_CPU', + Stage: 'Pre-processing', + Name: 'DeNiX HandBrake UI Basic Options CPU', + Type: 'Video', + Operation: 'Transcode', + Description: ` + This plugin provides basic HandBrake transcode options through a user-friendly UI. + It allows you to set various video and audio encoding parameters using HandBrake, + including video encoder, frame rate mode, and audio settings. + + Key Features: + - Choose from a variety of CPU video encoders such as svt_av1, svt_av1_10bit, x264, x264_10bit, x265, x265_10bit, x265_12bit, x265_16bit. + - Configure encoder presets, profiles, and levels for CPU encoders. + - Set frame rate modes, including constant (CFR), variable (VFR), peak-limited (PFR), and bitrate (VB). + - Specify video quality or bitrate values. + - Select audio and subtitle languages, with options to keep or delete original tracks. + - Enable or disable two-pass encoding for bitrate mode. + + This plugin is ideal for users who want to leverage HandBrake's powerful encoding capabilities + through a simplified and intuitive interface. + + ### Instructions for the User + - **Frame Rate Mode:** + - **Additional Parameters:** + - If \`--cfr\` is selected, enter the quality value (e.g., \`-q 25\`). + - If \`--vb\` is selected, enter the bitrate value (e.g., \`4000kb\`). + - If \`--vfr\` or \`--pfr\` is selected, enter the quality value (e.g., \`-q 25\`). + - **Two-Pass Encoding:** Only enable when using \`--vb\` mode. Two-pass encoding provides better quality by analyzing the video in the first pass and encoding it in the second pass. + `, + Version: '1.01', + Tags: 'action', + Inputs: [ + { + name: 'container', + type: 'string', + defaultValue: 'mkv', + inputUI: { + type: 'dropdown', + options: [ + 'mkv', + 'mp4', + ], + }, + tooltip: 'Select the output container format. MKV supports more features and codecs than MP4, making it a versatile choice for high-quality videos.', + }, + { + name: 'videoEncoder', + type: 'string', + defaultValue: 'svt_av1', + inputUI: { + type: 'dropdown', + options: [ + 'svt_av1', + 'svt_av1_10bit', + 'x264', + 'x264_10bit', + 'x265', + 'x265_10bit', + 'x265_12bit', + 'x265_16bit', + ], + }, + tooltip: 'Select the video encoder. Options include:\n' + + 'svt_av1: AV1 encoder.\n' + + 'svt_av1_10bit: AV1 10-bit encoder.\n' + + 'x264: H.264 encoder.\n' + + 'x264_10bit: H.264 10-bit encoder.\n' + + 'x265: H.265 encoder.\n' + + 'x265_10bit: H.265 10-bit encoder.\n' + + 'x265_12bit: H.265 12-bit encoder.\n' + + 'x265_16bit: H.265 16-bit encoder.', + }, + { + name: 'encoderPreset', + type: 'string', + defaultValue: 'medium', + inputUI: { + type: 'dropdown', + options: [ + 'ultrafast', + 'superfast', + 'veryfast', + 'faster', + 'fast', + 'medium', + 'slow', + 'slower', + 'veryslow', + ], + }, + tooltip: 'Select the encoder preset for CPU encoders. Options range from "ultrafast" (fastest speed, lowest quality) to "veryslow" (slowest speed, highest quality).', + }, + { + name: 'encoderProfile', + type: 'string', + defaultValue: 'auto', + inputUI: { + type: 'dropdown', + options: [ + 'baseline', + 'main', + 'high', + 'high10', + 'main10', + 'main12', + 'main422_10', + 'main422_12', + 'main444', + 'main444_10', + 'main444_12', + 'auto', + ], + }, + tooltip: 'Select the encoder profile for CPU encoders. Options include:\n' + + 'baseline: Basic profile with minimal compression.\n' + + 'main: Suitable for most use cases with good compatibility.\n' + + 'high: Higher compression and quality.\n' + + 'high10: Supports 10-bit video encoding for higher color depth.\n' + + 'main10: 10-bit main profile.\n' + + 'main12: 12-bit main profile.\n' + + 'main422_10: 10-bit 4:2:2 profile.\n' + + 'main422_12: 12-bit 4:2:2 profile.\n' + + 'main444: 4:4:4 profile.\n' + + 'main444_10: 10-bit 4:4:4 profile.\n' + + 'main444_12: 12-bit 4:4:4 profile.\n' + + 'auto: Automatically choose the best profile based on input and output settings.', + }, + { + name: 'encoderLevel', + type: 'string', + defaultValue: 'auto', + inputUI: { + type: 'dropdown', + options: [ + 'auto', + '1.0', + '1.1', + '1.2', + '1.3', + '2.0', + '2.1', + '2.2', + '3.0', + '3.1', + '3.2', + '4.0', + '4.1', + '4.2', + '5.0', + '5.1', + '5.2', + '6.0', + '6.1', + '6.2', + ], + }, + tooltip: 'Select the encoder level for CPU encoders. The level defines the maximum bitrate and resolution allowed. "auto" lets the encoder select the appropriate level based on the input video.', + }, + { + name: 'frameMode', + type: 'string', + defaultValue: '--cfr', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the frame rate mode. Options include:\n' + + '--cfr: Constant Frame Rate.\nEnsures the output video has a constant frame rate.\nUseful for compatibility with some devices.\n' + + '--vfr: Variable Frame Rate.\nAllows the frame rate to vary.\nUseful for reducing file size.\n' + + '--pfr: Peak-Limited Variable Frame Rate.\nEnsures the frame rate does not exceed a certain peak.\n' + + '--vb: Bitrate Variable Frame Rate.\nAdjusts the frame rate based on bitrate settings.\n' + + 'For --cfr, --vfr, or --pfr: Enter the quality value (e.g., "-q 25").', + }, + { + name: 'frameModeExtra', + type: 'string', + defaultValue: '-q 25', + inputUI: { + type: 'text', + }, + tooltip: 'Enter additional parameters for the selected frame rate mode. Examples:\n' + + 'For --cfr: Enter the quality value, e.g., "-q 25".\n' + + 'For --vb: Enter the bitrate value, e.g., "4000kb".\n' + + 'For --vfr or --pfr: Enter the quality value, e.g., "-q 25".', + }, + { + name: 'twoPass', + type: 'boolean', + defaultValue: false, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Enable or disable two-pass encoding for bitrate mode. Two-pass encoding provides better quality by analyzing the video in the first pass and encoding it in the second pass. Useful for achieving a consistent bitrate. Note: Only enable when using --vb mode.', + }, + { + name: 'audioLanguage', + type: 'string', + defaultValue: 'eng,tur,nld,und', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the desired audio languages as comma-separated ISO 639-2 codes (e.g., eng,tur,nld,und). The plugin will include all audio tracks that match the specified languages.', + }, + { + name: 'subtitleLanguage', + type: 'string', + defaultValue: 'eng,tur,nld,und', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the desired subtitle languages as comma-separated ISO 639-2 codes (e.g., eng,tur,nld,und). The plugin will include all subtitle tracks that match the specified languages.', + }, + { + name: 'keepSubtitles', + type: 'boolean', + defaultValue: true, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Toggle to decide whether to keep all subtitles or only those matching the specified languages. "true" will keep only the specified languages. "false" will keep all subtitles.', + }, + { + name: 'audioLanguageOnly', + type: 'boolean', + defaultValue: true, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Toggle to decide whether to keep all audio in the given language or keep all audio from the input. "true" will keep all audio in the given language. "false" will keep all audio from the input.', + }, + { + name: 'customAudioOptions', + type: 'string', + defaultValue: '--audio-copy-mask aac,ac3,eac3,truehd,dts,dtshd,mp3,flac --audio-fallback copy', + inputUI: { + type: 'text', + }, + tooltip: 'Enter any custom audio options. Default is to copy all common audio formats.\n\n' + + '### Possible Commands:\n' + + '- **--audio-lang-list**: Specify audio languages to keep (e.g., "eng,spa").\n' + + '- **--audio-copy-mask**: Preserve specified audio codecs (e.g., "aac,ac3").\n' + + '- **--audio-fallback**: Fallback audio codec if none match the mask (e.g., "copy").\n' + + '- **--all-audio**: Keep all audio tracks.\n' + + '- **--no-audio**: Remove all audio tracks.\n' + + '- **--audio-bitrate**: Set the audio bitrate (e.g., "128k").\n' + + '- **--audio-quality**: Set the audio quality (e.g., "5").\n\n' + + '### Example Use Cases:\n' + + '- Keep all audio tracks: `--all-audio`\n' + + '- Keep only English and Spanish audio tracks: `--audio-lang-list eng,spa`\n' + + '- Preserve AAC and AC3 codecs, fallback to copy: `--audio-copy-mask aac,ac3 --audio-fallback copy`\n' + + '- Set audio bitrate to 128kbps: `--audio-bitrate 128k`\n' + + '- Set audio quality to 5: `--audio-quality 5`', + }, + { + name: 'customArguments', + type: 'string', + inputUI: { + type: 'text', + }, + tooltip: 'Enter any additional custom arguments to be passed to HandBrake. These arguments will be added to the command line for more advanced customization.\n\n' + + '### Possible Commands:\n' + + '- **--crop**: Set the crop values (e.g., "--crop 0:0:0:0").\n' + + '- **--scale**: Set the output resolution (e.g., "--width 1920 --height 1080").\n' + + '- **--rate**: Set the frame rate (e.g., "--rate 30").\n' + + '- **--rotate**: Rotate the video (e.g., "--rotate=4").\n' + + '- **--deinterlace**: Deinterlace the video (e.g., "--deinterlace").\n' + + '- **--denoise**: Apply denoise filter (e.g., "--denoise=weak").\n' + + '- **--deblock**: Apply deblock filter (e.g., "--deblock").\n' + + '- **--custom-anamorphic**: Set custom anamorphic settings.\n\n' + + '### Example Use Cases:\n' + + '- Crop the video: `--crop 0:0:0:0`\n' + + '- Scale to 1080p: `--width 1920 --height 1080`\n' + + '- Set frame rate to 30fps: `--rate 30`\n' + + '- Rotate video: `--rotate=4`\n' + + '- Apply deinterlace filter: `--deinterlace`\n' + + '- Apply denoise filter: `--denoise=weak`\n' + + '- Apply deblock filter: `--deblock`\n' + + '- Set custom anamorphic settings: `--custom-anamorphic`', + }, + ], +}); + +const plugin = (file, librarySettings, inputs, otherArguments) => { + const lib = require('../methods/lib')(); + inputs = lib.loadDefaultValues(inputs, details); + const response = { + processFile: false, + preset: '', + container: '', + handBrakeMode: true, + FFmpegMode: false, + reQueueAfter: false, + infoLog: '', + }; + + const frameRateOptions = inputs.frameModeExtra || ''; + + const audioLanguage = inputs.audioLanguage || 'eng,tur,nld,und'; + const subtitleLanguage = inputs.subtitleLanguage || 'eng,tur,nld,und'; + + let keepSubs = ''; + if (inputs.keepSubtitles) { + keepSubs = `--subtitle-lang-list ${subtitleLanguage}`; + } else { + keepSubs = '--all-subtitles'; + } + + let audioOptions = ''; + if (inputs.audioLanguageOnly) { + audioOptions = `--audio-lang-list ${audioLanguage}`; + } else { + audioOptions = '--all-audio'; + } + + const customAudioOptions = inputs.customAudioOptions || ''; + + const twoPass = inputs.twoPass ? '--two-pass' : ''; + + const videoEncoder = inputs.videoEncoder || 'x264'; + const encoderPreset = inputs.encoderPreset || 'medium'; + const encoderProfile = inputs.encoderProfile || 'auto'; + const encoderLevel = inputs.encoderLevel || 'auto'; + const container = inputs.container || 'mkv'; + + const customArguments = inputs.customArguments || ''; + + response.preset = `-e ${videoEncoder} --encoder-preset ${encoderPreset} --encoder-profile ${encoderProfile} --encoder-level ${encoderLevel} ${inputs.frameMode} ${frameRateOptions} ${audioOptions} ${customAudioOptions} ${keepSubs} ${twoPass} ${customArguments}`; + response.container = `.${container}`; + response.handBrakeMode = true; + response.FFmpegMode = false; + response.reQueueAfter = true; + response.processFile = true; + response.infoLog += 'File is being transcoded using HandBrake \n'; + + return response; +}; + +module.exports.details = details; +module.exports.plugin = plugin; diff --git a/Community/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_NVIDIA.js b/Community/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_NVIDIA.js new file mode 100644 index 000000000..5315c59f3 --- /dev/null +++ b/Community/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_NVIDIA.js @@ -0,0 +1,350 @@ +const details = () => ({ + id: 'Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_NVENC', + Stage: 'Pre-processing', + Name: 'DeNiX HandBrake UI Basic Options NVENC', + Type: 'Video', + Operation: 'Transcode', + Description: ` + This plugin provides basic HandBrake transcode options through a user-friendly UI. + It allows you to set various video and audio encoding parameters using HandBrake, + including video encoder, frame rate mode, and audio settings. + + Key Features: + - Choose from a variety of NVIDIA NVENC video encoders such as nvenc_h264, nvenc_h265, nvenc_av1, nvenc_h265_10bit, nvenc_av1_10bit. + - Select hardware decoder options or disable them. + - Configure encoder presets, profiles, and levels for NVENC. + - Set frame rate modes, including constant (CFR), variable (VFR), peak-limited (PFR), and bitrate (VB). + - Specify video quality or bitrate values. + - Select audio and subtitle languages, with options to keep or delete original tracks. + - Enable or disable two-pass encoding for bitrate mode. + + This plugin is ideal for users who want to leverage HandBrake's powerful encoding capabilities + through a simplified and intuitive interface. + + ### Instructions for the User + - **Frame Rate Mode:** + - **Additional Parameters:** + - If \`--cfr\` is selected, enter the quality value (e.g., \`-q 25\`). + - If \`--vb\` is selected, enter the bitrate value (e.g., \`4000kb\`). + - If \`--vfr\` or \`--pfr\` is selected, enter the quality value (e.g., \`-q 25\`). + - **Two-Pass Encoding:** Only enable when using \`--vb\` mode. Two-pass encoding provides better quality by analyzing the video in the first pass and encoding it in the second pass. + `, + Version: '1.01', + Tags: 'action', + Inputs: [ + { + name: 'container', + type: 'string', + defaultValue: 'mkv', + inputUI: { + type: 'dropdown', + options: [ + 'mkv', + 'mp4', + ], + }, + tooltip: 'Select the output container format. MKV supports more features and codecs than MP4, making it a versatile choice for high-quality videos.', + }, + { + name: 'videoEncoder', + type: 'string', + defaultValue: 'nvenc_h264', + inputUI: { + type: 'dropdown', + options: [ + 'nvenc_h264', + 'nvenc_h265', + 'nvenc_av1', + 'nvenc_h265_10bit', + 'nvenc_av1_10bit', + ], + }, + tooltip: 'Select the video encoder. Options include:\n' + + 'nvenc_h264: H.264 encoder using NVIDIA NVENC.\n' + + 'nvenc_h265: H.265 encoder using NVIDIA NVENC.\n' + + 'nvenc_av1: AV1 encoder using NVIDIA NVENC.\n' + + 'nvenc_h265_10bit: H.265 10-bit encoder using NVIDIA NVENC.\n' + + 'nvenc_av1_10bit: AV1 10-bit encoder using NVIDIA NVENC.', + }, + { + name: 'videoDecoder', + type: 'string', + defaultValue: 'nvdec', + inputUI: { + type: 'dropdown', + options: [ + 'nvdec', + 'disable', + ], + }, + tooltip: 'Select the video decoder. Options include:\n' + + 'nvdec: Use NVIDIA NVDEC for hardware-accelerated decoding.\n' + + 'disable: Do not use hardware acceleration for decoding.', + }, + { + name: 'nvencEncoderPreset', + type: 'string', + defaultValue: 'p7', + inputUI: { + type: 'dropdown', + options: [ + 'p1', + 'p2', + 'p3', + 'p4', + 'p5', + 'p6', + 'p7', + ], + }, + tooltip: 'Select the encoder preset for NVIDIA encoders. Options include:\n' + + 'p1: Slowest speed, highest quality.\n' + + 'p2: Slower speed, higher quality.\n' + + 'p3: Slow speed, high quality.\n' + + 'p4: Medium speed, medium quality.\n' + + 'p5: Fast speed, medium quality.\n' + + 'p6: Faster speed, lower quality.\n' + + 'p7: Fastest speed, lowest quality.', + }, + { + name: 'nvencEncoderProfile', + type: 'string', + defaultValue: 'auto', + inputUI: { + type: 'dropdown', + options: [ + 'main', + 'main10', + 'auto', + ], + }, + tooltip: 'Select the encoder profile for NVIDIA encoders. Options include:\n' + + 'main: Suitable for most use cases with good compatibility.\n' + + 'main10: Supports 10-bit video encoding for higher color depth.\n' + + 'auto: Automatically choose the best profile based on input and output settings.', + }, + { + name: 'encoderLevel', + type: 'string', + defaultValue: 'auto', + inputUI: { + type: 'dropdown', + options: [ + 'auto', + '1.0', + '1.1', + '1.2', + '1.3', + '2.0', + '2.1', + '2.2', + '3.0', + '3.1', + '3.2', + '4.0', + '4.1', + '4.2', + '5.0', + '5.1', + '5.2', + '6.0', + '6.1', + '6.2', + ], + }, + tooltip: 'Select the encoder level for NVENC encoders. The level defines the maximum bitrate and resolution allowed. "auto" lets the encoder select the appropriate level based on the input video.', + }, + { + name: 'frameMode', + type: 'string', + defaultValue: '--cfr', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the frame rate mode. Options include:\n' + + '--cfr: Constant Frame Rate.\nEnsures the output video has a constant frame rate.\nUseful for compatibility with some devices.\n' + + '--vfr: Variable Frame Rate.\nAllows the frame rate to vary.\nUseful for reducing file size.\n' + + '--pfr: Peak-Limited Variable Frame Rate.\nEnsures the frame rate does not exceed a certain peak.\n' + + '--vb: Bitrate Variable Frame Rate.\nAdjusts the frame rate based on bitrate settings.\n' + + 'For --cfr, --vfr, or --pfr: Enter the quality value (e.g., "-q 25").', + }, + { + name: 'frameModeExtra', + type: 'string', + defaultValue: '-q 25', + inputUI: { + type: 'text', + }, + tooltip: 'Enter additional parameters for the selected frame rate mode. Examples:\n' + + 'For --cfr: Enter the quality value, e.g., "-q 25".\n' + + 'For --vb: Enter the bitrate value, e.g., "4000kb".\n' + + 'For --vfr or --pfr: Enter the quality value, e.g., "-q 25".', + }, + { + name: 'twoPass', + type: 'boolean', + defaultValue: false, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Enable or disable two-pass encoding for bitrate mode. Two-pass encoding provides better quality by analyzing the video in the first pass and encoding it in the second pass. Useful for achieving a consistent bitrate. Note: Only enable when using --vb mode.', + }, + { + name: 'audioLanguage', + type: 'string', + defaultValue: 'eng,tur,nld,und', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the desired audio languages as comma-separated ISO 639-2 codes (e.g., eng,tur,nld,und). The plugin will include all audio tracks that match the specified languages.', + }, + { + name: 'subtitleLanguage', + type: 'string', + defaultValue: 'eng,tur,nld,und', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the desired subtitle languages as comma-separated ISO 639-2 codes (e.g., eng,tur,nld,und). The plugin will include all subtitle tracks that match the specified languages.', + }, + { + name: 'keepSubtitles', + type: 'boolean', + defaultValue: true, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Toggle to decide whether to keep all subtitles or only those matching the specified languages. "true" will keep only the specified languages. "false" will keep all subtitles.', + }, + { + name: 'audioLanguageOnly', + type: 'boolean', + defaultValue: true, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Toggle to decide whether to keep all audio in the given language or keep all audio from the input. "true" will keep all audio in the given language. "false" will keep all audio from the input.', + }, + { + name: 'customAudioOptions', + type: 'string', + defaultValue: '--audio-copy-mask aac,ac3,eac3,truehd,dts,dtshd,mp3,flac --audio-fallback copy', + inputUI: { + type: 'text', + }, + tooltip: 'Enter any custom audio options. Default is to copy all common audio formats.\n\n' + + '### Possible Commands:\n' + + '- **--audio-lang-list**: Specify audio languages to keep (e.g., "eng,spa").\n' + + '- **--audio-copy-mask**: Preserve specified audio codecs (e.g., "aac,ac3").\n' + + '- **--audio-fallback**: Fallback audio codec if none match the mask (e.g., "copy").\n' + + '- **--all-audio**: Keep all audio tracks.\n' + + '- **--no-audio**: Remove all audio tracks.\n' + + '- **--audio-bitrate**: Set the audio bitrate (e.g., "128k").\n' + + '- **--audio-quality**: Set the audio quality (e.g., "5").\n\n' + + '### Example Use Cases:\n' + + '- Keep all audio tracks: `--all-audio`\n' + + '- Keep only English and Spanish audio tracks: `--audio-lang-list eng,spa`\n' + + '- Preserve AAC and AC3 codecs, fallback to copy: `--audio-copy-mask aac,ac3 --audio-fallback copy`\n' + + '- Set audio bitrate to 128kbps: `--audio-bitrate 128k`\n' + + '- Set audio quality to 5: `--audio-quality 5`', + }, + { + name: 'customArguments', + type: 'string', + inputUI: { + type: 'text', + }, + tooltip: 'Enter any additional custom arguments to be passed to HandBrake. These arguments will be added to the command line for more advanced customization.\n\n' + + '### Possible Commands:\n' + + '- **--crop**: Set the crop values (e.g., "--crop 0:0:0:0").\n' + + '- **--scale**: Set the output resolution (e.g., "--width 1920 --height 1080").\n' + + '- **--rate**: Set the frame rate (e.g., "--rate 30").\n' + + '- **--rotate**: Rotate the video (e.g., "--rotate=4").\n' + + '- **--deinterlace**: Deinterlace the video (e.g., "--deinterlace").\n' + + '- **--denoise**: Apply denoise filter (e.g., "--denoise=weak").\n' + + '- **--deblock**: Apply deblock filter (e.g., "--deblock").\n' + + '- **--custom-anamorphic**: Set custom anamorphic settings.\n\n' + + '### Example Use Cases:\n' + + '- Crop the video: `--crop 0:0:0:0`\n' + + '- Scale to 1080p: `--width 1920 --height 1080`\n' + + '- Set frame rate to 30fps: `--rate 30`\n' + + '- Rotate video: `--rotate=4`\n' + + '- Apply deinterlace filter: `--deinterlace`\n' + + '- Apply denoise filter: `--denoise=weak`\n' + + '- Apply deblock filter: `--deblock`\n' + + '- Set custom anamorphic settings: `--custom-anamorphic`', + }, + ], +}); + +const plugin = (file, librarySettings, inputs, otherArguments) => { + const lib = require('../methods/lib')(); + inputs = lib.loadDefaultValues(inputs, details); + const response = { + processFile: false, + preset: '', + container: '', + handBrakeMode: true, + FFmpegMode: false, + reQueueAfter: false, + infoLog: '', + }; + + const decoder = inputs.videoDecoder === 'disable' ? '--disable-hw-decoding' : `--enable-hw-decoding ${inputs.videoDecoder}`; + + const frameRateOptions = inputs.frameModeExtra || ''; + + const audioLanguage = inputs.audioLanguage || 'eng,tur,nld,und'; + const subtitleLanguage = inputs.subtitleLanguage || 'eng,tur,nld,und'; + + let keepSubs = ''; + if (inputs.keepSubtitles) { + keepSubs = `--subtitle-lang-list ${subtitleLanguage}`; + } else { + keepSubs = '--all-subtitles'; + } + + let audioOptions = ''; + if (inputs.audioLanguageOnly) { + audioOptions = `--audio-lang-list ${audioLanguage}`; + } else { + audioOptions = '--all-audio'; + } + + const customAudioOptions = inputs.customAudioOptions || ''; + + const twoPass = inputs.twoPass ? '--two-pass' : ''; + + const videoEncoder = inputs.videoEncoder || 'nvenc_h264'; + const nvencEncoderPreset = inputs.nvencEncoderPreset || 'p7'; + const nvencEncoderProfile = inputs.nvencEncoderProfile || 'auto'; + const encoderLevel = inputs.encoderLevel || 'auto'; + const container = inputs.container || 'mkv'; + + const customArguments = inputs.customArguments || ''; + + response.preset = `${decoder} -e ${videoEncoder} --encoder-preset ${nvencEncoderPreset} --encoder-profile ${nvencEncoderProfile} --encoder-level ${encoderLevel} ${inputs.frameMode} ${frameRateOptions} ${audioOptions} ${customAudioOptions} ${keepSubs} ${twoPass} ${customArguments}`; + response.container = `.${container}`; + response.handBrakeMode = true; + response.FFmpegMode = false; + response.reQueueAfter = true; + response.processFile = true; + response.infoLog += 'File is being transcoded using HandBrake \n'; + + return response; +}; + +module.exports.details = details; +module.exports.plugin = plugin; diff --git a/Community/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_QSV.js b/Community/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_QSV.js new file mode 100644 index 000000000..0163144b4 --- /dev/null +++ b/Community/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_QSV.js @@ -0,0 +1,361 @@ +const details = () => ({ + id: 'Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_QSV', + Stage: 'Pre-processing', + Name: 'DeNiX HandBrake UI Basic Options QSV', + Type: 'Video', + Operation: 'Transcode', + Description: ` + This plugin provides basic HandBrake transcode options through a user-friendly UI. + It allows you to set various video and audio encoding parameters using HandBrake, + including video encoder, decoder, frame rate mode, and audio settings. + + Key Features: + - Choose from a variety of Intel QSV video encoders such as qsv_h264, qsv_h265, qsv_av1, qsv_h264_10bit, qsv_h265_10bit, qsv_av1_10bit. + - Select hardware decoder options or disable them. + - Configure encoder presets, profiles, and levels for QSV. + - Set frame rate modes, including constant (CFR), variable (VFR), peak-limited (PFR), and bitrate (VB). + - Specify video quality or bitrate values. + - Select audio and subtitle languages, with options to keep or delete original tracks. + - Enable or disable turbo mode and two-pass encoding for QSV bitrate mode. + + This plugin is ideal for users who want to leverage HandBrake's powerful encoding capabilities + through a simplified and intuitive interface. + + ### Instructions for the User + - **Frame Rate Mode:** + - **Additional Parameters:** + - If \`--cfr\` is selected, enter the quality value (e.g., \`-q 25\`). + - If \`--vb\` is selected, enter the bitrate value (e.g., \`4000kb\`). + - If \`--vfr\` or \`--pfr\` is selected, enter the quality value (e.g., \`-q 25\`). + - **Turbo Mode:** Only enable when using \`--vb\` mode. Turbo mode increases encoding speed at the cost of output quality. + - **Two-Pass Encoding:** Only enable when using \`--vb\` mode. Two-pass encoding provides better quality by analyzing the video in the first pass and encoding it in the second pass. + `, + Version: '1.01', + Tags: 'action', + Inputs: [ + { + name: 'container', + type: 'string', + defaultValue: 'mkv', + inputUI: { + type: 'dropdown', + options: [ + 'mkv', + 'mp4', + ], + }, + tooltip: 'Select the output container format. MKV supports more features and codecs than MP4, making it a versatile choice for high-quality videos.', + }, + { + name: 'videoEncoder', + type: 'string', + defaultValue: 'qsv_av1', + inputUI: { + type: 'dropdown', + options: [ + 'qsv_h264', + 'qsv_h265', + 'qsv_av1', + 'qsv_h264_10bit', + 'qsv_h265_10bit', + 'qsv_av1_10bit', + ], + }, + tooltip: 'Select the video encoder. Options include:\n' + + 'qsv_h264: H.264 encoder using Intel Quick Sync Video.\n' + + 'qsv_h265: H.265 encoder using Intel Quick Sync Video.\n' + + 'qsv_av1: AV1 encoder using Intel Quick Sync Video. AV1 offers better compression rates compared to H.264 and H.265.\n' + + 'qsv_h264_10bit: H.264 10-bit encoder using Intel Quick Sync Video.\n' + + 'qsv_h265_10bit: H.265 10-bit encoder using Intel Quick Sync Video.\n' + + 'qsv_av1_10bit: AV1 10-bit encoder using Intel Quick Sync Video.', + }, + { + name: 'videoDecoder', + type: 'string', + defaultValue: 'qsv', + inputUI: { + type: 'dropdown', + options: [ + 'qsv', + 'disable', + ], + }, + tooltip: 'Select the video decoder. Options include:\n' + + 'qsv: Use Intel Quick Sync Video for hardware-accelerated decoding.\n' + + 'disable: Do not use hardware acceleration for decoding.', + }, + { + name: 'qsvEncoderPreset', + type: 'string', + defaultValue: 'balanced', + inputUI: { + type: 'dropdown', + options: [ + 'speed', + 'balanced', + 'quality', + ], + }, + tooltip: 'Select the encoder preset for QSV encoders. Options include:\n' + + 'speed: Prioritize encoding speed over quality.\n' + + 'balanced: Balance between speed and quality.\n' + + 'quality: Prioritize output quality over encoding speed.', + }, + { + name: 'qsvEncoderProfile', + type: 'string', + defaultValue: 'auto', + inputUI: { + type: 'dropdown', + options: [ + 'main', + 'main-still-picture', + 'main10', + 'auto', + ], + }, + tooltip: 'Select the encoder profile for QSV encoders. Options include:\n' + + 'main: Suitable for most use cases with good compatibility.\n' + + 'main-still-picture: Optimized for still images.\n' + + 'main10: Supports 10-bit video encoding for higher color depth.\n' + + 'auto: Automatically choose the best profile based on input and output settings.', + }, + { + name: 'qsvEncoderLevel', + type: 'string', + defaultValue: 'auto', + inputUI: { + type: 'dropdown', + options: [ + 'auto', + '1.0', + '1.1', + '1.2', + '1.3', + '2.0', + '2.1', + '2.2', + '3.0', + '3.1', + '3.2', + '4.0', + '4.1', + '4.2', + '5.0', + '5.1', + '5.2', + '6.0', + '6.1', + '6.2', + ], + }, + tooltip: 'Select the encoder level for QSV encoders. The level defines the maximum bitrate and resolution allowed. "auto" lets the encoder select the appropriate level based on the input video.', + }, + { + name: 'frameMode', + type: 'string', + defaultValue: '--cfr', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the frame rate mode. Options include:\n' + + '--cfr: Constant Frame Rate.\nEnsures the output video has a constant frame rate.\nUseful for compatibility with some devices.\n' + + '--vfr: Variable Frame Rate.\nAllows the frame rate to vary.\nUseful for reducing file size.\n' + + '--pfr: Peak-Limited Variable Frame Rate.\nEnsures the frame rate does not exceed a certain peak.\n' + + '--vb: Bitrate Variable Frame Rate.\nAdjusts the frame rate based on bitrate settings.\n' + + 'For --cfr, --vfr, or --pfr: Enter the quality value (e.g., "-q 25").', + }, + { + name: 'frameModeExtra', + type: 'string', + defaultValue: '-q 25', + inputUI: { + type: 'text', + }, + tooltip: 'Enter additional parameters for the selected frame rate mode. Examples:\n' + + 'For --cfr: Enter the quality value, e.g., "-q 25".\n' + + 'For --vb: Enter the bitrate value, e.g., "4000kb".\n' + + 'For --vfr or --pfr: Enter the quality value, e.g., "-q 25".', + }, + { + name: 'turbo', + type: 'boolean', + defaultValue: false, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Enable or disable turbo mode for QSV bitrate mode. Turbo mode increases encoding speed at the cost of output quality. Useful for quick encodes when quality is less critical. Note: Only enable when using --vb mode.', + }, + { + name: 'twoPass', + type: 'boolean', + defaultValue: false, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Enable or disable two-pass encoding for QSV bitrate mode. Two-pass encoding provides better quality by analyzing the video in the first pass and encoding it in the second pass. Useful for achieving a consistent bitrate. Note: Only enable when using --vb mode.', + }, + { + name: 'audioLanguage', + type: 'string', + defaultValue: 'eng,tur,nld,und', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the desired audio languages as comma-separated ISO 639-2 codes (e.g., eng,tur,nld,und). The plugin will include all audio tracks that match the specified languages.', + }, + { + name: 'subtitleLanguage', + type: 'string', + defaultValue: 'eng,tur,nld,und', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the desired subtitle languages as comma-separated ISO 639-2 codes (e.g., eng,tur,nld,und). The plugin will include all subtitle tracks that match the specified languages.', + }, + { + name: 'keepSubtitles', + type: 'boolean', + defaultValue: true, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Toggle to decide whether to keep all subtitles or only those matching the specified languages. "true" will keep only the specified languages. "false" will keep all subtitles.', + }, + { + name: 'audioLanguageOnly', + type: 'boolean', + defaultValue: true, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Toggle to decide whether to keep all audio in the given language or keep all audio from the input. "true" will keep all audio in the given language. "false" will keep all audio from the input.', + }, + { + name: 'customAudioOptions', + type: 'string', + defaultValue: '--audio-copy-mask aac,ac3,eac3,truehd,dts,dtshd,mp3,flac --audio-fallback copy', + inputUI: { + type: 'text', + }, + tooltip: 'Enter any custom audio options. Default is to copy all common audio formats.\n\n' + + '### Possible Commands:\n' + + '- **--audio-lang-list**: Specify audio languages to keep (e.g., "eng,spa").\n' + + '- **--audio-copy-mask**: Preserve specified audio codecs (e.g., "aac,ac3").\n' + + '- **--audio-fallback**: Fallback audio codec if none match the mask (e.g., "copy").\n' + + '- **--all-audio**: Keep all audio tracks.\n' + + '- **--no-audio**: Remove all audio tracks.\n' + + '- **--audio-bitrate**: Set the audio bitrate (e.g., "128k").\n' + + '- **--audio-quality**: Set the audio quality (e.g., "5").\n\n' + + '### Example Use Cases:\n' + + '- Keep all audio tracks: `--all-audio`\n' + + '- Keep only English and Spanish audio tracks: `--audio-lang-list eng,spa`\n' + + '- Preserve AAC and AC3 codecs, fallback to copy: `--audio-copy-mask aac,ac3 --audio-fallback copy`\n' + + '- Set audio bitrate to 128kbps: `--audio-bitrate 128k`\n' + + '- Set audio quality to 5: `--audio-quality 5`', + }, + { + name: 'customArguments', + type: 'string', + inputUI: { + type: 'text', + }, + tooltip: 'Enter any additional custom arguments to be passed to HandBrake. These arguments will be added to the command line for more advanced customization.\n\n' + + '### Possible Commands:\n' + + '- **--crop**: Set the crop values (e.g., "--crop 0:0:0:0").\n' + + '- **--scale**: Set the output resolution (e.g., "--width 1920 --height 1080").\n' + + '- **--rate**: Set the frame rate (e.g., "--rate 30").\n' + + '- **--rotate**: Rotate the video (e.g., "--rotate=4").\n' + + '- **--deinterlace**: Deinterlace the video (e.g., "--deinterlace").\n' + + '- **--denoise**: Apply denoise filter (e.g., "--denoise=weak").\n' + + '- **--deblock**: Apply deblock filter (e.g., "--deblock").\n' + + '- **--custom-anamorphic**: Set custom anamorphic settings.\n\n' + + '### Example Use Cases:\n' + + '- Crop the video: `--crop 0:0:0:0`\n' + + '- Scale to 1080p: `--width 1920 --height 1080`\n' + + '- Set frame rate to 30fps: `--rate 30`\n' + + '- Rotate video: `--rotate=4`\n' + + '- Apply deinterlace filter: `--deinterlace`\n' + + '- Apply denoise filter: `--denoise=weak`\n' + + '- Apply deblock filter: `--deblock`\n' + + '- Set custom anamorphic settings: `--custom-anamorphic`', + }, + ], +}); + +const plugin = (file, librarySettings, inputs, otherArguments) => { + const lib = require('../methods/lib')(); + inputs = lib.loadDefaultValues(inputs, details); + const response = { + processFile: false, + preset: '', + container: '', + handBrakeMode: true, + FFmpegMode: false, + reQueueAfter: false, + infoLog: '', + }; + + const decoder = inputs.videoDecoder === 'disable' ? '--disable-hw-decoding' : `--enable-hw-decoding ${inputs.videoDecoder}`; + + const frameRateOptions = inputs.frameModeExtra || ''; + + const audioLanguage = inputs.audioLanguage || 'eng,tur,nld,und'; + const subtitleLanguage = inputs.subtitleLanguage || 'eng,tur,nld,und'; + + let keepSubs = ''; + if (inputs.keepSubtitles) { + keepSubs = `--subtitle-lang-list ${subtitleLanguage}`; + } else { + keepSubs = '--all-subtitles'; + } + + let audioOptions = ''; + if (inputs.audioLanguageOnly) { + audioOptions = `--audio-lang-list ${audioLanguage}`; + } else { + audioOptions = '--all-audio'; + } + + const customAudioOptions = inputs.customAudioOptions || ''; + + const turbo = inputs.turbo ? '--turbo' : ''; + const twoPass = inputs.twoPass ? '--two-pass' : ''; + + const videoEncoder = inputs.videoEncoder || 'qsv_h264'; + const qsvEncoderPreset = inputs.qsvEncoderPreset || 'balanced'; + const qsvEncoderProfile = inputs.qsvEncoderProfile || 'auto'; + const qsvEncoderLevel = inputs.qsvEncoderLevel || 'auto'; + const container = inputs.container || 'mkv'; + + const customArguments = inputs.customArguments || ''; + + response.preset = `${decoder} -e ${videoEncoder} --encoder-preset ${qsvEncoderPreset} --encoder-profile ${qsvEncoderProfile} --encoder-level ${qsvEncoderLevel} ${inputs.frameMode} ${frameRateOptions} ${audioOptions} ${customAudioOptions} ${keepSubs} ${turbo} ${twoPass} ${customArguments}`; + response.container = `.${container}`; + response.handBrakeMode = true; + response.FFmpegMode = false; + response.reQueueAfter = true; + response.processFile = true; + response.infoLog += 'File is being transcoded using HandBrake \n'; + + return response; +}; + +module.exports.details = details; +module.exports.plugin = plugin; diff --git a/Community/Tdarr_Plugin_DeNiX_rename_files_based_on_resolution.js b/Community/Tdarr_Plugin_DeNiX_rename_files_based_on_resolution.js new file mode 100644 index 000000000..3db62019e --- /dev/null +++ b/Community/Tdarr_Plugin_DeNiX_rename_files_based_on_resolution.js @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// tdarrSkipTest +const details = () => { + return { + id: "Tdarr_Plugin_DeNiX_rename_files_based_on_resolution", + Stage: "Post-processing", + Name: "Rename Based On Resolution", + Type: "Video", + Operation: "Transcode", + Description: [Contains built-in filter] If the filename contains resolution indicators such as '720p', '1080p', '2160p', '4K', '480p', etc., this plugin renames files to match the actual resolution of the video stream. \n\n, + Version: "1.00", + Tags: "post-processing", + Inputs: [] + }; +}; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const plugin = (file, librarySettings, inputs, otherArguments) => { + const lib = require('../methods/lib')(); + inputs = lib.loadDefaultValues(inputs, details); + + try { + const fs = require("fs"); + const fileNameOld = file._id; + const width = file.ffProbeData.streams[0].width; + let resolution; + + if (width >= 3840) { + resolution = "2160p"; + } else if (width >= 1920) { + resolution = "1080p"; + } else if (width >= 1280) { + resolution = "720p"; + } else if (width >= 640) { + resolution = "480p"; + } else { + resolution = "SD"; + } + + console.log(Detected resolution: ${resolution}); + + const regex = /720p|1080p|2160p|4K|480p/; + if (regex.test(file._id)) { + file._id = file._id.replace(regex, resolution); + file.file = file.file.replace(regex, resolution); + } + + if (fileNameOld !== file._id) { + fs.renameSync(fileNameOld, file._id, { overwrite: true }); + + return { + file, + removeFromDB: false, + updateDB: true, + }; + } + } catch (err) { + console.log(Error renaming file: ${err.message}); + } + + return { + file, + removeFromDB: false, + updateDB: false, + }; +}; + +module.exports.details = details; +module.exports.plugin = plugin; diff --git a/FlowPlugins/CommunityFlowPlugins/video/checkDoViProfile b/FlowPlugins/CommunityFlowPlugins/video/checkDoViProfile new file mode 100644 index 000000000..e69de29bb diff --git a/FlowPlugins/CommunityFlowPlugins/video/checkHDRType b/FlowPlugins/CommunityFlowPlugins/video/checkHDRType new file mode 100644 index 000000000..e69de29bb diff --git a/FlowPlugins/CommunityFlowPlugins/video/extractDoViRpu b/FlowPlugins/CommunityFlowPlugins/video/extractDoViRpu new file mode 100644 index 000000000..e69de29bb diff --git a/FlowPlugins/CommunityFlowPlugins/video/injectDoViRpu b/FlowPlugins/CommunityFlowPlugins/video/injectDoViRpu new file mode 100644 index 000000000..e69de29bb diff --git a/FlowPlugins/CommunityFlowPlugins/video/packageDoViMp4 b/FlowPlugins/CommunityFlowPlugins/video/packageDoViMp4 new file mode 100644 index 000000000..e69de29bb diff --git a/Local/Readme.MD b/Local/Readme.MD new file mode 100644 index 000000000..dae064f3a --- /dev/null +++ b/Local/Readme.MD @@ -0,0 +1,2 @@ + +Here I keep plugins created by me. diff --git a/Local/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_AMD.js b/Local/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_AMD.js new file mode 100644 index 000000000..5810f57b1 --- /dev/null +++ b/Local/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_AMD.js @@ -0,0 +1,324 @@ +const details = () => ({ + id: 'Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_AMD', + Stage: 'Pre-processing', + Name: 'DeNiX HandBrake UI Basic Options AMD', + Type: 'Video', + Operation: 'Transcode', + Description: ` + This plugin provides basic HandBrake transcode options through a user-friendly UI. + It allows you to set various video and audio encoding parameters using HandBrake, + including video encoder, frame rate mode, and audio settings. + + Key Features: + - Choose from a variety of AMD video encoders such as vce_h264, vce_h265, vce_h265_10bit, vce_av1, vce_av1_10bit. + - Configure encoder presets, profiles, and levels for AMD. + - Set frame rate modes, including constant (CFR), variable (VFR), peak-limited (PFR), and bitrate (VB). + - Specify video quality or bitrate values. + - Select audio and subtitle languages, with options to keep or delete original tracks. + - Enable or disable two-pass encoding for AMD bitrate mode. + + This plugin is ideal for users who want to leverage HandBrake's powerful encoding capabilities + through a simplified and intuitive interface. + + ### Instructions for the User + - **Frame Rate Mode:** + - **Additional Parameters:** + - If \`--cfr\` is selected, enter the quality value (e.g., \`-q 25\`). + - If \`--vb\` is selected, enter the bitrate value (e.g., \`4000kb\`). + - If \`--vfr\` or \`--pfr\` is selected, enter the quality value (e.g., \`-q 25\`). + - **Two-Pass Encoding:** Only enable when using \`--vb\` mode. Two-pass encoding provides better quality by analyzing the video in the first pass and encoding it in the second pass. + `, + Version: '1.01', + Tags: 'action', + Inputs: [ + { + name: 'container', + type: 'string', + defaultValue: 'mkv', + inputUI: { + type: 'dropdown', + options: [ + 'mkv', + 'mp4', + ], + }, + tooltip: 'Select the output container format. MKV supports more features and codecs than MP4, making it a versatile choice for high-quality videos.', + }, + { + name: 'videoEncoder', + type: 'string', + defaultValue: 'vce_av1', + inputUI: { + type: 'dropdown', + options: [ + 'vce_h264', + 'vce_h265', + 'vce_h265_10bit', + 'vce_av1', + 'vce_av1_10bit', + ], + }, + tooltip: 'Select the video encoder. Options include:\n' + + 'vce_h264: H.264 encoder using AMD VCE.\n' + + 'vce_h265: H.265 encoder using AMD VCE.\n' + + 'vce_h265_10bit: H.265 10-bit encoder using AMD VCE.\n' + + 'vce_av1: AV1 encoder using AMD VCE.\n' + + 'vce_av1_10bit: AV1 10-bit encoder using AMD VCE.', + }, + { + name: 'amfEncoderPreset', + type: 'string', + defaultValue: 'quality', + inputUI: { + type: 'dropdown', + options: [ + 'speed', + 'balanced', + 'quality', + ], + }, + tooltip: 'Select the encoder preset for AMD encoders. Options include:\n' + + 'speed: Prioritize encoding speed over quality.\n' + + 'balanced: Balance between speed and quality.\n' + + 'quality: Prioritize output quality over encoding speed.', + }, + { + name: 'amfEncoderProfile', + type: 'string', + defaultValue: 'auto', + inputUI: { + type: 'dropdown', + options: [ + 'main', + 'main10', + 'auto', + ], + }, + tooltip: 'Select the encoder profile for AMD encoders. Options include:\n' + + 'main: Suitable for most use cases with good compatibility.\n' + + 'main10: Supports 10-bit video encoding for higher color depth.\n' + + 'auto: Automatically choose the best profile based on input and output settings.', + }, + { + name: 'amfEncoderLevel', + type: 'string', + defaultValue: 'auto', + inputUI: { + type: 'dropdown', + options: [ + 'auto', + '1.0', + '1.1', + '1.2', + '1.3', + '2.0', + '2.1', + '2.2', + '3.0', + '3.1', + '3.2', + '4.0', + '4.1', + '4.2', + '5.0', + '5.1', + '5.2', + '6.0', + '6.1', + '6.2', + ], + }, + tooltip: 'Select the encoder level for AMD encoders. The level defines the maximum bitrate and resolution allowed. "auto" lets the encoder select the appropriate level based on the input video.', + }, + { + name: 'frameMode', + type: 'string', + defaultValue: '--cfr', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the frame rate mode. Options include:\n' + + '--cfr: Constant Frame Rate.\nEnsures the output video has a constant frame rate.\nUseful for compatibility with some devices.\n' + + '--vfr: Variable Frame Rate.\nAllows the frame rate to vary.\nUseful for reducing file size.\n' + + '--pfr: Peak-Limited Variable Frame Rate.\nEnsures the frame rate does not exceed a certain peak.\n' + + '--vb: Bitrate Variable Frame Rate.\nAdjusts the frame rate based on bitrate settings.\n' + + 'For --cfr, --vfr, or --pfr: Enter the quality value (e.g., "-q 25").', + }, + { + name: 'frameModeExtra', + type: 'string', + defaultValue: '-q 25', + inputUI: { + type: 'text', + }, + tooltip: 'Enter additional parameters for the selected frame rate mode. Examples:\n' + + 'For --cfr: Enter the quality value, e.g., "-q 25".\n' + + 'For --vb: Enter the bitrate value, e.g., "4000kb".\n' + + 'For --vfr or --pfr: Enter the quality value, e.g., "-q 25".', + }, + { + name: 'twoPass', + type: 'boolean', + defaultValue: false, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Enable or disable two-pass encoding for AMD bitrate mode. Two-pass encoding provides better quality by analyzing the video in the first pass and encoding it in the second pass. Useful for achieving a consistent bitrate. Note: Only enable when using --vb mode.', + }, + { + name: 'audioLanguage', + type: 'string', + defaultValue: 'eng,tur,nld,und', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the desired audio languages as comma-separated ISO 639-2 codes (e.g., eng,tur,nld,und). The plugin will include all audio tracks that match the specified languages.', + }, + { + name: 'subtitleLanguage', + type: 'string', + defaultValue: 'eng,tur,nld,und', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the desired subtitle languages as comma-separated ISO 639-2 codes (e.g., eng,tur,nld,und). The plugin will include all subtitle tracks that match the specified languages.', + }, + { + name: 'keepSubtitles', + type: 'boolean', + defaultValue: true, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Toggle to decide whether to keep all subtitles or only those matching the specified languages. "true" will keep only the specified languages. "false" will keep all subtitles.', + }, + { + name: 'audioLanguageOnly', + type: 'boolean', + defaultValue: true, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Toggle to decide whether to keep all audio in the given language or keep all audio from the input. "true" will keep all audio in the given language. "false" will keep all audio from the input.', + }, + { + name: 'customAudioOptions', + type: 'string', + defaultValue: '--audio-copy-mask aac,ac3,eac3,truehd,dts,dtshd,mp3,flac --audio-fallback copy', + inputUI: { + type: 'text', + }, + tooltip: 'Enter any custom audio options. Default is to copy all common audio formats.\n\n' + + '### Possible Commands:\n' + + '- **--audio-lang-list**: Specify audio languages to keep (e.g., "eng,spa").\n' + + '- **--audio-copy-mask**: Preserve specified audio codecs (e.g., "aac,ac3").\n' + + '- **--audio-fallback**: Fallback audio codec if none match the mask (e.g., "copy").\n' + + '- **--all-audio**: Keep all audio tracks.\n' + + '- **--no-audio**: Remove all audio tracks.\n' + + '- **--audio-bitrate**: Set the audio bitrate (e.g., "128k").\n' + + '- **--audio-quality**: Set the audio quality (e.g., "5").\n\n' + + '### Example Use Cases:\n' + + '- Keep all audio tracks: `--all-audio`\n' + + '- Keep only English and Spanish audio tracks: `--audio-lang-list eng,spa`\n' + + '- Preserve AAC and AC3 codecs, fallback to copy: `--audio-copy-mask aac,ac3 --audio-fallback copy`\n' + + '- Set audio bitrate to 128kbps: `--audio-bitrate 128k`\n' + + '- Set audio quality to 5: `--audio-quality 5`', + }, + { + name: 'customArguments', + type: 'string', + inputUI: { + type: 'text', + }, + tooltip: 'Enter any additional custom arguments to be passed to HandBrake. These arguments will be added to the command line for more advanced customization.\n\n' + + '### Possible Commands:\n' + + '- **--crop**: Set the crop values (e.g., "--crop 0:0:0:0").\n' + + '- **--scale**: Set the output resolution (e.g., "--width 1920 --height 1080").\n' + + '- **--rate**: Set the frame rate (e.g., "--rate 30").\n' + + '- **--rotate**: Rotate the video (e.g., "--rotate=4").\n' + + '- **--deinterlace**: Deinterlace the video (e.g., "--deinterlace").\n' + + '- **--denoise**: Apply denoise filter (e.g., "--denoise=weak").\n' + + '- **--deblock**: Apply deblock filter (e.g., "--deblock").\n' + + '- **--custom-anamorphic**: Set custom anamorphic settings.\n\n' + + '### Example Use Cases:\n' + + '- Crop the video: `--crop 0:0:0:0`\n' + + '- Scale to 1080p: `--width 1920 --height 1080`\n' + + '- Set frame rate to 30fps: `--rate 30`\n' + + '- Rotate video: `--rotate=4`\n' + + '- Apply deinterlace filter: `--deinterlace`\n' + + '- Apply denoise filter: `--denoise=weak`\n' + + '- Apply deblock filter: `--deblock`\n' + + '- Set custom anamorphic settings: `--custom-anamorphic`', + }, + ], +}); + +const plugin = (file, librarySettings, inputs, otherArguments) => { + const lib = require('../methods/lib')(); + inputs = lib.loadDefaultValues(inputs, details); + const response = { + processFile: false, + preset: '', + container: '', + handBrakeMode: true, + FFmpegMode: false, + reQueueAfter: false, + infoLog: '', + }; + + const frameRateOptions = inputs.frameModeExtra || ''; + + const audioLanguage = inputs.audioLanguage || 'eng,tur,nld,und'; + const subtitleLanguage = inputs.subtitleLanguage || 'eng,tur,nld,und'; + + let keepSubs = ''; + if (inputs.keepSubtitles) { + keepSubs = `--subtitle-lang-list ${subtitleLanguage}`; + } else { + keepSubs = '--all-subtitles'; + } + + let audioOptions = ''; + if (inputs.audioLanguageOnly) { + audioOptions = `--audio-lang-list ${audioLanguage}`; + } else { + audioOptions = '--all-audio'; + } + + const customAudioOptions = inputs.customAudioOptions || ''; + + const twoPass = inputs.twoPass ? '--two-pass' : ''; + + const videoEncoder = inputs.videoEncoder || 'vce_h264'; + const amfEncoderPreset = inputs.amfEncoderPreset || 'balanced'; + const amfEncoderProfile = inputs.amfEncoderProfile || 'auto'; + const amfEncoderLevel = inputs.amfEncoderLevel || 'auto'; + const container = inputs.container || 'mkv'; + + const customArguments = inputs.customArguments || ''; + + response.preset = `-e ${videoEncoder} --encoder-preset ${amfEncoderPreset} --encoder-profile ${amfEncoderProfile} --encoder-level ${amfEncoderLevel} ${inputs.frameMode} ${frameRateOptions} ${audioOptions} ${customAudioOptions} ${keepSubs} ${twoPass} ${customArguments}`; + response.container = `.${container}`; + response.handBrakeMode = true; + response.FFmpegMode = false; + response.reQueueAfter = true; + response.processFile = true; + response.infoLog += 'File is being transcoded using HandBrake \n'; + + return response; +}; + +module.exports.details = details; +module.exports.plugin = plugin; diff --git a/Local/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_CPU.js b/Local/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_CPU.js new file mode 100644 index 000000000..a7cec9fb9 --- /dev/null +++ b/Local/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_CPU.js @@ -0,0 +1,351 @@ +const details = () => ({ + id: 'Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_CPU', + Stage: 'Pre-processing', + Name: 'DeNiX HandBrake UI Basic Options CPU', + Type: 'Video', + Operation: 'Transcode', + Description: ` + This plugin provides basic HandBrake transcode options through a user-friendly UI. + It allows you to set various video and audio encoding parameters using HandBrake, + including video encoder, frame rate mode, and audio settings. + + Key Features: + - Choose from a variety of CPU video encoders such as svt_av1, svt_av1_10bit, x264, x264_10bit, x265, x265_10bit, x265_12bit, x265_16bit. + - Configure encoder presets, profiles, and levels for CPU encoders. + - Set frame rate modes, including constant (CFR), variable (VFR), peak-limited (PFR), and bitrate (VB). + - Specify video quality or bitrate values. + - Select audio and subtitle languages, with options to keep or delete original tracks. + - Enable or disable two-pass encoding for bitrate mode. + + This plugin is ideal for users who want to leverage HandBrake's powerful encoding capabilities + through a simplified and intuitive interface. + + ### Instructions for the User + - **Frame Rate Mode:** + - **Additional Parameters:** + - If \`--cfr\` is selected, enter the quality value (e.g., \`-q 25\`). + - If \`--vb\` is selected, enter the bitrate value (e.g., \`4000kb\`). + - If \`--vfr\` or \`--pfr\` is selected, enter the quality value (e.g., \`-q 25\`). + - **Two-Pass Encoding:** Only enable when using \`--vb\` mode. Two-pass encoding provides better quality by analyzing the video in the first pass and encoding it in the second pass. + `, + Version: '1.01', + Tags: 'action', + Inputs: [ + { + name: 'container', + type: 'string', + defaultValue: 'mkv', + inputUI: { + type: 'dropdown', + options: [ + 'mkv', + 'mp4', + ], + }, + tooltip: 'Select the output container format. MKV supports more features and codecs than MP4, making it a versatile choice for high-quality videos.', + }, + { + name: 'videoEncoder', + type: 'string', + defaultValue: 'svt_av1', + inputUI: { + type: 'dropdown', + options: [ + 'svt_av1', + 'svt_av1_10bit', + 'x264', + 'x264_10bit', + 'x265', + 'x265_10bit', + 'x265_12bit', + 'x265_16bit', + ], + }, + tooltip: 'Select the video encoder. Options include:\n' + + 'svt_av1: AV1 encoder.\n' + + 'svt_av1_10bit: AV1 10-bit encoder.\n' + + 'x264: H.264 encoder.\n' + + 'x264_10bit: H.264 10-bit encoder.\n' + + 'x265: H.265 encoder.\n' + + 'x265_10bit: H.265 10-bit encoder.\n' + + 'x265_12bit: H.265 12-bit encoder.\n' + + 'x265_16bit: H.265 16-bit encoder.', + }, + { + name: 'encoderPreset', + type: 'string', + defaultValue: 'medium', + inputUI: { + type: 'dropdown', + options: [ + 'ultrafast', + 'superfast', + 'veryfast', + 'faster', + 'fast', + 'medium', + 'slow', + 'slower', + 'veryslow', + ], + }, + tooltip: 'Select the encoder preset for CPU encoders. Options range from "ultrafast" (fastest speed, lowest quality) to "veryslow" (slowest speed, highest quality).', + }, + { + name: 'encoderProfile', + type: 'string', + defaultValue: 'auto', + inputUI: { + type: 'dropdown', + options: [ + 'baseline', + 'main', + 'high', + 'high10', + 'main10', + 'main12', + 'main422_10', + 'main422_12', + 'main444', + 'main444_10', + 'main444_12', + 'auto', + ], + }, + tooltip: 'Select the encoder profile for CPU encoders. Options include:\n' + + 'baseline: Basic profile with minimal compression.\n' + + 'main: Suitable for most use cases with good compatibility.\n' + + 'high: Higher compression and quality.\n' + + 'high10: Supports 10-bit video encoding for higher color depth.\n' + + 'main10: 10-bit main profile.\n' + + 'main12: 12-bit main profile.\n' + + 'main422_10: 10-bit 4:2:2 profile.\n' + + 'main422_12: 12-bit 4:2:2 profile.\n' + + 'main444: 4:4:4 profile.\n' + + 'main444_10: 10-bit 4:4:4 profile.\n' + + 'main444_12: 12-bit 4:4:4 profile.\n' + + 'auto: Automatically choose the best profile based on input and output settings.', + }, + { + name: 'encoderLevel', + type: 'string', + defaultValue: 'auto', + inputUI: { + type: 'dropdown', + options: [ + 'auto', + '1.0', + '1.1', + '1.2', + '1.3', + '2.0', + '2.1', + '2.2', + '3.0', + '3.1', + '3.2', + '4.0', + '4.1', + '4.2', + '5.0', + '5.1', + '5.2', + '6.0', + '6.1', + '6.2', + ], + }, + tooltip: 'Select the encoder level for CPU encoders. The level defines the maximum bitrate and resolution allowed. "auto" lets the encoder select the appropriate level based on the input video.', + }, + { + name: 'frameMode', + type: 'string', + defaultValue: '--cfr', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the frame rate mode. Options include:\n' + + '--cfr: Constant Frame Rate.\nEnsures the output video has a constant frame rate.\nUseful for compatibility with some devices.\n' + + '--vfr: Variable Frame Rate.\nAllows the frame rate to vary.\nUseful for reducing file size.\n' + + '--pfr: Peak-Limited Variable Frame Rate.\nEnsures the frame rate does not exceed a certain peak.\n' + + '--vb: Bitrate Variable Frame Rate.\nAdjusts the frame rate based on bitrate settings.\n' + + 'For --cfr, --vfr, or --pfr: Enter the quality value (e.g., "-q 25").', + }, + { + name: 'frameModeExtra', + type: 'string', + defaultValue: '-q 25', + inputUI: { + type: 'text', + }, + tooltip: 'Enter additional parameters for the selected frame rate mode. Examples:\n' + + 'For --cfr: Enter the quality value, e.g., "-q 25".\n' + + 'For --vb: Enter the bitrate value, e.g., "4000kb".\n' + + 'For --vfr or --pfr: Enter the quality value, e.g., "-q 25".', + }, + { + name: 'twoPass', + type: 'boolean', + defaultValue: false, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Enable or disable two-pass encoding for bitrate mode. Two-pass encoding provides better quality by analyzing the video in the first pass and encoding it in the second pass. Useful for achieving a consistent bitrate. Note: Only enable when using --vb mode.', + }, + { + name: 'audioLanguage', + type: 'string', + defaultValue: 'eng,tur,nld,und', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the desired audio languages as comma-separated ISO 639-2 codes (e.g., eng,tur,nld,und). The plugin will include all audio tracks that match the specified languages.', + }, + { + name: 'subtitleLanguage', + type: 'string', + defaultValue: 'eng,tur,nld,und', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the desired subtitle languages as comma-separated ISO 639-2 codes (e.g., eng,tur,nld,und). The plugin will include all subtitle tracks that match the specified languages.', + }, + { + name: 'keepSubtitles', + type: 'boolean', + defaultValue: true, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Toggle to decide whether to keep all subtitles or only those matching the specified languages. "true" will keep only the specified languages. "false" will keep all subtitles.', + }, + { + name: 'audioLanguageOnly', + type: 'boolean', + defaultValue: true, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Toggle to decide whether to keep all audio in the given language or keep all audio from the input. "true" will keep all audio in the given language. "false" will keep all audio from the input.', + }, + { + name: 'customAudioOptions', + type: 'string', + defaultValue: '--audio-copy-mask aac,ac3,eac3,truehd,dts,dtshd,mp3,flac --audio-fallback copy', + inputUI: { + type: 'text', + }, + tooltip: 'Enter any custom audio options. Default is to copy all common audio formats.\n\n' + + '### Possible Commands:\n' + + '- **--audio-lang-list**: Specify audio languages to keep (e.g., "eng,spa").\n' + + '- **--audio-copy-mask**: Preserve specified audio codecs (e.g., "aac,ac3").\n' + + '- **--audio-fallback**: Fallback audio codec if none match the mask (e.g., "copy").\n' + + '- **--all-audio**: Keep all audio tracks.\n' + + '- **--no-audio**: Remove all audio tracks.\n' + + '- **--audio-bitrate**: Set the audio bitrate (e.g., "128k").\n' + + '- **--audio-quality**: Set the audio quality (e.g., "5").\n\n' + + '### Example Use Cases:\n' + + '- Keep all audio tracks: `--all-audio`\n' + + '- Keep only English and Spanish audio tracks: `--audio-lang-list eng,spa`\n' + + '- Preserve AAC and AC3 codecs, fallback to copy: `--audio-copy-mask aac,ac3 --audio-fallback copy`\n' + + '- Set audio bitrate to 128kbps: `--audio-bitrate 128k`\n' + + '- Set audio quality to 5: `--audio-quality 5`', + }, + { + name: 'customArguments', + type: 'string', + inputUI: { + type: 'text', + }, + tooltip: 'Enter any additional custom arguments to be passed to HandBrake. These arguments will be added to the command line for more advanced customization.\n\n' + + '### Possible Commands:\n' + + '- **--crop**: Set the crop values (e.g., "--crop 0:0:0:0").\n' + + '- **--scale**: Set the output resolution (e.g., "--width 1920 --height 1080").\n' + + '- **--rate**: Set the frame rate (e.g., "--rate 30").\n' + + '- **--rotate**: Rotate the video (e.g., "--rotate=4").\n' + + '- **--deinterlace**: Deinterlace the video (e.g., "--deinterlace").\n' + + '- **--denoise**: Apply denoise filter (e.g., "--denoise=weak").\n' + + '- **--deblock**: Apply deblock filter (e.g., "--deblock").\n' + + '- **--custom-anamorphic**: Set custom anamorphic settings.\n\n' + + '### Example Use Cases:\n' + + '- Crop the video: `--crop 0:0:0:0`\n' + + '- Scale to 1080p: `--width 1920 --height 1080`\n' + + '- Set frame rate to 30fps: `--rate 30`\n' + + '- Rotate video: `--rotate=4`\n' + + '- Apply deinterlace filter: `--deinterlace`\n' + + '- Apply denoise filter: `--denoise=weak`\n' + + '- Apply deblock filter: `--deblock`\n' + + '- Set custom anamorphic settings: `--custom-anamorphic`', + }, + ], +}); + +const plugin = (file, librarySettings, inputs, otherArguments) => { + const lib = require('../methods/lib')(); + inputs = lib.loadDefaultValues(inputs, details); + const response = { + processFile: false, + preset: '', + container: '', + handBrakeMode: true, + FFmpegMode: false, + reQueueAfter: false, + infoLog: '', + }; + + const frameRateOptions = inputs.frameModeExtra || ''; + + const audioLanguage = inputs.audioLanguage || 'eng,tur,nld,und'; + const subtitleLanguage = inputs.subtitleLanguage || 'eng,tur,nld,und'; + + let keepSubs = ''; + if (inputs.keepSubtitles) { + keepSubs = `--subtitle-lang-list ${subtitleLanguage}`; + } else { + keepSubs = '--all-subtitles'; + } + + let audioOptions = ''; + if (inputs.audioLanguageOnly) { + audioOptions = `--audio-lang-list ${audioLanguage}`; + } else { + audioOptions = '--all-audio'; + } + + const customAudioOptions = inputs.customAudioOptions || ''; + + const twoPass = inputs.twoPass ? '--two-pass' : ''; + + const videoEncoder = inputs.videoEncoder || 'x264'; + const encoderPreset = inputs.encoderPreset || 'medium'; + const encoderProfile = inputs.encoderProfile || 'auto'; + const encoderLevel = inputs.encoderLevel || 'auto'; + const container = inputs.container || 'mkv'; + + const customArguments = inputs.customArguments || ''; + + response.preset = `-e ${videoEncoder} --encoder-preset ${encoderPreset} --encoder-profile ${encoderProfile} --encoder-level ${encoderLevel} ${inputs.frameMode} ${frameRateOptions} ${audioOptions} ${customAudioOptions} ${keepSubs} ${twoPass} ${customArguments}`; + response.container = `.${container}`; + response.handBrakeMode = true; + response.FFmpegMode = false; + response.reQueueAfter = true; + response.processFile = true; + response.infoLog += 'File is being transcoded using HandBrake \n'; + + return response; +}; + +module.exports.details = details; +module.exports.plugin = plugin; diff --git a/Local/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_NVIDIA.js b/Local/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_NVIDIA.js new file mode 100644 index 000000000..5315c59f3 --- /dev/null +++ b/Local/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_NVIDIA.js @@ -0,0 +1,350 @@ +const details = () => ({ + id: 'Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_NVENC', + Stage: 'Pre-processing', + Name: 'DeNiX HandBrake UI Basic Options NVENC', + Type: 'Video', + Operation: 'Transcode', + Description: ` + This plugin provides basic HandBrake transcode options through a user-friendly UI. + It allows you to set various video and audio encoding parameters using HandBrake, + including video encoder, frame rate mode, and audio settings. + + Key Features: + - Choose from a variety of NVIDIA NVENC video encoders such as nvenc_h264, nvenc_h265, nvenc_av1, nvenc_h265_10bit, nvenc_av1_10bit. + - Select hardware decoder options or disable them. + - Configure encoder presets, profiles, and levels for NVENC. + - Set frame rate modes, including constant (CFR), variable (VFR), peak-limited (PFR), and bitrate (VB). + - Specify video quality or bitrate values. + - Select audio and subtitle languages, with options to keep or delete original tracks. + - Enable or disable two-pass encoding for bitrate mode. + + This plugin is ideal for users who want to leverage HandBrake's powerful encoding capabilities + through a simplified and intuitive interface. + + ### Instructions for the User + - **Frame Rate Mode:** + - **Additional Parameters:** + - If \`--cfr\` is selected, enter the quality value (e.g., \`-q 25\`). + - If \`--vb\` is selected, enter the bitrate value (e.g., \`4000kb\`). + - If \`--vfr\` or \`--pfr\` is selected, enter the quality value (e.g., \`-q 25\`). + - **Two-Pass Encoding:** Only enable when using \`--vb\` mode. Two-pass encoding provides better quality by analyzing the video in the first pass and encoding it in the second pass. + `, + Version: '1.01', + Tags: 'action', + Inputs: [ + { + name: 'container', + type: 'string', + defaultValue: 'mkv', + inputUI: { + type: 'dropdown', + options: [ + 'mkv', + 'mp4', + ], + }, + tooltip: 'Select the output container format. MKV supports more features and codecs than MP4, making it a versatile choice for high-quality videos.', + }, + { + name: 'videoEncoder', + type: 'string', + defaultValue: 'nvenc_h264', + inputUI: { + type: 'dropdown', + options: [ + 'nvenc_h264', + 'nvenc_h265', + 'nvenc_av1', + 'nvenc_h265_10bit', + 'nvenc_av1_10bit', + ], + }, + tooltip: 'Select the video encoder. Options include:\n' + + 'nvenc_h264: H.264 encoder using NVIDIA NVENC.\n' + + 'nvenc_h265: H.265 encoder using NVIDIA NVENC.\n' + + 'nvenc_av1: AV1 encoder using NVIDIA NVENC.\n' + + 'nvenc_h265_10bit: H.265 10-bit encoder using NVIDIA NVENC.\n' + + 'nvenc_av1_10bit: AV1 10-bit encoder using NVIDIA NVENC.', + }, + { + name: 'videoDecoder', + type: 'string', + defaultValue: 'nvdec', + inputUI: { + type: 'dropdown', + options: [ + 'nvdec', + 'disable', + ], + }, + tooltip: 'Select the video decoder. Options include:\n' + + 'nvdec: Use NVIDIA NVDEC for hardware-accelerated decoding.\n' + + 'disable: Do not use hardware acceleration for decoding.', + }, + { + name: 'nvencEncoderPreset', + type: 'string', + defaultValue: 'p7', + inputUI: { + type: 'dropdown', + options: [ + 'p1', + 'p2', + 'p3', + 'p4', + 'p5', + 'p6', + 'p7', + ], + }, + tooltip: 'Select the encoder preset for NVIDIA encoders. Options include:\n' + + 'p1: Slowest speed, highest quality.\n' + + 'p2: Slower speed, higher quality.\n' + + 'p3: Slow speed, high quality.\n' + + 'p4: Medium speed, medium quality.\n' + + 'p5: Fast speed, medium quality.\n' + + 'p6: Faster speed, lower quality.\n' + + 'p7: Fastest speed, lowest quality.', + }, + { + name: 'nvencEncoderProfile', + type: 'string', + defaultValue: 'auto', + inputUI: { + type: 'dropdown', + options: [ + 'main', + 'main10', + 'auto', + ], + }, + tooltip: 'Select the encoder profile for NVIDIA encoders. Options include:\n' + + 'main: Suitable for most use cases with good compatibility.\n' + + 'main10: Supports 10-bit video encoding for higher color depth.\n' + + 'auto: Automatically choose the best profile based on input and output settings.', + }, + { + name: 'encoderLevel', + type: 'string', + defaultValue: 'auto', + inputUI: { + type: 'dropdown', + options: [ + 'auto', + '1.0', + '1.1', + '1.2', + '1.3', + '2.0', + '2.1', + '2.2', + '3.0', + '3.1', + '3.2', + '4.0', + '4.1', + '4.2', + '5.0', + '5.1', + '5.2', + '6.0', + '6.1', + '6.2', + ], + }, + tooltip: 'Select the encoder level for NVENC encoders. The level defines the maximum bitrate and resolution allowed. "auto" lets the encoder select the appropriate level based on the input video.', + }, + { + name: 'frameMode', + type: 'string', + defaultValue: '--cfr', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the frame rate mode. Options include:\n' + + '--cfr: Constant Frame Rate.\nEnsures the output video has a constant frame rate.\nUseful for compatibility with some devices.\n' + + '--vfr: Variable Frame Rate.\nAllows the frame rate to vary.\nUseful for reducing file size.\n' + + '--pfr: Peak-Limited Variable Frame Rate.\nEnsures the frame rate does not exceed a certain peak.\n' + + '--vb: Bitrate Variable Frame Rate.\nAdjusts the frame rate based on bitrate settings.\n' + + 'For --cfr, --vfr, or --pfr: Enter the quality value (e.g., "-q 25").', + }, + { + name: 'frameModeExtra', + type: 'string', + defaultValue: '-q 25', + inputUI: { + type: 'text', + }, + tooltip: 'Enter additional parameters for the selected frame rate mode. Examples:\n' + + 'For --cfr: Enter the quality value, e.g., "-q 25".\n' + + 'For --vb: Enter the bitrate value, e.g., "4000kb".\n' + + 'For --vfr or --pfr: Enter the quality value, e.g., "-q 25".', + }, + { + name: 'twoPass', + type: 'boolean', + defaultValue: false, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Enable or disable two-pass encoding for bitrate mode. Two-pass encoding provides better quality by analyzing the video in the first pass and encoding it in the second pass. Useful for achieving a consistent bitrate. Note: Only enable when using --vb mode.', + }, + { + name: 'audioLanguage', + type: 'string', + defaultValue: 'eng,tur,nld,und', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the desired audio languages as comma-separated ISO 639-2 codes (e.g., eng,tur,nld,und). The plugin will include all audio tracks that match the specified languages.', + }, + { + name: 'subtitleLanguage', + type: 'string', + defaultValue: 'eng,tur,nld,und', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the desired subtitle languages as comma-separated ISO 639-2 codes (e.g., eng,tur,nld,und). The plugin will include all subtitle tracks that match the specified languages.', + }, + { + name: 'keepSubtitles', + type: 'boolean', + defaultValue: true, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Toggle to decide whether to keep all subtitles or only those matching the specified languages. "true" will keep only the specified languages. "false" will keep all subtitles.', + }, + { + name: 'audioLanguageOnly', + type: 'boolean', + defaultValue: true, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Toggle to decide whether to keep all audio in the given language or keep all audio from the input. "true" will keep all audio in the given language. "false" will keep all audio from the input.', + }, + { + name: 'customAudioOptions', + type: 'string', + defaultValue: '--audio-copy-mask aac,ac3,eac3,truehd,dts,dtshd,mp3,flac --audio-fallback copy', + inputUI: { + type: 'text', + }, + tooltip: 'Enter any custom audio options. Default is to copy all common audio formats.\n\n' + + '### Possible Commands:\n' + + '- **--audio-lang-list**: Specify audio languages to keep (e.g., "eng,spa").\n' + + '- **--audio-copy-mask**: Preserve specified audio codecs (e.g., "aac,ac3").\n' + + '- **--audio-fallback**: Fallback audio codec if none match the mask (e.g., "copy").\n' + + '- **--all-audio**: Keep all audio tracks.\n' + + '- **--no-audio**: Remove all audio tracks.\n' + + '- **--audio-bitrate**: Set the audio bitrate (e.g., "128k").\n' + + '- **--audio-quality**: Set the audio quality (e.g., "5").\n\n' + + '### Example Use Cases:\n' + + '- Keep all audio tracks: `--all-audio`\n' + + '- Keep only English and Spanish audio tracks: `--audio-lang-list eng,spa`\n' + + '- Preserve AAC and AC3 codecs, fallback to copy: `--audio-copy-mask aac,ac3 --audio-fallback copy`\n' + + '- Set audio bitrate to 128kbps: `--audio-bitrate 128k`\n' + + '- Set audio quality to 5: `--audio-quality 5`', + }, + { + name: 'customArguments', + type: 'string', + inputUI: { + type: 'text', + }, + tooltip: 'Enter any additional custom arguments to be passed to HandBrake. These arguments will be added to the command line for more advanced customization.\n\n' + + '### Possible Commands:\n' + + '- **--crop**: Set the crop values (e.g., "--crop 0:0:0:0").\n' + + '- **--scale**: Set the output resolution (e.g., "--width 1920 --height 1080").\n' + + '- **--rate**: Set the frame rate (e.g., "--rate 30").\n' + + '- **--rotate**: Rotate the video (e.g., "--rotate=4").\n' + + '- **--deinterlace**: Deinterlace the video (e.g., "--deinterlace").\n' + + '- **--denoise**: Apply denoise filter (e.g., "--denoise=weak").\n' + + '- **--deblock**: Apply deblock filter (e.g., "--deblock").\n' + + '- **--custom-anamorphic**: Set custom anamorphic settings.\n\n' + + '### Example Use Cases:\n' + + '- Crop the video: `--crop 0:0:0:0`\n' + + '- Scale to 1080p: `--width 1920 --height 1080`\n' + + '- Set frame rate to 30fps: `--rate 30`\n' + + '- Rotate video: `--rotate=4`\n' + + '- Apply deinterlace filter: `--deinterlace`\n' + + '- Apply denoise filter: `--denoise=weak`\n' + + '- Apply deblock filter: `--deblock`\n' + + '- Set custom anamorphic settings: `--custom-anamorphic`', + }, + ], +}); + +const plugin = (file, librarySettings, inputs, otherArguments) => { + const lib = require('../methods/lib')(); + inputs = lib.loadDefaultValues(inputs, details); + const response = { + processFile: false, + preset: '', + container: '', + handBrakeMode: true, + FFmpegMode: false, + reQueueAfter: false, + infoLog: '', + }; + + const decoder = inputs.videoDecoder === 'disable' ? '--disable-hw-decoding' : `--enable-hw-decoding ${inputs.videoDecoder}`; + + const frameRateOptions = inputs.frameModeExtra || ''; + + const audioLanguage = inputs.audioLanguage || 'eng,tur,nld,und'; + const subtitleLanguage = inputs.subtitleLanguage || 'eng,tur,nld,und'; + + let keepSubs = ''; + if (inputs.keepSubtitles) { + keepSubs = `--subtitle-lang-list ${subtitleLanguage}`; + } else { + keepSubs = '--all-subtitles'; + } + + let audioOptions = ''; + if (inputs.audioLanguageOnly) { + audioOptions = `--audio-lang-list ${audioLanguage}`; + } else { + audioOptions = '--all-audio'; + } + + const customAudioOptions = inputs.customAudioOptions || ''; + + const twoPass = inputs.twoPass ? '--two-pass' : ''; + + const videoEncoder = inputs.videoEncoder || 'nvenc_h264'; + const nvencEncoderPreset = inputs.nvencEncoderPreset || 'p7'; + const nvencEncoderProfile = inputs.nvencEncoderProfile || 'auto'; + const encoderLevel = inputs.encoderLevel || 'auto'; + const container = inputs.container || 'mkv'; + + const customArguments = inputs.customArguments || ''; + + response.preset = `${decoder} -e ${videoEncoder} --encoder-preset ${nvencEncoderPreset} --encoder-profile ${nvencEncoderProfile} --encoder-level ${encoderLevel} ${inputs.frameMode} ${frameRateOptions} ${audioOptions} ${customAudioOptions} ${keepSubs} ${twoPass} ${customArguments}`; + response.container = `.${container}`; + response.handBrakeMode = true; + response.FFmpegMode = false; + response.reQueueAfter = true; + response.processFile = true; + response.infoLog += 'File is being transcoded using HandBrake \n'; + + return response; +}; + +module.exports.details = details; +module.exports.plugin = plugin; diff --git a/Local/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_QSV.js b/Local/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_QSV.js new file mode 100644 index 000000000..0163144b4 --- /dev/null +++ b/Local/Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_QSV.js @@ -0,0 +1,361 @@ +const details = () => ({ + id: 'Tdarr_Plugin_DeNiX_HandBrake_UI_Basics_QSV', + Stage: 'Pre-processing', + Name: 'DeNiX HandBrake UI Basic Options QSV', + Type: 'Video', + Operation: 'Transcode', + Description: ` + This plugin provides basic HandBrake transcode options through a user-friendly UI. + It allows you to set various video and audio encoding parameters using HandBrake, + including video encoder, decoder, frame rate mode, and audio settings. + + Key Features: + - Choose from a variety of Intel QSV video encoders such as qsv_h264, qsv_h265, qsv_av1, qsv_h264_10bit, qsv_h265_10bit, qsv_av1_10bit. + - Select hardware decoder options or disable them. + - Configure encoder presets, profiles, and levels for QSV. + - Set frame rate modes, including constant (CFR), variable (VFR), peak-limited (PFR), and bitrate (VB). + - Specify video quality or bitrate values. + - Select audio and subtitle languages, with options to keep or delete original tracks. + - Enable or disable turbo mode and two-pass encoding for QSV bitrate mode. + + This plugin is ideal for users who want to leverage HandBrake's powerful encoding capabilities + through a simplified and intuitive interface. + + ### Instructions for the User + - **Frame Rate Mode:** + - **Additional Parameters:** + - If \`--cfr\` is selected, enter the quality value (e.g., \`-q 25\`). + - If \`--vb\` is selected, enter the bitrate value (e.g., \`4000kb\`). + - If \`--vfr\` or \`--pfr\` is selected, enter the quality value (e.g., \`-q 25\`). + - **Turbo Mode:** Only enable when using \`--vb\` mode. Turbo mode increases encoding speed at the cost of output quality. + - **Two-Pass Encoding:** Only enable when using \`--vb\` mode. Two-pass encoding provides better quality by analyzing the video in the first pass and encoding it in the second pass. + `, + Version: '1.01', + Tags: 'action', + Inputs: [ + { + name: 'container', + type: 'string', + defaultValue: 'mkv', + inputUI: { + type: 'dropdown', + options: [ + 'mkv', + 'mp4', + ], + }, + tooltip: 'Select the output container format. MKV supports more features and codecs than MP4, making it a versatile choice for high-quality videos.', + }, + { + name: 'videoEncoder', + type: 'string', + defaultValue: 'qsv_av1', + inputUI: { + type: 'dropdown', + options: [ + 'qsv_h264', + 'qsv_h265', + 'qsv_av1', + 'qsv_h264_10bit', + 'qsv_h265_10bit', + 'qsv_av1_10bit', + ], + }, + tooltip: 'Select the video encoder. Options include:\n' + + 'qsv_h264: H.264 encoder using Intel Quick Sync Video.\n' + + 'qsv_h265: H.265 encoder using Intel Quick Sync Video.\n' + + 'qsv_av1: AV1 encoder using Intel Quick Sync Video. AV1 offers better compression rates compared to H.264 and H.265.\n' + + 'qsv_h264_10bit: H.264 10-bit encoder using Intel Quick Sync Video.\n' + + 'qsv_h265_10bit: H.265 10-bit encoder using Intel Quick Sync Video.\n' + + 'qsv_av1_10bit: AV1 10-bit encoder using Intel Quick Sync Video.', + }, + { + name: 'videoDecoder', + type: 'string', + defaultValue: 'qsv', + inputUI: { + type: 'dropdown', + options: [ + 'qsv', + 'disable', + ], + }, + tooltip: 'Select the video decoder. Options include:\n' + + 'qsv: Use Intel Quick Sync Video for hardware-accelerated decoding.\n' + + 'disable: Do not use hardware acceleration for decoding.', + }, + { + name: 'qsvEncoderPreset', + type: 'string', + defaultValue: 'balanced', + inputUI: { + type: 'dropdown', + options: [ + 'speed', + 'balanced', + 'quality', + ], + }, + tooltip: 'Select the encoder preset for QSV encoders. Options include:\n' + + 'speed: Prioritize encoding speed over quality.\n' + + 'balanced: Balance between speed and quality.\n' + + 'quality: Prioritize output quality over encoding speed.', + }, + { + name: 'qsvEncoderProfile', + type: 'string', + defaultValue: 'auto', + inputUI: { + type: 'dropdown', + options: [ + 'main', + 'main-still-picture', + 'main10', + 'auto', + ], + }, + tooltip: 'Select the encoder profile for QSV encoders. Options include:\n' + + 'main: Suitable for most use cases with good compatibility.\n' + + 'main-still-picture: Optimized for still images.\n' + + 'main10: Supports 10-bit video encoding for higher color depth.\n' + + 'auto: Automatically choose the best profile based on input and output settings.', + }, + { + name: 'qsvEncoderLevel', + type: 'string', + defaultValue: 'auto', + inputUI: { + type: 'dropdown', + options: [ + 'auto', + '1.0', + '1.1', + '1.2', + '1.3', + '2.0', + '2.1', + '2.2', + '3.0', + '3.1', + '3.2', + '4.0', + '4.1', + '4.2', + '5.0', + '5.1', + '5.2', + '6.0', + '6.1', + '6.2', + ], + }, + tooltip: 'Select the encoder level for QSV encoders. The level defines the maximum bitrate and resolution allowed. "auto" lets the encoder select the appropriate level based on the input video.', + }, + { + name: 'frameMode', + type: 'string', + defaultValue: '--cfr', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the frame rate mode. Options include:\n' + + '--cfr: Constant Frame Rate.\nEnsures the output video has a constant frame rate.\nUseful for compatibility with some devices.\n' + + '--vfr: Variable Frame Rate.\nAllows the frame rate to vary.\nUseful for reducing file size.\n' + + '--pfr: Peak-Limited Variable Frame Rate.\nEnsures the frame rate does not exceed a certain peak.\n' + + '--vb: Bitrate Variable Frame Rate.\nAdjusts the frame rate based on bitrate settings.\n' + + 'For --cfr, --vfr, or --pfr: Enter the quality value (e.g., "-q 25").', + }, + { + name: 'frameModeExtra', + type: 'string', + defaultValue: '-q 25', + inputUI: { + type: 'text', + }, + tooltip: 'Enter additional parameters for the selected frame rate mode. Examples:\n' + + 'For --cfr: Enter the quality value, e.g., "-q 25".\n' + + 'For --vb: Enter the bitrate value, e.g., "4000kb".\n' + + 'For --vfr or --pfr: Enter the quality value, e.g., "-q 25".', + }, + { + name: 'turbo', + type: 'boolean', + defaultValue: false, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Enable or disable turbo mode for QSV bitrate mode. Turbo mode increases encoding speed at the cost of output quality. Useful for quick encodes when quality is less critical. Note: Only enable when using --vb mode.', + }, + { + name: 'twoPass', + type: 'boolean', + defaultValue: false, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Enable or disable two-pass encoding for QSV bitrate mode. Two-pass encoding provides better quality by analyzing the video in the first pass and encoding it in the second pass. Useful for achieving a consistent bitrate. Note: Only enable when using --vb mode.', + }, + { + name: 'audioLanguage', + type: 'string', + defaultValue: 'eng,tur,nld,und', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the desired audio languages as comma-separated ISO 639-2 codes (e.g., eng,tur,nld,und). The plugin will include all audio tracks that match the specified languages.', + }, + { + name: 'subtitleLanguage', + type: 'string', + defaultValue: 'eng,tur,nld,und', + inputUI: { + type: 'text', + }, + tooltip: 'Enter the desired subtitle languages as comma-separated ISO 639-2 codes (e.g., eng,tur,nld,und). The plugin will include all subtitle tracks that match the specified languages.', + }, + { + name: 'keepSubtitles', + type: 'boolean', + defaultValue: true, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Toggle to decide whether to keep all subtitles or only those matching the specified languages. "true" will keep only the specified languages. "false" will keep all subtitles.', + }, + { + name: 'audioLanguageOnly', + type: 'boolean', + defaultValue: true, + inputUI: { + type: 'dropdown', + options: [ + 'true', + 'false', + ], + }, + tooltip: 'Toggle to decide whether to keep all audio in the given language or keep all audio from the input. "true" will keep all audio in the given language. "false" will keep all audio from the input.', + }, + { + name: 'customAudioOptions', + type: 'string', + defaultValue: '--audio-copy-mask aac,ac3,eac3,truehd,dts,dtshd,mp3,flac --audio-fallback copy', + inputUI: { + type: 'text', + }, + tooltip: 'Enter any custom audio options. Default is to copy all common audio formats.\n\n' + + '### Possible Commands:\n' + + '- **--audio-lang-list**: Specify audio languages to keep (e.g., "eng,spa").\n' + + '- **--audio-copy-mask**: Preserve specified audio codecs (e.g., "aac,ac3").\n' + + '- **--audio-fallback**: Fallback audio codec if none match the mask (e.g., "copy").\n' + + '- **--all-audio**: Keep all audio tracks.\n' + + '- **--no-audio**: Remove all audio tracks.\n' + + '- **--audio-bitrate**: Set the audio bitrate (e.g., "128k").\n' + + '- **--audio-quality**: Set the audio quality (e.g., "5").\n\n' + + '### Example Use Cases:\n' + + '- Keep all audio tracks: `--all-audio`\n' + + '- Keep only English and Spanish audio tracks: `--audio-lang-list eng,spa`\n' + + '- Preserve AAC and AC3 codecs, fallback to copy: `--audio-copy-mask aac,ac3 --audio-fallback copy`\n' + + '- Set audio bitrate to 128kbps: `--audio-bitrate 128k`\n' + + '- Set audio quality to 5: `--audio-quality 5`', + }, + { + name: 'customArguments', + type: 'string', + inputUI: { + type: 'text', + }, + tooltip: 'Enter any additional custom arguments to be passed to HandBrake. These arguments will be added to the command line for more advanced customization.\n\n' + + '### Possible Commands:\n' + + '- **--crop**: Set the crop values (e.g., "--crop 0:0:0:0").\n' + + '- **--scale**: Set the output resolution (e.g., "--width 1920 --height 1080").\n' + + '- **--rate**: Set the frame rate (e.g., "--rate 30").\n' + + '- **--rotate**: Rotate the video (e.g., "--rotate=4").\n' + + '- **--deinterlace**: Deinterlace the video (e.g., "--deinterlace").\n' + + '- **--denoise**: Apply denoise filter (e.g., "--denoise=weak").\n' + + '- **--deblock**: Apply deblock filter (e.g., "--deblock").\n' + + '- **--custom-anamorphic**: Set custom anamorphic settings.\n\n' + + '### Example Use Cases:\n' + + '- Crop the video: `--crop 0:0:0:0`\n' + + '- Scale to 1080p: `--width 1920 --height 1080`\n' + + '- Set frame rate to 30fps: `--rate 30`\n' + + '- Rotate video: `--rotate=4`\n' + + '- Apply deinterlace filter: `--deinterlace`\n' + + '- Apply denoise filter: `--denoise=weak`\n' + + '- Apply deblock filter: `--deblock`\n' + + '- Set custom anamorphic settings: `--custom-anamorphic`', + }, + ], +}); + +const plugin = (file, librarySettings, inputs, otherArguments) => { + const lib = require('../methods/lib')(); + inputs = lib.loadDefaultValues(inputs, details); + const response = { + processFile: false, + preset: '', + container: '', + handBrakeMode: true, + FFmpegMode: false, + reQueueAfter: false, + infoLog: '', + }; + + const decoder = inputs.videoDecoder === 'disable' ? '--disable-hw-decoding' : `--enable-hw-decoding ${inputs.videoDecoder}`; + + const frameRateOptions = inputs.frameModeExtra || ''; + + const audioLanguage = inputs.audioLanguage || 'eng,tur,nld,und'; + const subtitleLanguage = inputs.subtitleLanguage || 'eng,tur,nld,und'; + + let keepSubs = ''; + if (inputs.keepSubtitles) { + keepSubs = `--subtitle-lang-list ${subtitleLanguage}`; + } else { + keepSubs = '--all-subtitles'; + } + + let audioOptions = ''; + if (inputs.audioLanguageOnly) { + audioOptions = `--audio-lang-list ${audioLanguage}`; + } else { + audioOptions = '--all-audio'; + } + + const customAudioOptions = inputs.customAudioOptions || ''; + + const turbo = inputs.turbo ? '--turbo' : ''; + const twoPass = inputs.twoPass ? '--two-pass' : ''; + + const videoEncoder = inputs.videoEncoder || 'qsv_h264'; + const qsvEncoderPreset = inputs.qsvEncoderPreset || 'balanced'; + const qsvEncoderProfile = inputs.qsvEncoderProfile || 'auto'; + const qsvEncoderLevel = inputs.qsvEncoderLevel || 'auto'; + const container = inputs.container || 'mkv'; + + const customArguments = inputs.customArguments || ''; + + response.preset = `${decoder} -e ${videoEncoder} --encoder-preset ${qsvEncoderPreset} --encoder-profile ${qsvEncoderProfile} --encoder-level ${qsvEncoderLevel} ${inputs.frameMode} ${frameRateOptions} ${audioOptions} ${customAudioOptions} ${keepSubs} ${turbo} ${twoPass} ${customArguments}`; + response.container = `.${container}`; + response.handBrakeMode = true; + response.FFmpegMode = false; + response.reQueueAfter = true; + response.processFile = true; + response.infoLog += 'File is being transcoded using HandBrake \n'; + + return response; +}; + +module.exports.details = details; +module.exports.plugin = plugin; diff --git a/Local/Tdarr_Plugin_DeNiX_rename_files_based_on_resolution.js b/Local/Tdarr_Plugin_DeNiX_rename_files_based_on_resolution.js new file mode 100644 index 000000000..3db62019e --- /dev/null +++ b/Local/Tdarr_Plugin_DeNiX_rename_files_based_on_resolution.js @@ -0,0 +1,70 @@ +/* eslint-disable */ + +// tdarrSkipTest +const details = () => { + return { + id: "Tdarr_Plugin_DeNiX_rename_files_based_on_resolution", + Stage: "Post-processing", + Name: "Rename Based On Resolution", + Type: "Video", + Operation: "Transcode", + Description: [Contains built-in filter] If the filename contains resolution indicators such as '720p', '1080p', '2160p', '4K', '480p', etc., this plugin renames files to match the actual resolution of the video stream. \n\n, + Version: "1.00", + Tags: "post-processing", + Inputs: [] + }; +}; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const plugin = (file, librarySettings, inputs, otherArguments) => { + const lib = require('../methods/lib')(); + inputs = lib.loadDefaultValues(inputs, details); + + try { + const fs = require("fs"); + const fileNameOld = file._id; + const width = file.ffProbeData.streams[0].width; + let resolution; + + if (width >= 3840) { + resolution = "2160p"; + } else if (width >= 1920) { + resolution = "1080p"; + } else if (width >= 1280) { + resolution = "720p"; + } else if (width >= 640) { + resolution = "480p"; + } else { + resolution = "SD"; + } + + console.log(Detected resolution: ${resolution}); + + const regex = /720p|1080p|2160p|4K|480p/; + if (regex.test(file._id)) { + file._id = file._id.replace(regex, resolution); + file.file = file.file.replace(regex, resolution); + } + + if (fileNameOld !== file._id) { + fs.renameSync(fileNameOld, file._id, { overwrite: true }); + + return { + file, + removeFromDB: false, + updateDB: true, + }; + } + } catch (err) { + console.log(Error renaming file: ${err.message}); + } + + return { + file, + removeFromDB: false, + updateDB: false, + }; +}; + +module.exports.details = details; +module.exports.plugin = plugin;