mirror of
https://github.com/gabehf/Tdarr_Plugins.git
synced 2026-03-18 03:36:26 -07:00
Update: All Migz Plugins
1) Ran all plugins through javascript formatter to make them look nicer/ have correct javascript formatting. 2) Added comments to all plugins. 3) Modified all plugins that have checks for inputs to check for existance of inputs itself. 4) Modify 5ConvertAudio so that you can just put "true" in a single input, rather then having to put false in the opposing one. If only 1 action is wanted. 5) Fix for 3CleanAudio & 4CleanSubs where if language meta was completely missing then plugins would not set it to the specified tag language. 6) Correct 4CleanSubs input title of "tag_title" to "tag_language"
This commit is contained in:
parent
3e4b2c7126
commit
20fe6461a1
9 changed files with 998 additions and 883 deletions
|
|
@ -4,13 +4,12 @@ function details() {
|
||||||
Stage: "Pre-processing",
|
Stage: "Pre-processing",
|
||||||
Name: "Migz-Transcode Using Nvidia GPU & FFMPEG",
|
Name: "Migz-Transcode Using Nvidia GPU & FFMPEG",
|
||||||
Type: "Video",
|
Type: "Video",
|
||||||
Operation:"Transcode",
|
Operation: "Transcode",
|
||||||
Description: `Files will be transcoded using Nvidia GPU with ffmpeg, settings are dependant on file bitrate, working by the logic that H265 can support the same ammount of data at half the bitrate of H264. NVDEC & NVENC compatable GPU required. \n\n`,
|
Description: `Files will be transcoded using Nvidia GPU with ffmpeg, settings are dependant on file bitrate, working by the logic that H265 can support the same ammount of data at half the bitrate of H264. NVDEC & NVENC compatable GPU required. \n\n`,
|
||||||
Version: "2.20",
|
Version: "2.3",
|
||||||
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz1FFMPEG.js",
|
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz1FFMPEG.js",
|
||||||
Tags:'pre-processing,ffmpeg,video only,nvenc h265,configurable',
|
Tags: 'pre-processing,ffmpeg,video only,nvenc h265,configurable',
|
||||||
Inputs: [
|
Inputs: [{
|
||||||
{
|
|
||||||
name: 'container',
|
name: 'container',
|
||||||
tooltip: `Specify output container of file, ensure that all stream types you may have are supported by your chosen container. mkv is recommended.
|
tooltip: `Specify output container of file, ensure that all stream types you may have are supported by your chosen container. mkv is recommended.
|
||||||
\\nExample:\\n
|
\\nExample:\\n
|
||||||
|
|
@ -29,8 +28,6 @@ function details() {
|
||||||
|
|
||||||
\\nExample:\\n
|
\\nExample:\\n
|
||||||
4000`
|
4000`
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -46,6 +43,7 @@ function plugin(file, librarySettings, inputs) {
|
||||||
infoLog: ''
|
infoLog: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if inputs.container has been configured. If it hasn't then exit plugin.
|
||||||
if (inputs.container == "") {
|
if (inputs.container == "") {
|
||||||
response.infoLog += "☒Container has not been configured within plugin settings, please configure required options. Skipping this plugin. \n"
|
response.infoLog += "☒Container has not been configured within plugin settings, please configure required options. Skipping this plugin. \n"
|
||||||
response.processFile = false
|
response.processFile = false
|
||||||
|
|
@ -54,40 +52,49 @@ function plugin(file, librarySettings, inputs) {
|
||||||
response.container = '.' + inputs.container
|
response.container = '.' + inputs.container
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if file is MKV, if so then add extra argument to drop data. MKV does not support data streams.
|
||||||
if (inputs.container == "mkv") {
|
if (inputs.container == "mkv") {
|
||||||
extraArguments += "-map -0:d "
|
extraArguments += "-map -0:d "
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if file is a video. If it isn't then exit plugin.
|
||||||
if (file.fileMedium !== "video") {
|
if (file.fileMedium !== "video") {
|
||||||
response.processFile = false
|
response.processFile = false
|
||||||
response.infoLog += "☒File is not a video. \n"
|
response.infoLog += "☒File is not a video. \n"
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if duration info is filled, if so times it by 0.0166667 to get time in minutes. If not filled then get duration of stream 0 and do the same.
|
||||||
if (typeof file.meta.Duration != 'undefined') {
|
if (typeof file.meta.Duration != 'undefined') {
|
||||||
var duration = (file.meta.Duration * 0.0166667)
|
var duration = (file.meta.Duration * 0.0166667)
|
||||||
} else {
|
} else {
|
||||||
var duration = (file.ffProbeData.streams[0].duration * 0.0166667)
|
var duration = (file.ffProbeData.streams[0].duration * 0.0166667)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up required variables.
|
||||||
var videoIdx = 0
|
var videoIdx = 0
|
||||||
var extraArguments = ""
|
var extraArguments = ""
|
||||||
var bitrateSettings = ""
|
var bitrateSettings = ""
|
||||||
var filesize = (file.file_size / 1000)
|
// Work out currentBitrate using "Bitrate = file size / (number of minutes * .0075)" - Used from here https://blog.frame.io/2017/03/06/calculate-video-bitrates/
|
||||||
var currentBitrate = ~~(file.file_size / (duration * 0.0075))
|
var currentBitrate = ~~(file.file_size / (duration * 0.0075))
|
||||||
|
// Use the same calculation used for currentBitrate but divide it in half to get targetBitrate. Logic of h265 can be half the bitrate as h264 without losing quality.
|
||||||
var targetBitrate = ~~((file.file_size / (duration * 0.0075)) / 2)
|
var targetBitrate = ~~((file.file_size / (duration * 0.0075)) / 2)
|
||||||
|
// Allow some leeway under and over the targetBitrate.
|
||||||
var minimumBitrate = ~~(targetBitrate * 0.7)
|
var minimumBitrate = ~~(targetBitrate * 0.7)
|
||||||
var maximumBitrate = ~~(targetBitrate * 1.3)
|
var maximumBitrate = ~~(targetBitrate * 1.3)
|
||||||
|
|
||||||
|
// If targetBitrate comes out as 0 then something has gone wrong and bitrates could not be calculcated. Cancel plugin completely.
|
||||||
if (targetBitrate == "0") {
|
if (targetBitrate == "0") {
|
||||||
response.processFile = false
|
response.processFile = false
|
||||||
response.infoLog += "☒Target bitrate could not be calculated. Skipping this plugin. \n"
|
response.infoLog += "☒Target bitrate could not be calculated. Skipping this plugin. \n"
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if inputs.bitrate)cutoff has something entered (Entered means user actually wants something to happen, empty would disable this).
|
||||||
if (inputs.bitrate_cutoff != "") {
|
if (inputs.bitrate_cutoff != "") {
|
||||||
|
// Checks if currentBitrate is below inputs.bitrate_cutoff, if so then continue.
|
||||||
if (currentBitrate <= inputs.bitrate_cutoff) {
|
if (currentBitrate <= inputs.bitrate_cutoff) {
|
||||||
|
// Check if file.container matches inputs.container. If so nothing for plugin to do. Else remux container to inputs.container.
|
||||||
if (file.container == inputs.container) {
|
if (file.container == inputs.container) {
|
||||||
response.processFile = false
|
response.processFile = false
|
||||||
response.infoLog += `☑Current bitrate is below configured bitrate cutoff of ${inputs.bitrate_cutoff} & file container is already ${inputs.container}. Nothing to do, skipping. \n`
|
response.infoLog += `☑Current bitrate is below configured bitrate cutoff of ${inputs.bitrate_cutoff} & file container is already ${inputs.container}. Nothing to do, skipping. \n`
|
||||||
|
|
@ -100,54 +107,57 @@ function plugin(file, librarySettings, inputs) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Go through each stream in the file.
|
||||||
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
||||||
|
// Check if stream is a video.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
|
||||||
|
|
||||||
|
// Check if codec of stream is mjpeg, if so then remove this "video" stream. mjpeg are usually imbedded pictures that can cause havoc with plugins.
|
||||||
if (file.ffProbeData.streams[i].codec_name == 'mjpeg') {
|
if (file.ffProbeData.streams[i].codec_name == 'mjpeg') {
|
||||||
extraArguments += `-map -v:${videoIdx} `
|
extraArguments += `-map -v:${videoIdx} `
|
||||||
}
|
}
|
||||||
|
// Check if codec of stream is hevc AND check if file.container matches inputs.container. If so nothing for plugin to do.
|
||||||
if (file.ffProbeData.streams[i].codec_name == 'hevc' && file.container == inputs.container) {
|
if (file.ffProbeData.streams[i].codec_name == 'hevc' && file.container == inputs.container) {
|
||||||
response.processFile = false
|
response.processFile = false
|
||||||
response.infoLog += `☑File is already in ${inputs.container} & hevc. \n`
|
response.infoLog += `☑File is already in ${inputs.container} & hevc. \n`
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
// Check if codec of stream is hevc AND check if file.container does NOT match inputs.container. If so remux file.
|
||||||
if (file.ffProbeData.streams[i].codec_name == 'hevc' && file.container != '${inputs.container}') {
|
if (file.ffProbeData.streams[i].codec_name == 'hevc' && file.container != '${inputs.container}') {
|
||||||
response.infoLog += `☒File is hevc but is not in ${inputs.container} container. Remuxing. \n`
|
response.infoLog += `☒File is hevc but is not in ${inputs.container} container. Remuxing. \n`
|
||||||
response.preset = `, -map 0 -c copy ${extraArguments}`
|
response.preset = `, -map 0 -c copy ${extraArguments}`
|
||||||
response.processFile = true;
|
response.processFile = true;
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
// Increment videoIdx.
|
||||||
videoIdx++
|
videoIdx++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set bitrateSettings variable using bitrate information calulcated earlier.
|
||||||
bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k -maxrate ${maximumBitrate}k`
|
bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k -maxrate ${maximumBitrate}k`
|
||||||
|
// Print to infoLog information around file & bitrate settings.
|
||||||
response.infoLog += `Container for output selected as ${inputs.container}. \n Current bitrate = ${~~(file.file_size / (duration * 0.0075))} \n Bitrate settings: \nTarget = ${targetBitrate} \nMinimum = ${minimumBitrate} \nMaximum = ${maximumBitrate} \n`
|
response.infoLog += `Container for output selected as ${inputs.container}. \n Current bitrate = ${~~(file.file_size / (duration * 0.0075))} \n Bitrate settings: \nTarget = ${targetBitrate} \nMinimum = ${minimumBitrate} \nMaximum = ${maximumBitrate} \n`
|
||||||
|
|
||||||
//codec will be checked so it can be transcoded correctly
|
// Codec will be checked so it can be transcoded correctly
|
||||||
if (file.video_codec_name == 'h263') {
|
if (file.video_codec_name == 'h263') {
|
||||||
response.preset = `-c:v h263_cuvid`
|
response.preset = `-c:v h263_cuvid`
|
||||||
}
|
} else if (file.video_codec_name == 'h264') {
|
||||||
else if (file.video_codec_name == 'h264') {
|
|
||||||
if (file.ffProbeData.streams[0].profile != 'High 10') { //if a h264 coded video is not HDR
|
if (file.ffProbeData.streams[0].profile != 'High 10') { //if a h264 coded video is not HDR
|
||||||
response.preset = `-c:v h264_cuvid`
|
response.preset = `-c:v h264_cuvid`
|
||||||
}
|
}
|
||||||
}
|
} else if (file.video_codec_name == 'mjpeg') {
|
||||||
else if (file.video_codec_name == 'mjpeg') {
|
|
||||||
response.preset = `c:v mjpeg_cuvid`
|
response.preset = `c:v mjpeg_cuvid`
|
||||||
}
|
} else if (file.video_codec_name == 'mpeg1') {
|
||||||
else if (file.video_codec_name == 'mpeg1') {
|
|
||||||
response.preset = `-c:v mpeg1_cuvid`
|
response.preset = `-c:v mpeg1_cuvid`
|
||||||
}
|
} else if (file.video_codec_name == 'mpeg2') {
|
||||||
else if (file.video_codec_name == 'mpeg2') {
|
|
||||||
response.preset = `-c:v mpeg2_cuvid`
|
response.preset = `-c:v mpeg2_cuvid`
|
||||||
}
|
} else if (file.video_codec_name == 'vc1') {
|
||||||
else if (file.video_codec_name == 'vc1') {
|
|
||||||
response.preset = `-c:v vc1_cuvid`
|
response.preset = `-c:v vc1_cuvid`
|
||||||
}
|
} else if (file.video_codec_name == 'vp8') {
|
||||||
else if (file.video_codec_name == 'vp8') {
|
|
||||||
response.preset = `-c:v vp8_cuvid`
|
response.preset = `-c:v vp8_cuvid`
|
||||||
}
|
} else if (file.video_codec_name == 'vp9') {
|
||||||
else if (file.video_codec_name == 'vp9') {
|
|
||||||
response.preset = `-c:v vp9_cuvid`
|
response.preset = `-c:v vp9_cuvid`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,6 +167,5 @@ function plugin(file, librarySettings, inputs) {
|
||||||
response.infoLog += `☒File is not hevc. Transcoding. \n`
|
response.infoLog += `☒File is not hevc. Transcoding. \n`
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.details = details;
|
module.exports.details = details;
|
||||||
module.exports.plugin = plugin;
|
module.exports.plugin = plugin;
|
||||||
|
|
@ -4,13 +4,12 @@ function details() {
|
||||||
Stage: "Pre-processing",
|
Stage: "Pre-processing",
|
||||||
Name: "Migz-Transcode Using CPU & FFMPEG",
|
Name: "Migz-Transcode Using CPU & FFMPEG",
|
||||||
Type: "Video",
|
Type: "Video",
|
||||||
Operation:"Transcode",
|
Operation: "Transcode",
|
||||||
Description: `Files will be transcoded using CPU with ffmpeg, settings are dependant on file bitrate, working by the logic that H265 can support the same ammount of data at half the bitrate of H264. \n\n`,
|
Description: `Files will be transcoded using CPU with ffmpeg, settings are dependant on file bitrate, working by the logic that H265 can support the same ammount of data at half the bitrate of H264. \n\n`,
|
||||||
Version: "1.1",
|
Version: "1.2",
|
||||||
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz1FFMPEG_CPU.js",
|
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz1FFMPEG_CPU.js",
|
||||||
Tags:'pre-processing,ffmpeg,video only,configurable,h265',
|
Tags: 'pre-processing,ffmpeg,video only,configurable,h265',
|
||||||
Inputs: [
|
Inputs: [{
|
||||||
{
|
|
||||||
name: 'container',
|
name: 'container',
|
||||||
tooltip: `Specify output container of file, ensure that all stream types you may have are supported by your chosen container. mkv is recommended.
|
tooltip: `Specify output container of file, ensure that all stream types you may have are supported by your chosen container. mkv is recommended.
|
||||||
\\nExample:\\n
|
\\nExample:\\n
|
||||||
|
|
@ -29,8 +28,6 @@ function details() {
|
||||||
|
|
||||||
\\nExample:\\n
|
\\nExample:\\n
|
||||||
4000`
|
4000`
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -46,6 +43,7 @@ function plugin(file, librarySettings, inputs) {
|
||||||
infoLog: ''
|
infoLog: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if inputs.container has been configured. If it hasn't then exit plugin.
|
||||||
if (inputs.container == "") {
|
if (inputs.container == "") {
|
||||||
response.infoLog += "☒Container has not been configured within plugin settings, please configure required options. Skipping this plugin. \n"
|
response.infoLog += "☒Container has not been configured within plugin settings, please configure required options. Skipping this plugin. \n"
|
||||||
response.processFile = false
|
response.processFile = false
|
||||||
|
|
@ -54,39 +52,49 @@ function plugin(file, librarySettings, inputs) {
|
||||||
response.container = '.' + inputs.container
|
response.container = '.' + inputs.container
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if file is MKV, if so then add extra argument to drop data. MKV does not support data streams.
|
||||||
if (inputs.container == "mkv") {
|
if (inputs.container == "mkv") {
|
||||||
extraArguments += "-map -0:d "
|
extraArguments += "-map -0:d "
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if file is a video. If it isn't then exit plugin.
|
||||||
if (file.fileMedium !== "video") {
|
if (file.fileMedium !== "video") {
|
||||||
response.processFile = false
|
response.processFile = false
|
||||||
response.infoLog += "☒File is not a video. \n"
|
response.infoLog += "☒File is not a video. \n"
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if duration info is filled, if so times it by 0.0166667 to get time in minutes. If not filled then get duration of stream 0 and do the same.
|
||||||
if (typeof file.meta.Duration != 'undefined') {
|
if (typeof file.meta.Duration != 'undefined') {
|
||||||
var duration = (file.meta.Duration * 0.0166667)
|
var duration = (file.meta.Duration * 0.0166667)
|
||||||
} else {
|
} else {
|
||||||
var duration = (file.ffProbeData.streams[0].duration * 0.0166667)
|
var duration = (file.ffProbeData.streams[0].duration * 0.0166667)
|
||||||
}
|
}
|
||||||
|
|
||||||
var videoIdx = 0
|
// Set up required variables.
|
||||||
|
var videoIdx = -1
|
||||||
var extraArguments = ""
|
var extraArguments = ""
|
||||||
var bitrateSettings = ""
|
var bitrateSettings = ""
|
||||||
var filesize = (file.file_size / 1000)
|
// Work out currentBitrate using "Bitrate = file size / (number of minutes * .0075)" - Used from here https://blog.frame.io/2017/03/06/calculate-video-bitrates/
|
||||||
var currentBitrate = ~~(file.file_size / (duration * 0.0075))
|
var currentBitrate = ~~(file.file_size / (duration * 0.0075))
|
||||||
|
// Use the same calculation used for currentBitrate but divide it in half to get targetBitrate. Logic of h265 can be half the bitrate as h264 without losing quality.
|
||||||
var targetBitrate = ~~((file.file_size / (duration * 0.0075)) / 2)
|
var targetBitrate = ~~((file.file_size / (duration * 0.0075)) / 2)
|
||||||
|
// Allow some leeway under and over the targetBitrate.
|
||||||
var minimumBitrate = ~~(targetBitrate * 0.7)
|
var minimumBitrate = ~~(targetBitrate * 0.7)
|
||||||
var maximumBitrate = ~~(targetBitrate * 1.3)
|
var maximumBitrate = ~~(targetBitrate * 1.3)
|
||||||
|
|
||||||
|
// If targetBitrate comes out as 0 then something has gone wrong and bitrates could not be calculcated. Cancel plugin completely.
|
||||||
if (targetBitrate == "0") {
|
if (targetBitrate == "0") {
|
||||||
response.processFile = false
|
response.processFile = false
|
||||||
response.infoLog += "☒Target bitrate could not be calculated. Skipping this plugin. \n"
|
response.infoLog += "☒Target bitrate could not be calculated. Skipping this plugin. \n"
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if inputs.bitrate)cutoff has something entered (Entered means user actually wants something to happen, empty would disable this).
|
||||||
if (inputs.bitrate_cutoff != "") {
|
if (inputs.bitrate_cutoff != "") {
|
||||||
|
// Checks if currentBitrate is below inputs.bitrate_cutoff, if so then continue.
|
||||||
if (currentBitrate <= inputs.bitrate_cutoff) {
|
if (currentBitrate <= inputs.bitrate_cutoff) {
|
||||||
|
// Check if file.container matches inputs.container. If so nothing for plugin to do. Else remux container to inputs.container.
|
||||||
if (file.container == inputs.container) {
|
if (file.container == inputs.container) {
|
||||||
response.processFile = false
|
response.processFile = false
|
||||||
response.infoLog += `☑Current bitrate is below configured bitrate cutoff of ${inputs.bitrate_cutoff} & file container is already ${inputs.container}. Nothing to do, skipping. \n`
|
response.infoLog += `☑Current bitrate is below configured bitrate cutoff of ${inputs.bitrate_cutoff} & file container is already ${inputs.container}. Nothing to do, skipping. \n`
|
||||||
|
|
@ -99,27 +107,37 @@ function plugin(file, librarySettings, inputs) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Go through each stream in the file.
|
||||||
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
||||||
|
// Check if stream is a video.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
|
||||||
|
|
||||||
|
// Check if codec of stream is mjpeg, if so then remove this "video" stream. mjpeg are usually imbedded pictures that can cause havoc with plugins.
|
||||||
if (file.ffProbeData.streams[i].codec_name == 'mjpeg') {
|
if (file.ffProbeData.streams[i].codec_name == 'mjpeg') {
|
||||||
extraArguments += `-map -v:${videoIdx} `
|
extraArguments += `-map -v:${videoIdx} `
|
||||||
}
|
}
|
||||||
|
// Check if codec of stream is hevc AND check if file.container matches inputs.container. If so nothing for plugin to do.
|
||||||
if (file.ffProbeData.streams[i].codec_name == 'hevc' && file.container == inputs.container) {
|
if (file.ffProbeData.streams[i].codec_name == 'hevc' && file.container == inputs.container) {
|
||||||
response.processFile = false
|
response.processFile = false
|
||||||
response.infoLog += `☑File is already in ${inputs.container} & hevc. \n`
|
response.infoLog += `☑File is already in ${inputs.container} & hevc. \n`
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
// Check if codec of stream is hevc AND check if file.container does NOT match inputs.container. If so remux file.
|
||||||
if (file.ffProbeData.streams[i].codec_name == 'hevc' && file.container != '${inputs.container}') {
|
if (file.ffProbeData.streams[i].codec_name == 'hevc' && file.container != '${inputs.container}') {
|
||||||
response.infoLog += `☒File is hevc but is not in ${inputs.container} container. Remuxing. \n`
|
response.infoLog += `☒File is hevc but is not in ${inputs.container} container. Remuxing. \n`
|
||||||
response.preset = `, -map 0 -c copy ${extraArguments}`
|
response.preset = `, -map 0 -c copy ${extraArguments}`
|
||||||
response.processFile = true;
|
response.processFile = true;
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
// Increment videoIdx.
|
||||||
videoIdx++
|
videoIdx++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set bitrateSettings variable using bitrate information calulcated earlier.
|
||||||
bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k -maxrate ${maximumBitrate}k`
|
bitrateSettings = `-b:v ${targetBitrate}k -minrate ${minimumBitrate}k -maxrate ${maximumBitrate}k`
|
||||||
|
// Print to infoLog information around file & bitrate settings.
|
||||||
response.infoLog += `Container for output selected as ${inputs.container}. \n Current bitrate = ${~~(file.file_size / (duration * 0.0075))} \n Bitrate settings: \nTarget = ${targetBitrate} \nMinimum = ${minimumBitrate} \nMaximum = ${maximumBitrate} \n`
|
response.infoLog += `Container for output selected as ${inputs.container}. \n Current bitrate = ${~~(file.file_size / (duration * 0.0075))} \n Bitrate settings: \nTarget = ${targetBitrate} \nMinimum = ${minimumBitrate} \nMaximum = ${maximumBitrate} \n`
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -128,6 +146,5 @@ function plugin(file, librarySettings, inputs) {
|
||||||
response.infoLog += `☒File is not hevc. Transcoding. \n`
|
response.infoLog += `☒File is not hevc. Transcoding. \n`
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.details = details;
|
module.exports.details = details;
|
||||||
module.exports.plugin = plugin;
|
module.exports.plugin = plugin;
|
||||||
|
|
@ -6,11 +6,10 @@ function details() {
|
||||||
Type: "Video",
|
Type: "Video",
|
||||||
Operation: "Clean",
|
Operation: "Clean",
|
||||||
Description: `This plugin removes title metadata from video/audio/subtitles, if it exists. Video checking is mandatory, audio and subtitles are optional.\n\n`,
|
Description: `This plugin removes title metadata from video/audio/subtitles, if it exists. Video checking is mandatory, audio and subtitles are optional.\n\n`,
|
||||||
Version: "1.20",
|
Version: "1.2",
|
||||||
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz2CleanTitle.js",
|
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz2CleanTitle.js",
|
||||||
Tags:'pre-processing,ffmpeg,configurable',
|
Tags: 'pre-processing,ffmpeg,configurable',
|
||||||
Inputs: [
|
Inputs: [{
|
||||||
{
|
|
||||||
name: 'clean_audio',
|
name: 'clean_audio',
|
||||||
tooltip: `Specify if audio titles should be checked & cleaned. Optional.
|
tooltip: `Specify if audio titles should be checked & cleaned. Optional.
|
||||||
\\nExample:\\n
|
\\nExample:\\n
|
||||||
|
|
@ -34,22 +33,24 @@ function details() {
|
||||||
|
|
||||||
function plugin(file, librarySettings, inputs) {
|
function plugin(file, librarySettings, inputs) {
|
||||||
var response = {
|
var response = {
|
||||||
processFile : false,
|
processFile: false,
|
||||||
preset : '',
|
preset: '',
|
||||||
container: '.' + file.container,
|
container: '.' + file.container,
|
||||||
handBrakeMode : false,
|
handBrakeMode: false,
|
||||||
FFmpegMode : true,
|
FFmpegMode: true,
|
||||||
reQueueAfter : false,
|
reQueueAfter: false,
|
||||||
infoLog : '',
|
infoLog: '',
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up required variables.
|
||||||
var ffmpegCommandInsert = ''
|
var ffmpegCommandInsert = ''
|
||||||
var videoIdx = 0
|
var videoIdx = 0
|
||||||
var audioIdx = 0
|
var audioIdx = 0
|
||||||
var subtitleIdx = 0
|
var subtitleIdx = 0
|
||||||
var convert = false
|
var convert = false
|
||||||
|
|
||||||
|
// Check if file is a video. If it isn't then exit plugin.
|
||||||
if (file.fileMedium !== "video") {
|
if (file.fileMedium !== "video") {
|
||||||
console.log("File is not video")
|
console.log("File is not video")
|
||||||
response.infoLog += "☒File is not video \n"
|
response.infoLog += "☒File is not video \n"
|
||||||
|
|
@ -57,40 +58,50 @@ function plugin(file, librarySettings, inputs) {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if overall file metadata title is not empty, if it's not empty set to "".
|
||||||
if (typeof file.meta.Title != 'undefined') try {
|
if (typeof file.meta.Title != 'undefined') try {
|
||||||
ffmpegCommandInsert += ` -metadata title="" `
|
ffmpegCommandInsert += ` -metadata title="" `
|
||||||
convert = true
|
convert = true
|
||||||
} catch (err) { }
|
} catch (err) {}
|
||||||
|
|
||||||
|
// Go through each stream in the file.
|
||||||
for (var i = 0; i < file.ffProbeData.streams.length; i++) try {
|
for (var i = 0; i < file.ffProbeData.streams.length; i++) try {
|
||||||
|
// Check if stream is a video.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
|
||||||
|
// Check if stream title is not empty, if it's nto empty set to "".
|
||||||
if (typeof file.ffProbeData.streams[i].tags.title != 'undefined') {
|
if (typeof file.ffProbeData.streams[i].tags.title != 'undefined') {
|
||||||
response.infoLog += `☒Video stream title is not empty, most likely junk metadata. Removing title from stream ${i} \n`
|
response.infoLog += `☒Video stream title is not empty, most likely junk metadata. Removing title from stream ${i} \n`
|
||||||
ffmpegCommandInsert += ` -metadata:s:v:${videoIdx} title="" `
|
ffmpegCommandInsert += ` -metadata:s:v:${videoIdx} title="" `
|
||||||
convert = true
|
convert = true
|
||||||
}
|
}
|
||||||
|
// Increment videoIdx.
|
||||||
videoIdx++
|
videoIdx++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if title metadata of audio stream has more then 3 full stops. If so then it's likely to be junk metadata so remove.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && inputs.clean_audio.toLowerCase() == "true") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && inputs.clean_audio.toLowerCase() == "true") {
|
||||||
if (file.ffProbeData.streams[i].tags.title.split('.').length-1 > 3) {
|
if (file.ffProbeData.streams[i].tags.title.split('.').length - 1 > 3) {
|
||||||
response.infoLog += `☒More then 3 full stops detected in subtitle title, likely to be junk metadata. Removing title from stream ${i} \n`
|
response.infoLog += `☒More then 3 full stops detected in audio title, likely to be junk metadata. Removing title from stream ${i} \n`
|
||||||
ffmpegCommandInsert += ` -metadata:s:a:${audioIdx} title="" `
|
ffmpegCommandInsert += ` -metadata:s:a:${audioIdx} title="" `
|
||||||
convert = true
|
convert = true
|
||||||
}
|
}
|
||||||
|
// Increment audioIdx.
|
||||||
audioIdx++
|
audioIdx++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if title metadata of subtitle stream has more then 3 full stops. If so then it's likely to be junk metadata so remove.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" && inputs.clean_subtitles.toLowerCase() == "true") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" && inputs.clean_subtitles.toLowerCase() == "true") {
|
||||||
if (file.ffProbeData.streams[i].tags.title.split('.').length-1 > 3) {
|
if (file.ffProbeData.streams[i].tags.title.split('.').length - 1 > 3) {
|
||||||
response.infoLog += `☒More then 3 full stops detected in subtitle title, likely to be junk metadata. Removing title from stream ${i} \n`
|
response.infoLog += `☒More then 3 full stops detected in subtitle title, likely to be junk metadata. Removing title from stream ${i} \n`
|
||||||
ffmpegCommandInsert += ` -metadata:s:s:${subtitleIdx} title="" `
|
ffmpegCommandInsert += ` -metadata:s:s:${subtitleIdx} title="" `
|
||||||
convert = true
|
convert = true
|
||||||
}
|
}
|
||||||
|
// Increment subtitleIdx.
|
||||||
subtitleIdx++
|
subtitleIdx++
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
} catch (err) {}
|
||||||
|
|
||||||
|
// Convert file if convert variable is set to true.
|
||||||
if (convert == true) {
|
if (convert == true) {
|
||||||
response.infoLog += "☒File has title metadata. Removing \n"
|
response.infoLog += "☒File has title metadata. Removing \n"
|
||||||
response.preset = `,${ffmpegCommandInsert} -c copy -map 0 -max_muxing_queue_size 4096`
|
response.preset = `,${ffmpegCommandInsert} -c copy -map 0 -max_muxing_queue_size 4096`
|
||||||
|
|
@ -101,6 +112,5 @@ function plugin(file, librarySettings, inputs) {
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.details = details;
|
module.exports.details = details;
|
||||||
module.exports.plugin = plugin;
|
module.exports.plugin = plugin;
|
||||||
|
|
@ -6,11 +6,10 @@ function details() {
|
||||||
Type: "Audio",
|
Type: "Audio",
|
||||||
Operation: "Clean",
|
Operation: "Clean",
|
||||||
Description: `This plugin keeps only specified language audio tracks & can tags those that have an unknown language. \n\n`,
|
Description: `This plugin keeps only specified language audio tracks & can tags those that have an unknown language. \n\n`,
|
||||||
Version: "2.00",
|
Version: "2.1",
|
||||||
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz3CleanAudio.js",
|
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz3CleanAudio.js",
|
||||||
Tags:'pre-processing,ffmpeg,audio only,configurable',
|
Tags: 'pre-processing,ffmpeg,audio only,configurable',
|
||||||
Inputs: [
|
Inputs: [{
|
||||||
{
|
|
||||||
name: 'language',
|
name: 'language',
|
||||||
tooltip: `Specify language tag/s here for the audio tracks you'd like to keep, recommended to keep "und" as this stands for undertermined, some files may not have the language specified. Must follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
|
tooltip: `Specify language tag/s here for the audio tracks you'd like to keep, recommended to keep "und" as this stands for undertermined, some files may not have the language specified. Must follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
|
||||||
\\nExample:\\n
|
\\nExample:\\n
|
||||||
|
|
@ -38,8 +37,7 @@ function details() {
|
||||||
eng
|
eng
|
||||||
|
|
||||||
\\nExample:\\n
|
\\nExample:\\n
|
||||||
por
|
por`
|
||||||
`
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'tag_title',
|
name: 'tag_title',
|
||||||
|
|
@ -65,6 +63,7 @@ function plugin(file, librarySettings, inputs) {
|
||||||
infoLog: '',
|
infoLog: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if file is a video. If it isn't then exit plugin.
|
||||||
if (file.fileMedium !== "video") {
|
if (file.fileMedium !== "video") {
|
||||||
console.log("File is not video")
|
console.log("File is not video")
|
||||||
response.infoLog += "☒File is not video \n"
|
response.infoLog += "☒File is not video \n"
|
||||||
|
|
@ -72,64 +71,68 @@ function plugin(file, librarySettings, inputs) {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if inputs.language has been configured. If it hasn't then exit plugin.
|
||||||
if (inputs.language == "") {
|
if (inputs.language == "") {
|
||||||
response.infoLog += "☒Language/s keep have not been configured within plugin settings, please configure required options. Skipping this plugin. \n"
|
response.infoLog += "☒Language/s keep have not been configured within plugin settings, please configure required options. Skipping this plugin. \n"
|
||||||
response.processFile = false;
|
response.processFile = false;
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up required variables.
|
||||||
var language = inputs.language.split(",")
|
var language = inputs.language.split(",")
|
||||||
var ffmpegCommandInsert = ''
|
var ffmpegCommandInsert = ''
|
||||||
var convert = false
|
var convert = false
|
||||||
var audioIdx = -1
|
var audioIdx = 0
|
||||||
var audioStreamsRemoved = 0
|
var audioStreamsRemoved = 0
|
||||||
var audioStreamCount = file.ffProbeData.streams.filter(row => (row.codec_type.toLowerCase() == "audio")).length;
|
var audioStreamCount = file.ffProbeData.streams.filter(row => (row.codec_type.toLowerCase() == "audio")).length;
|
||||||
|
|
||||||
console.log("audioStreamCount:" + audioStreamCount)
|
|
||||||
response.infoLog += `Languages to keep are ${language} \n`
|
|
||||||
|
|
||||||
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
||||||
try {
|
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
|
|
||||||
audioIdx++
|
|
||||||
}
|
|
||||||
} catch (err) { }
|
|
||||||
|
|
||||||
|
// Catch error here incase the language metadata is completely missing.
|
||||||
try {
|
try {
|
||||||
|
// Check if stream is audio AND checks if the tracks language code does not match any of the languages entered in inputs.language.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && language.indexOf(file.ffProbeData.streams[i].tags.language.toLowerCase()) === -1) {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && language.indexOf(file.ffProbeData.streams[i].tags.language.toLowerCase()) === -1) {
|
||||||
audioStreamsRemoved++
|
audioStreamsRemoved++
|
||||||
ffmpegCommandInsert += `-map -0:a:${audioIdx} `
|
ffmpegCommandInsert += `-map -0:a:${audioIdx} `
|
||||||
response.infoLog += `☒Audio stream detected as being an unwanted language, removing. Audio stream 0:a:${audioIdx} - ${file.ffProbeData.streams[i].tags.language.toLowerCase()} \n`
|
response.infoLog += `☒Audio stream detected as being an unwanted language, removing. Audio stream 0:a:${audioIdx} - ${file.ffProbeData.streams[i].tags.language.toLowerCase()} \n`
|
||||||
convert = true
|
convert = true
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
} catch (err) {}
|
||||||
|
|
||||||
|
// Catch error here incase the title metadata is completely missing.
|
||||||
try {
|
try {
|
||||||
|
// Check if inputs.commentary is set to true AND if stream is audio AND then checks for stream titles with the following "commentary, description, sdh". Removing any streams that are applicable.
|
||||||
if (inputs.commentary.toLowerCase() == "true" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && (file.ffProbeData.streams[i].tags.title.toLowerCase().includes('commentary') || file.ffProbeData.streams[i].tags.title.toLowerCase().includes('description') || file.ffProbeData.streams[i].tags.title.toLowerCase().includes('sdh'))) {
|
if (inputs.commentary.toLowerCase() == "true" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && (file.ffProbeData.streams[i].tags.title.toLowerCase().includes('commentary') || file.ffProbeData.streams[i].tags.title.toLowerCase().includes('description') || file.ffProbeData.streams[i].tags.title.toLowerCase().includes('sdh'))) {
|
||||||
audioStreamsRemoved++
|
audioStreamsRemoved++
|
||||||
ffmpegCommandInsert += `-map -0:a:${audioIdx} `
|
ffmpegCommandInsert += `-map -0:a:${audioIdx} `
|
||||||
response.infoLog += `☒Audio stream detected as being Commentary or Description, removing. Audio stream 0:a:${audioIdx} - ${file.ffProbeData.streams[i].tags.title}. \n`
|
response.infoLog += `☒Audio stream detected as being Commentary or Description, removing. Audio stream 0:a:${audioIdx} - ${file.ffProbeData.streams[i].tags.title}. \n`
|
||||||
convert = true
|
convert = true
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
} catch (err) {}
|
||||||
|
|
||||||
|
// Check if inputs.tag_language has something entered (Entered means user actually wants something to happen, empty would disable this) AND checks that stream is audio.
|
||||||
|
if (inputs.tag_language != "" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
|
||||||
|
// Catch error here incase the metadata is completely missing.
|
||||||
try {
|
try {
|
||||||
if (inputs.tag_language != "") {
|
// Look for audio with "und" as metadata language.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].tags.language.toLowerCase().includes('und') && language.indexOf('und') !== -1) {
|
if (file.ffProbeData.streams[i].tags.language.toLowerCase().includes('und')) {
|
||||||
|
response.infoLog += `first`
|
||||||
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} language=${inputs.tag_language} `
|
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} language=${inputs.tag_language} `
|
||||||
response.infoLog += `☒Audio stream detected as having unknown language tagged, tagging as ${inputs.tag_language}. \n`
|
response.infoLog += `☒Audio stream detected as having unknown language tagged, tagging as ${inputs.tag_language}. \n`
|
||||||
convert = true
|
convert = true
|
||||||
}
|
}
|
||||||
|
} catch (err) {}
|
||||||
|
|
||||||
if (typeof file.ffProbeData.streams[i].tags.language === 'undefined' && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
|
// Checks if the tags.language metadata is completely missing, if so this would cause playback to show language as "undefined". No catch error here otherwise it would never detect the metadata as missing.
|
||||||
|
if (typeof file.ffProbeData.streams[i].tags.language == 'undefined') {
|
||||||
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} language=${inputs.tag_language} `
|
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} language=${inputs.tag_language} `
|
||||||
response.infoLog += `☒Audio stream detected as having no language tagged, tagging as ${inputs.tag_language}. \n`
|
response.infoLog += `☒Audio stream detected as having no language tagged, tagging as ${inputs.tag_language}. \n`
|
||||||
convert = true
|
convert = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Check if title metadata is missing from any streams AND inputs.tag_title set to true AND if stream type is audio. Add title to any applicable streams.
|
||||||
if (typeof file.ffProbeData.streams[i].tags.title == 'undefined' && inputs.tag_title.toLowerCase() == "true" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
|
if (typeof file.ffProbeData.streams[i].tags.title == 'undefined' && inputs.tag_title.toLowerCase() == "true" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
|
||||||
if (file.ffProbeData.streams[i].channels == "8") {
|
if (file.ffProbeData.streams[i].channels == "8") {
|
||||||
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} title="7.1" `
|
ffmpegCommandInsert += `-metadata:s:a:${audioIdx} title="7.1" `
|
||||||
|
|
@ -147,17 +150,22 @@ function plugin(file, librarySettings, inputs) {
|
||||||
convert = true
|
convert = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
} catch (err) {}
|
||||||
|
|
||||||
|
// Check if stream type is audio and increment audioIdx if true.
|
||||||
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
|
||||||
|
audioIdx++
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// Failsafe to cancel processing if all streams would be removed following this plugin. We don't want no audio.
|
||||||
if (audioStreamsRemoved == audioStreamCount) {
|
if (audioStreamsRemoved == audioStreamCount) {
|
||||||
response.infoLog += "☒Cancelling plugin otherwise all audio tracks would be removed. \n"
|
response.infoLog += "☒Cancelling plugin otherwise all audio tracks would be removed. \n"
|
||||||
response.processFile = false
|
response.processFile = false
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
if (convert === true && (audioStreamsRemoved != audioStreamCount)) {
|
// Convert file if convert variable is set to true.
|
||||||
|
if (convert === true) {
|
||||||
response.processFile = true
|
response.processFile = true
|
||||||
response.preset = `, -map 0 ${ffmpegCommandInsert} -c copy -max_muxing_queue_size 4096`
|
response.preset = `, -map 0 ${ffmpegCommandInsert} -c copy -max_muxing_queue_size 4096`
|
||||||
response.container = '.' + file.container
|
response.container = '.' + file.container
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,13 @@ function details() {
|
||||||
id: "Tdarr_Plugin_MC93_Migz4CleanSubs",
|
id: "Tdarr_Plugin_MC93_Migz4CleanSubs",
|
||||||
Stage: "Pre-processing",
|
Stage: "Pre-processing",
|
||||||
Name: "Migz-Clean subtitle streams",
|
Name: "Migz-Clean subtitle streams",
|
||||||
Type: "subtitless",
|
Type: "subtitles",
|
||||||
Operation: "Clean",
|
Operation: "Clean",
|
||||||
Description: `This plugin keeps only specified language subtitle tracks & can tag those that have an unknown language. \n\n`,
|
Description: `This plugin keeps only specified language subtitle tracks & can tag those that have an unknown language. \n\n`,
|
||||||
Version: "2.00",
|
Version: "2.1",
|
||||||
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz4CleanSubs.js",
|
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz4CleanSubs.js",
|
||||||
Tags:'pre-processing,ffmpeg,subtitle only,configurable',
|
Tags: 'pre-processing,ffmpeg,subtitle only,configurable',
|
||||||
Inputs: [
|
Inputs: [{
|
||||||
{
|
|
||||||
name: 'language',
|
name: 'language',
|
||||||
tooltip: `Specify language tag/s here for the subtitle tracks you'd like to keep. Must follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
|
tooltip: `Specify language tag/s here for the subtitle tracks you'd like to keep. Must follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
|
||||||
\\nExample:\\n
|
\\nExample:\\n
|
||||||
|
|
@ -29,7 +28,7 @@ function details() {
|
||||||
false`
|
false`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'tag_title',
|
name: 'tag_language',
|
||||||
tooltip: `Specify a single language for subtitle tracks with no language or unknown language to be tagged with, leave empty to disable. Must follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
|
tooltip: `Specify a single language for subtitle tracks with no language or unknown language to be tagged with, leave empty to disable. Must follow ISO-639-2 3 letter format. https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
|
||||||
\\nExample:\\n
|
\\nExample:\\n
|
||||||
eng
|
eng
|
||||||
|
|
@ -52,6 +51,7 @@ function plugin(file, librarySettings, inputs) {
|
||||||
infoLog: '',
|
infoLog: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if file is a video. If it isn't then exit plugin.
|
||||||
if (file.fileMedium !== "video") {
|
if (file.fileMedium !== "video") {
|
||||||
console.log("File is not video")
|
console.log("File is not video")
|
||||||
response.infoLog += "☒File is not video \n"
|
response.infoLog += "☒File is not video \n"
|
||||||
|
|
@ -59,59 +59,70 @@ function plugin(file, librarySettings, inputs) {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if inputs.language has been configured. If it hasn't then exit plugin.
|
||||||
if (inputs.language == "") {
|
if (inputs.language == "") {
|
||||||
response.infoLog += "☒Language/s keep have not been configured within plugin settings, please configure required options. Skipping this plugin. \n"
|
response.infoLog += "☒Language/s keep have not been configured within plugin settings, please configure required options. Skipping this plugin. \n"
|
||||||
response.processFile = false;
|
response.processFile = false;
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up required variables.
|
||||||
var language = inputs.language.split(",")
|
var language = inputs.language.split(",")
|
||||||
var ffmpegCommandInsert = ''
|
var ffmpegCommandInsert = ''
|
||||||
var subtitleIdx = -1
|
var subtitleIdx = 0
|
||||||
var convert = false
|
var convert = false
|
||||||
|
|
||||||
|
// Go through each stream in the file.
|
||||||
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
||||||
try {
|
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") {
|
|
||||||
subtitleIdx++
|
|
||||||
}
|
|
||||||
} catch (err) { }
|
|
||||||
|
|
||||||
|
// Catch error here incase the language metadata is completely missing.
|
||||||
try {
|
try {
|
||||||
|
// Check if stream is subtitle AND checks if the tracks language code does not match any of the languages entered in inputs.language.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" && language.indexOf(file.ffProbeData.streams[i].tags.language.toLowerCase()) === -1) {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" && language.indexOf(file.ffProbeData.streams[i].tags.language.toLowerCase()) === -1) {
|
||||||
ffmpegCommandInsert += `-map -0:s:${subtitleIdx} `
|
ffmpegCommandInsert += `-map -0:s:${subtitleIdx} `
|
||||||
response.infoLog += `☒Subtitle stream detected as being an unwanted language, removing. Subtitle stream 0:s:${subtitleIdx} - ${file.ffProbeData.streams[i].tags.language.toLowerCase()} \n`
|
response.infoLog += `☒Subtitle stream detected as being an unwanted language, removing. Subtitle stream 0:s:${subtitleIdx} - ${file.ffProbeData.streams[i].tags.language.toLowerCase()} \n`
|
||||||
convert = true
|
convert = true
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
} catch (err) {}
|
||||||
|
|
||||||
|
// Catch error here incase the title metadata is completely missing.
|
||||||
try {
|
try {
|
||||||
|
// Check if inputs.commentary is set to true AND if stream is subtitle AND then checks for stream titles with the following "commentary, description, sdh". Removing any streams that are applicable.
|
||||||
if (inputs.commentary.toLowerCase() == "true" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" && (file.ffProbeData.streams[i].tags.title.toLowerCase().includes('commentary') || file.ffProbeData.streams[i].tags.title.toLowerCase().includes('description') || file.ffProbeData.streams[i].tags.title.toLowerCase().includes('sdh'))) {
|
if (inputs.commentary.toLowerCase() == "true" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" && (file.ffProbeData.streams[i].tags.title.toLowerCase().includes('commentary') || file.ffProbeData.streams[i].tags.title.toLowerCase().includes('description') || file.ffProbeData.streams[i].tags.title.toLowerCase().includes('sdh'))) {
|
||||||
ffmpegCommandInsert += `-map -0:s:${subtitleIdx} `
|
ffmpegCommandInsert += `-map -0:s:${subtitleIdx} `
|
||||||
response.infoLog += `☒Subtitle stream detected as being Commentary or Description, removing. Subtitle stream 0:s:${SubtitleIdx} - ${file.ffProbeData.streams[i].tags.title}. \n`
|
response.infoLog += `☒Subtitle stream detected as being Commentary or Description, removing. Subtitle stream 0:s:${SubtitleIdx} - ${file.ffProbeData.streams[i].tags.title}. \n`
|
||||||
convert = true
|
convert = true
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
} catch (err) {}
|
||||||
|
|
||||||
|
// Check if inputs.tag_language has something entered (Entered means user actually wants something to happen, empty would disable this) AND checks that stream is audio.
|
||||||
|
if (inputs.tag_language != "" && file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") {
|
||||||
|
// Catch error here incase the metadata is completely missing.
|
||||||
try {
|
try {
|
||||||
if (inputs.tag_title != "") {
|
// Look for subtitle with "und" as metadata language.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle" && file.ffProbeData.streams[i].tags.language.toLowerCase().includes('und')) {
|
if (file.ffProbeData.streams[i].tags.language.toLowerCase().includes('und')) {
|
||||||
ffmpegCommandInsert += `-metadata:s:s:${subtitleIdx} language=${inputs.tag_title} `
|
ffmpegCommandInsert += `-metadata:s:s:${subtitleIdx} language=${inputs.tag_language} `
|
||||||
response.infoLog += `☒Subtitle stream detected as having unknown language tagged, tagging as ${inputs.tag_title}. \n`
|
response.infoLog += `☒Subtitle stream detected as having unknown language tagged, tagging as ${inputs.tag_language}. \n`
|
||||||
convert = true
|
convert = true
|
||||||
}
|
}
|
||||||
}
|
} catch (err) {}
|
||||||
} catch (err) { }
|
|
||||||
|
|
||||||
try {
|
// Checks if the tags.language metadata is completely missing, if so this would cause playback to show language as "undefined". No catch error here otherwise it would never detect the metadata as missing.
|
||||||
if (typeof file.ffProbeData.streams[i].tags.language == 'undefined' && file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") {
|
if (typeof file.ffProbeData.streams[i].tags.language == 'undefined' && file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") {
|
||||||
ffmpegCommandInsert += `-metadata:s:s:${subtitleIdx} language=${inputs.tag_title} `
|
ffmpegCommandInsert += `-metadata:s:s:${subtitleIdx} language=${inputs.tag_language} `
|
||||||
response.infoLog += `☒Subtitle stream detected as having no language tagged, tagging as ${inputs.tag_title}. \n`
|
response.infoLog += `☒Subtitle stream detected as having no language tagged, tagging as ${inputs.tag_language}. \n`
|
||||||
convert = true
|
convert = true
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
|
||||||
}
|
}
|
||||||
if (convert === true ) {
|
|
||||||
|
// Check if stream type is subtitle and increment subtitleIdx if true.
|
||||||
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") {
|
||||||
|
subtitleIdx++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert file if convert variable is set to true.
|
||||||
|
if (convert === true) {
|
||||||
response.processFile = true;
|
response.processFile = true;
|
||||||
response.preset = `, -map 0 ${ffmpegCommandInsert} -c copy -max_muxing_queue_size 4096`
|
response.preset = `, -map 0 ${ffmpegCommandInsert} -c copy -max_muxing_queue_size 4096`
|
||||||
response.container = '.' + file.container
|
response.container = '.' + file.container
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,12 @@ function details() {
|
||||||
Type: "Audio",
|
Type: "Audio",
|
||||||
Operation: "Transcode",
|
Operation: "Transcode",
|
||||||
Description: `This plugin can convert any 2.0 audio track/s to AAC and can create downmixed audio tracks. \n\n`,
|
Description: `This plugin can convert any 2.0 audio track/s to AAC and can create downmixed audio tracks. \n\n`,
|
||||||
Version: "2.00",
|
Version: "2.1",
|
||||||
Link: "",
|
Link: "",
|
||||||
Tags:'pre-processing,ffmpeg,audio only,configurable',
|
Tags: 'pre-processing,ffmpeg,audio only,configurable',
|
||||||
Inputs: [
|
Inputs: [{
|
||||||
{
|
|
||||||
name: 'aac_stereo',
|
name: 'aac_stereo',
|
||||||
tooltip: `Specify if any 2.0 audio tracks should be converted to aac for maximum compatability with devices.
|
tooltip: `Specify if any 2.0 audio tracks should be converted to aac for maximum compatability with devices. Optional.
|
||||||
\\nExample:\\n
|
\\nExample:\\n
|
||||||
true
|
true
|
||||||
|
|
||||||
|
|
@ -21,7 +20,7 @@ function details() {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'downmix',
|
name: 'downmix',
|
||||||
tooltip: `Specify if downmixing should be used to create extra audio tracks. I.e if you have an 8ch but no 2ch or 6ch, create the missing audio tracks from the 8 ch. Likewise if you only have 6ch, create the missing 2ch from it.
|
tooltip: `Specify if downmixing should be used to create extra audio tracks. I.e if you have an 8ch but no 2ch or 6ch, create the missing audio tracks from the 8 ch. Likewise if you only have 6ch, create the missing 2ch from it. Optional.
|
||||||
\\nExample:\\n
|
\\nExample:\\n
|
||||||
true
|
true
|
||||||
|
|
||||||
|
|
@ -42,7 +41,14 @@ function plugin(file, librarySettings, inputs) {
|
||||||
infoLog: '',
|
infoLog: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if both inputs.aac_stereo AND inputs.downmix have been left empty. If they have then exit plugin.
|
||||||
|
if (inputs && inputs.aac_stereo == "" && inputs.downmix == "") {
|
||||||
|
response.infoLog += "☒Neither aac_stereo or downmix options have been configured within plugin settings, please configure required options. Skipping this plugin. \n"
|
||||||
|
response.processFile = false
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if file is a video. If it isn't then exit plugin.
|
||||||
if (file.fileMedium !== "video") {
|
if (file.fileMedium !== "video") {
|
||||||
console.log("File is not video")
|
console.log("File is not video")
|
||||||
response.infoLog += "☒File is not video. \n"
|
response.infoLog += "☒File is not video. \n"
|
||||||
|
|
@ -50,12 +56,7 @@ function plugin(file, librarySettings, inputs) {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inputs.aac_stereo == "" && inputs.downmix == "") {
|
// Set up required variables.
|
||||||
response.infoLog += "☒Neither aac_stereo or downmix options have been configured within plugin settings, please configure required options. Skipping this plugin. \n"
|
|
||||||
response.processFile = false
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
var ffmpegCommandInsert = ''
|
var ffmpegCommandInsert = ''
|
||||||
var audioIdx = 0
|
var audioIdx = 0
|
||||||
var has2Channel = false
|
var has2Channel = false
|
||||||
|
|
@ -63,8 +64,10 @@ function plugin(file, librarySettings, inputs) {
|
||||||
var has8Channel = false
|
var has8Channel = false
|
||||||
var convert = false
|
var convert = false
|
||||||
|
|
||||||
|
// Go through each stream in the file.
|
||||||
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
||||||
try {
|
try {
|
||||||
|
// Go through all audio streams and check if 2,6 & 8 channel tracks exist or not.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
|
||||||
if (file.ffProbeData.streams[i].channels == "2") {
|
if (file.ffProbeData.streams[i].channels == "2") {
|
||||||
has2Channel = true
|
has2Channel = true
|
||||||
|
|
@ -76,35 +79,50 @@ function plugin(file, librarySettings, inputs) {
|
||||||
has8Channel = true
|
has8Channel = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
} catch (err) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Go through each stream in the file.
|
||||||
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
||||||
|
// Check if stream is audio.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
|
||||||
|
// Catch error here incase user left inputs.downmix empty.
|
||||||
|
try {
|
||||||
|
// Check if inputs.downmix is set to true.
|
||||||
if (inputs.downmix.toLowerCase() == "true") {
|
if (inputs.downmix.toLowerCase() == "true") {
|
||||||
|
// Check if file has 8 channel audio but no 6 channel, if so then create extra downmix from the 8 channel.
|
||||||
if (has8Channel == true && has6Channel == false && file.ffProbeData.streams[i].channels == "8") {
|
if (has8Channel == true && has6Channel == false && file.ffProbeData.streams[i].channels == "8") {
|
||||||
ffmpegCommandInsert += `-map 0:${i} -c:a:${audioIdx} ac3 -ac 6 -metadata:s:a:${audioIdx} title="5.1 " `
|
ffmpegCommandInsert += `-map 0:${i} -c:a:${audioIdx} ac3 -ac 6 -metadata:s:a:${audioIdx} title="5.1 " `
|
||||||
response.infoLog += "☒Audio track is 8 channel, no 6 channel exists. Creating 2 channel from 8 channel. \n"
|
response.infoLog += "☒Audio track is 8 channel, no 6 channel exists. Creating 6 channel from 8 channel. \n"
|
||||||
convert = true
|
convert = true
|
||||||
}
|
}
|
||||||
|
// Check if file has 6 channel audio but no 2 channel, if so then create extra downmix from the 6 channel.
|
||||||
if (has6Channel == true && has2Channel == false && file.ffProbeData.streams[i].channels == "6") {
|
if (has6Channel == true && has2Channel == false && file.ffProbeData.streams[i].channels == "6") {
|
||||||
ffmpegCommandInsert += `-map 0:${i} -c:a:${audioIdx} aac -ac 2 -metadata:s:a:${audioIdx} title="2.0 " `
|
ffmpegCommandInsert += `-map 0:${i} -c:a:${audioIdx} aac -ac 2 -metadata:s:a:${audioIdx} title="2.0 " `
|
||||||
response.infoLog += "☒Audio track is 6 channel, no 2 channel exists. Creating 2 channel from 6 channel. \n"
|
response.infoLog += "☒Audio track is 6 channel, no 2 channel exists. Creating 2 channel from 6 channel. \n"
|
||||||
convert = true
|
convert = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (err) {}
|
||||||
|
|
||||||
|
// Catch error here incase user left inputs.downmix empty.
|
||||||
|
try {
|
||||||
|
// Check if inputs.aac_stereo is set to true.
|
||||||
if (inputs.aac_stereo.toLowerCase() == "true") {
|
if (inputs.aac_stereo.toLowerCase() == "true") {
|
||||||
if (file.ffProbeData.streams[i].codec_name != "aac" && file.ffProbeData.streams[i].channels == "2" ) {
|
// Check if codec_name for stream is NOT aac AND check if channel ammount is 2.
|
||||||
|
if (file.ffProbeData.streams[i].codec_name != "aac" && file.ffProbeData.streams[i].channels == "2") {
|
||||||
ffmpegCommandInsert += `-c:a:${audioIdx} aac `
|
ffmpegCommandInsert += `-c:a:${audioIdx} aac `
|
||||||
response.infoLog += "☒Audio track is 2 channel but is not AAC. Converting. \n"
|
response.infoLog += "☒Audio track is 2 channel but is not AAC. Converting. \n"
|
||||||
convert = true
|
convert = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (err) {}
|
||||||
audioIdx++
|
audioIdx++
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert file if convert variable is set to true.
|
||||||
if (convert == true) {
|
if (convert == true) {
|
||||||
response.processFile = true;
|
response.processFile = true;
|
||||||
response.preset = `, -map 0 -c:v copy -c:a copy ${ffmpegCommandInsert} -strict -2 -c:s copy -max_muxing_queue_size 4096 `
|
response.preset = `, -map 0 -c:v copy -c:a copy ${ffmpegCommandInsert} -strict -2 -c:s copy -max_muxing_queue_size 4096 `
|
||||||
|
|
@ -115,6 +133,5 @@ function plugin(file, librarySettings, inputs) {
|
||||||
return response
|
return response
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.details = details;
|
module.exports.details = details;
|
||||||
module.exports.plugin = plugin;
|
module.exports.plugin = plugin;
|
||||||
|
|
@ -2,13 +2,13 @@ function details() {
|
||||||
return {
|
return {
|
||||||
id: "Tdarr_Plugin_MC93_Migz6OrderStreams",
|
id: "Tdarr_Plugin_MC93_Migz6OrderStreams",
|
||||||
Stage: "Pre-processing",
|
Stage: "Pre-processing",
|
||||||
Name: "Migz-Organize Streams",
|
Name: "Migz-Order Streams",
|
||||||
Type: "Streams",
|
Type: "Streams",
|
||||||
Operation: "Organize",
|
Operation: "Order",
|
||||||
Description: `Organizes streams into Video first, then Audio (2ch, 6ch, 8ch) and finally Subtitles. \n\n`,
|
Description: `Orders streams into Video first, then Audio (2ch, 6ch, 8ch) and finally Subtitles. \n\n`,
|
||||||
Version: "1.00",
|
Version: "1.1",
|
||||||
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz6OrderStreams.js",
|
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_Migz6OrderStreams.js",
|
||||||
Tags:'pre-processing,ffmpeg,'
|
Tags: 'pre-processing,ffmpeg,'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -22,6 +22,7 @@ function plugin(file) {
|
||||||
infoLog: '',
|
infoLog: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up required variables.
|
||||||
var ffmpegCommandInsert = ''
|
var ffmpegCommandInsert = ''
|
||||||
var videoIdx = 0
|
var videoIdx = 0
|
||||||
var audioIdx = 0
|
var audioIdx = 0
|
||||||
|
|
@ -31,96 +32,127 @@ function plugin(file) {
|
||||||
var subtitleIdx = 0
|
var subtitleIdx = 0
|
||||||
var convert = false
|
var convert = false
|
||||||
|
|
||||||
|
// Go through each stream in the file.
|
||||||
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
||||||
try {
|
try {
|
||||||
|
// Check if stream is video.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
|
||||||
|
// Check if audioIdx or subtitleIdx do NOT equal 0, if they do then it means a audio or subtitle track has already appeared before the video track so file needs to be organized.
|
||||||
if (audioIdx != "0" || subtitleIdx != "0") {
|
if (audioIdx != "0" || subtitleIdx != "0") {
|
||||||
convert = true
|
convert = true
|
||||||
response.infoLog += "☒ Video not first. \n"
|
response.infoLog += "☒ Video not first. \n"
|
||||||
}
|
}
|
||||||
|
// Increment videoIdx.
|
||||||
videoIdx++
|
videoIdx++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if stream is audio.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio") {
|
||||||
|
// Check if subtitleIdx does NOT equal 0, if it does then it means a subtitle track has already appeared before an audio track so file needs to be organized.
|
||||||
if (subtitleIdx != "0") {
|
if (subtitleIdx != "0") {
|
||||||
convert = true
|
convert = true
|
||||||
response.infoLog += "☒ Audio not second. \n"
|
response.infoLog += "☒ Audio not second. \n"
|
||||||
}
|
}
|
||||||
|
// Increment audioIdx.
|
||||||
audioIdx++
|
audioIdx++
|
||||||
|
|
||||||
|
// Check if audio track is 2 channel.
|
||||||
if (file.ffProbeData.streams[i].channels == "2") {
|
if (file.ffProbeData.streams[i].channels == "2") {
|
||||||
|
// Check if audio6Idx or audio8Idx do NOT equal 0, if they do then it means a 6 channel or 8 channel audio track has already appeared before the 2 channel audio track so file needs to be organized.
|
||||||
if (audio6Idx != "0" || audio8Idx != "0") {
|
if (audio6Idx != "0" || audio8Idx != "0") {
|
||||||
convert = true
|
convert = true
|
||||||
response.infoLog += "☒ Audio 2ch not first. \n"
|
response.infoLog += "☒ Audio 2ch not first. \n"
|
||||||
}
|
}
|
||||||
|
// Increment audio2Idx.
|
||||||
audio2Idx++
|
audio2Idx++
|
||||||
}
|
}
|
||||||
|
// Check if audio track is 6 channel.
|
||||||
if (file.ffProbeData.streams[i].channels == "6") {
|
if (file.ffProbeData.streams[i].channels == "6") {
|
||||||
|
// Check if audio8Idx does NOT equal 0, if it does then it means a 8 channel audio track has already appeared before the 6 channel audio track so file needs to be organized.
|
||||||
if (audio8Idx != "0") {
|
if (audio8Idx != "0") {
|
||||||
convert = true
|
convert = true
|
||||||
response.infoLog += "☒ Audio 6ch not second. \n"
|
response.infoLog += "☒ Audio 6ch not second. \n"
|
||||||
}
|
}
|
||||||
|
// Increment audio6Idx.
|
||||||
audio6Idx++
|
audio6Idx++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if audio track is 8 channel.
|
||||||
if (file.ffProbeData.streams[i].channels == "8") {
|
if (file.ffProbeData.streams[i].channels == "8") {
|
||||||
|
// Increment audio8Idx.
|
||||||
audio8Idx++
|
audio8Idx++
|
||||||
response.infoLog += "☒ Audio 8ch not last. \n"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if stream is subtitle.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") {
|
||||||
|
// Increment subtitleIdx
|
||||||
subtitleIdx++
|
subtitleIdx++
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
} catch (err) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Go through each stream in the file.
|
||||||
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
||||||
try {
|
try {
|
||||||
|
// Check if stream is video AND is not a mjpeg.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video" && file.ffProbeData.streams[i].codec_name.toLowerCase() != "mjpeg") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video" && file.ffProbeData.streams[i].codec_name.toLowerCase() != "mjpeg") {
|
||||||
ffmpegCommandInsert += `-map 0:${i} `
|
ffmpegCommandInsert += `-map 0:${i} `
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
} catch (err) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Go through each stream in the file.
|
||||||
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
||||||
try {
|
try {
|
||||||
|
// Check if stream is audio AND 2 channel.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].channels == "2") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].channels == "2") {
|
||||||
ffmpegCommandInsert += `-map 0:${i} `
|
ffmpegCommandInsert += `-map 0:${i} `
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
} catch (err) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Go through each stream in the file.
|
||||||
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
||||||
try {
|
try {
|
||||||
|
// Check if stream is audio AND 6 channel.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].channels == "6") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].channels == "6") {
|
||||||
ffmpegCommandInsert += `-map 0:${i} `
|
ffmpegCommandInsert += `-map 0:${i} `
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
} catch (err) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Go through each stream in the file.
|
||||||
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
||||||
try {
|
try {
|
||||||
|
// Check if stream is audio AND 8 channel.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].channels == "8") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].channels == "8") {
|
||||||
ffmpegCommandInsert += `-map 0:${i} `
|
ffmpegCommandInsert += `-map 0:${i} `
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
} catch (err) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Go through each stream in the file.
|
||||||
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
||||||
try {
|
try {
|
||||||
|
// Check if stream is audio AND not 2, 6 or 8 channel.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].channels != "2" && file.ffProbeData.streams[i].channels != "6" && file.ffProbeData.streams[i].channels != "8") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "audio" && file.ffProbeData.streams[i].channels != "2" && file.ffProbeData.streams[i].channels != "6" && file.ffProbeData.streams[i].channels != "8") {
|
||||||
ffmpegCommandInsert += `-map 0:${i} `
|
ffmpegCommandInsert += `-map 0:${i} `
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
} catch (err) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Go through each stream in the file.
|
||||||
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
||||||
try {
|
try {
|
||||||
|
// Check if stream is subtitle.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "subtitle") {
|
||||||
ffmpegCommandInsert += `-map 0:${i} `
|
ffmpegCommandInsert += `-map 0:${i} `
|
||||||
}
|
}
|
||||||
} catch (err) { }
|
} catch (err) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert file if convert variable is set to true.
|
||||||
if (convert == true) {
|
if (convert == true) {
|
||||||
response.processFile = true;
|
response.processFile = true;
|
||||||
response.preset = `,${ffmpegCommandInsert} -c copy -max_muxing_queue_size 4096`
|
response.preset = `,${ffmpegCommandInsert} -c copy -max_muxing_queue_size 4096`
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ function details() {
|
||||||
Stage: "Pre-processing",
|
Stage: "Pre-processing",
|
||||||
Name: "Migz-Remove image formats from file",
|
Name: "Migz-Remove image formats from file",
|
||||||
Type: "Video",
|
Type: "Video",
|
||||||
Operation:"Clean",
|
Operation: "Clean",
|
||||||
Description: `Identify any unwanted image formats in the file and remove those streams. MJPEG & PNG \n\n`,
|
Description: `Identify any unwanted image formats in the file and remove those streams. MJPEG & PNG \n\n`,
|
||||||
Version: "1.0",
|
Version: "1.1",
|
||||||
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_MigzImageRemoval.js",
|
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_MigzImageRemoval.js",
|
||||||
Tags:'pre-processing,ffmpeg,video only'
|
Tags: 'pre-processing,ffmpeg,video only'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,27 +23,34 @@ function plugin(file, librarySettings, inputs) {
|
||||||
infoLog: ''
|
infoLog: ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if file is a video. If it isn't then exit plugin.
|
||||||
if (file.fileMedium !== "video") {
|
if (file.fileMedium !== "video") {
|
||||||
response.processFile = false
|
response.processFile = false
|
||||||
response.infoLog += "☒File is not a video. \n"
|
response.infoLog += "☒File is not a video. \n"
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up required variables.
|
||||||
var videoIdx = 0
|
var videoIdx = 0
|
||||||
var extraArguments = ""
|
var extraArguments = ""
|
||||||
var convert = false
|
var convert = false
|
||||||
|
|
||||||
|
// Go through each stream in the file.
|
||||||
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
for (var i = 0; i < file.ffProbeData.streams.length; i++) {
|
||||||
|
// Check if stream is video.
|
||||||
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
|
if (file.ffProbeData.streams[i].codec_type.toLowerCase() == "video") {
|
||||||
|
// Check if stream codec is mjpeg or png. Remove if so.
|
||||||
if (file.ffProbeData.streams[i].codec_name == 'mjpeg' || file.ffProbeData.streams[i].codec_name == 'png') {
|
if (file.ffProbeData.streams[i].codec_name == 'mjpeg' || file.ffProbeData.streams[i].codec_name == 'png') {
|
||||||
convert = true
|
convert = true
|
||||||
extraArguments += `-map -v:${videoIdx} `
|
extraArguments += `-map -v:${videoIdx} `
|
||||||
}
|
}
|
||||||
|
// Increment videoIdx.
|
||||||
videoIdx++
|
videoIdx++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (convert === true ) {
|
// Convert file if convert variable is set to true.
|
||||||
|
if (convert === true) {
|
||||||
response.preset += `,-map 0 -c copy -max_muxing_queue_size 4096 ${extraArguments}`
|
response.preset += `,-map 0 -c copy -max_muxing_queue_size 4096 ${extraArguments}`
|
||||||
response.infoLog += `☒File has image format stream, removing. \n`
|
response.infoLog += `☒File has image format stream, removing. \n`
|
||||||
response.processFile = true;
|
response.processFile = true;
|
||||||
|
|
@ -53,8 +60,5 @@ function plugin(file, librarySettings, inputs) {
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports.details = details;
|
module.exports.details = details;
|
||||||
module.exports.plugin = plugin;
|
module.exports.plugin = plugin;
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
module.exports.details = function details() {
|
module.exports.details = function details() {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: "Tdarr_Plugin_MC93_MigzPlex_Autoscan",
|
id: "Tdarr_Plugin_MC93_MigzPlex_Autoscan",
|
||||||
Stage: "Post-processing",
|
Stage: "Post-processing",
|
||||||
|
|
@ -7,12 +6,11 @@ module.exports.details = function details() {
|
||||||
Type: "Video",
|
Type: "Video",
|
||||||
Operation: "",
|
Operation: "",
|
||||||
Description: `Send request for file to be scanned by plex_autoscan. https://github.com/l3uddz/plex_autoscan \n\n`,
|
Description: `Send request for file to be scanned by plex_autoscan. https://github.com/l3uddz/plex_autoscan \n\n`,
|
||||||
Version: "1.00",
|
Version: "1.1",
|
||||||
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_MigzPlex_Autoscan.js",
|
Link: "https://github.com/HaveAGitGat/Tdarr_Plugins/blob/master/Community/Tdarr_Plugin_MC93_MigzPlex_Autoscan.js",
|
||||||
Tags:"3rd party,post-processing,configurable",
|
Tags: "3rd party,post-processing,configurable",
|
||||||
|
|
||||||
Inputs: [
|
Inputs: [{
|
||||||
{
|
|
||||||
name: 'autoscan_address',
|
name: 'autoscan_address',
|
||||||
tooltip: `
|
tooltip: `
|
||||||
Enter the IP address/URL for autoscan. Must include http(s)://
|
Enter the IP address/URL for autoscan. Must include http(s)://
|
||||||
|
|
@ -21,8 +19,7 @@ module.exports.details = function details() {
|
||||||
http://192.168.0.10
|
http://192.168.0.10
|
||||||
|
|
||||||
\\nExample:\\n
|
\\nExample:\\n
|
||||||
https://subdomain.domain.tld
|
https://subdomain.domain.tld`
|
||||||
`
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'autoscan_port',
|
name: 'autoscan_port',
|
||||||
|
|
@ -30,8 +27,7 @@ module.exports.details = function details() {
|
||||||
Enter the port Autoscan is using, default is 3468
|
Enter the port Autoscan is using, default is 3468
|
||||||
|
|
||||||
\\nExample:\\n
|
\\nExample:\\n
|
||||||
3468
|
3468`
|
||||||
`
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'autoscan_passkey',
|
name: 'autoscan_passkey',
|
||||||
|
|
@ -40,8 +36,7 @@ module.exports.details = function details() {
|
||||||
Enter the autoscan passkey.
|
Enter the autoscan passkey.
|
||||||
|
|
||||||
\\nExample:\\n
|
\\nExample:\\n
|
||||||
9c4b81fe234e4d6eb9011cefe514d915
|
9c4b81fe234e4d6eb9011cefe514d915`
|
||||||
`
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -49,19 +44,33 @@ module.exports.details = function details() {
|
||||||
|
|
||||||
module.exports.plugin = function plugin(file, librarySettings, inputs) {
|
module.exports.plugin = function plugin(file, librarySettings, inputs) {
|
||||||
|
|
||||||
|
// Check if all inputs have been configured. If they haven't then exit plugin.
|
||||||
|
if (inputs && inputs.autoscan_address == "" && inputs.autoscan_port == "" && inputs.autoscan_passkey == "") {
|
||||||
|
response.infoLog += "☒Autoscan options have not been configured, please configure all options. Skipping this plugin. \n"
|
||||||
|
response.processFile = false;
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take variable inputs and turn them into read only variable
|
||||||
const request = require('request')
|
const request = require('request')
|
||||||
const ADDRESS = inputs.autoscan_address
|
const ADDRESS = inputs.autoscan_address
|
||||||
const PORT = inputs.autoscan_port
|
const PORT = inputs.autoscan_port
|
||||||
const PASSKEY = inputs.autoscan_passkey
|
const PASSKEY = inputs.autoscan_passkey
|
||||||
|
|
||||||
|
// Set up required variables.
|
||||||
var response = ""
|
var response = ""
|
||||||
filepath = `${file.file}`
|
filepath = `${file.file}`
|
||||||
|
|
||||||
|
// Set content of request/post.
|
||||||
request.post({
|
request.post({
|
||||||
headers: {'content-type': 'application/json'},
|
headers: {
|
||||||
|
'content-type': 'application/json'
|
||||||
|
},
|
||||||
url: `${ADDRESS}:${PORT}/${PASSKEY}`,
|
url: `${ADDRESS}:${PORT}/${PASSKEY}`,
|
||||||
form: { "eventType" : "Manual", "filepath" : `${filepath}` }
|
form: {
|
||||||
|
"eventType": "Manual",
|
||||||
|
"filepath": `${filepath}`
|
||||||
|
}
|
||||||
}, (error, res, body) => {
|
}, (error, res, body) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
|
|
@ -72,6 +81,4 @@ module.exports.plugin = function plugin(file, librarySettings, inputs) {
|
||||||
|
|
||||||
console.log("request next")
|
console.log("request next")
|
||||||
console.log(request.post)
|
console.log(request.post)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue