From 91b12d5b8360ccdcef4ac8e372529f9502d90c9e Mon Sep 17 00:00:00 2001 From: HaveAGitGat <43864057+HaveAGitGat@users.noreply.github.com> Date: Wed, 25 May 2022 08:19:25 +0100 Subject: [PATCH 1/7] Update re-ordering of mp4 files --- ...gin_00td_action_re_order_all_streams_v2.js | 6 ++ ...gin_00td_action_re_order_all_streams_v2.js | 92 ++++++++++++++++++- 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js b/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js index 4f162b2..9639b9a 100644 --- a/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js +++ b/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js @@ -102,6 +102,12 @@ const plugin = (file, librarySettings, inputs, otherArguments) => { + 'This may be due to a corrupt file or permissions issue when scanning the file.'); } + if (file.container === 'mp4' && file.ffProbeData.streams[0].codec_type === 'video') { + response.infoLog += 'File is mp4 and already has the video stream in the correct order!' + + ' Due to FFmpeg issues when reordering streams in mp4 files, other stream ordering will be skipped'; + return response; + } + let { streams } = JSON.parse(JSON.stringify(file.ffProbeData)); streams.forEach((stream, index) => { diff --git a/tests/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js b/tests/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js index 2567bac..8b7fa50 100644 --- a/tests/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js +++ b/tests/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js @@ -1,10 +1,11 @@ /* eslint max-len: 0 */ +const _ = require('lodash'); const run = require('../helpers/run'); const tests = [ { input: { - file: require('../sampleData/media/sampleH264_1.json'), + file: _.cloneDeep(require('../sampleData/media/sampleH264_1.json')), librarySettings: {}, inputs: {}, otherArguments: {}, @@ -15,7 +16,7 @@ const tests = [ container: '.mp4', handBrakeMode: false, FFmpegMode: true, - infoLog: 'Streams are in the correct order!', + infoLog: 'File is mp4 and already has the video stream in the correct order! Due to FFmpeg issues when reordering streams in mp4 files, other stream ordering will be skipped', }, }, { @@ -47,7 +48,7 @@ const tests = [ // })) input: { - file: require('../sampleData/media/sampleH264_2.json'), + file: _.cloneDeep(require('../sampleData/media/sampleH264_2.json')), librarySettings: {}, inputs: { processOrder: 'codecs,channels,languages,streamTypes', @@ -67,6 +68,91 @@ const tests = [ infoLog: 'Streams are not in the correct order!', }, }, + { + input: { + file: (() => { + const file = _.cloneDeep(require('../sampleData/media/sampleH264_2.json')); + const s4 = file.ffProbeData.streams[4]; + file.ffProbeData.streams[4] = file.ffProbeData.streams[4]; + file.ffProbeData.streams[5] = s4; + return file; + })(), + librarySettings: {}, + inputs: { + processOrder: 'codecs,channels,languages,streamTypes', + languages: 'eng,fre', + streamTypes: 'video,audio,subtitle', + codecs: 'flac,ac3,eac3,aac', + channels: '7.1,5.1,2,1', + }, + otherArguments: {}, + }, + output: { + processFile: false, + preset: '', + container: '.mkv', + handBrakeMode: false, + FFmpegMode: true, + infoLog: 'Streams are in the correct order!', + }, + }, + + { + input: { + file: (() => { + const file = _.cloneDeep(require('../sampleData/media/sampleH264_2.json')); + file.container = 'mp4'; + return file; + })(), + librarySettings: {}, + inputs: { + processOrder: 'codecs,channels,languages,streamTypes', + languages: 'fre,eng', + streamTypes: 'video,audio,subtitle', + codecs: 'ac3,flac,eac3,aac', + channels: '7.1,5.1,2,1', + }, + otherArguments: {}, + }, + output: { + processFile: false, + preset: '', + container: '.mp4', + handBrakeMode: false, + FFmpegMode: true, + infoLog: 'File is mp4 and already has the video stream in the correct order! Due to FFmpeg issues when reordering streams in mp4 files, other stream ordering will be skipped', + }, + }, + { + input: { + file: (() => { + const file = _.cloneDeep(require('../sampleData/media/sampleH264_2.json')); + const s0 = file.ffProbeData.streams[0]; + // eslint-disable-next-line prefer-destructuring + file.ffProbeData.streams[0] = file.ffProbeData.streams[1]; + file.ffProbeData.streams[1] = s0; + file.container = 'mp4'; + return file; + })(), + librarySettings: {}, + inputs: { + processOrder: 'codecs,channels,languages,streamTypes', + languages: 'fre,eng', + streamTypes: 'video,audio,subtitle', + codecs: 'ac3,flac,eac3,aac', + channels: '7.1,5.1,2,1', + }, + otherArguments: {}, + }, + output: { + processFile: true, + preset: ' -c copy -map 0:1 -map 0:4 -map 0:2 -map 0:0 -map 0:3 -map 0:5 -map 0:6', + container: '.mp4', + handBrakeMode: false, + FFmpegMode: true, + infoLog: 'Streams are not in the correct order!', + }, + }, ]; run(tests); From aa840354ff903d247d54521c5e54e8e89523dfe5 Mon Sep 17 00:00:00 2001 From: HaveAGitGat <43864057+HaveAGitGat@users.noreply.github.com> Date: Wed, 25 May 2022 08:47:36 +0100 Subject: [PATCH 2/7] Fix bug when video is not first --- ...darr_Plugin_076a_re_order_audio_streams.js | 4 +- ...darr_Plugin_076a_re_order_audio_streams.js | 53 +++++++++++++++++-- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/Community/Tdarr_Plugin_076a_re_order_audio_streams.js b/Community/Tdarr_Plugin_076a_re_order_audio_streams.js index 77835ca..8b3ecc7 100644 --- a/Community/Tdarr_Plugin_076a_re_order_audio_streams.js +++ b/Community/Tdarr_Plugin_076a_re_order_audio_streams.js @@ -100,9 +100,7 @@ const plugin = (file, librarySettings, inputs, otherArguments) => { var ffmpegCommand = ", -c copy"; - if (file.ffProbeData.streams[0].codec_type.toLowerCase() == "video") { - ffmpegCommand += ` -map 0:v `; - } + ffmpegCommand += ` -map 0:v? `; var allAudioTracks = file.ffProbeData.streams.filter( (stream) => stream.codec_type.toLowerCase() == "audio" diff --git a/tests/Community/Tdarr_Plugin_076a_re_order_audio_streams.js b/tests/Community/Tdarr_Plugin_076a_re_order_audio_streams.js index 95a1b47..2f226dc 100644 --- a/tests/Community/Tdarr_Plugin_076a_re_order_audio_streams.js +++ b/tests/Community/Tdarr_Plugin_076a_re_order_audio_streams.js @@ -1,10 +1,11 @@ /* eslint max-len: 0 */ +const _ = require('lodash'); const run = require('../helpers/run'); const tests = [ { input: { - file: require('../sampleData/media/sampleH264_2.json'), + file: _.cloneDeep(require('../sampleData/media/sampleH264_2.json')), librarySettings: {}, inputs: {}, otherArguments: {}, @@ -21,7 +22,7 @@ const tests = [ }, { input: { - file: require('../sampleData/media/sampleH264_2.json'), + file: _.cloneDeep(require('../sampleData/media/sampleH264_2.json')), librarySettings: {}, inputs: { preferred_language: 'fre', @@ -30,7 +31,53 @@ const tests = [ }, output: { processFile: true, - preset: ', -c copy -map 0:v -map 0:a:3 -disposition:a:0 default -map 0:a:0 -map 0:a:1 -disposition:a:1 0 -map 0:a:2 -disposition:a:2 0 -disposition:a:3 0 -map 0:a:4 -disposition:a:4 0 -map 0:s? -map 0:d? ', + preset: ', -c copy -map 0:v? -map 0:a:3 -disposition:a:0 default -map 0:a:0 -map 0:a:1 -disposition:a:1 0 -map 0:a:2 -disposition:a:2 0 -disposition:a:3 0 -map 0:a:4 -disposition:a:4 0 -map 0:s? -map 0:d? ', + container: '.mkv', + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: true, + infoLog: '☒ Desired audio lang is not first audio stream, moving! \n', + }, + }, + { + input: { + file: (() => { + const file = _.cloneDeep(require('../sampleData/media/sampleH264_2.json')); + file.ffProbeData.streams[0].codec_type = 'audio'; + return file; + })(), + librarySettings: {}, + inputs: { + preferred_language: 'fre', + }, + otherArguments: {}, + }, + output: { + processFile: false, + preset: '', + container: '.mp4', + handBrakeMode: false, + FFmpegMode: false, + reQueueAfter: false, + infoLog: '☑ Preferred language is already first audio track! \n', + }, + }, + { + input: { + file: (() => { + const file = _.cloneDeep(require('../sampleData/media/sampleH264_2.json')); + file.ffProbeData.streams[0].codec_type = 'audio'; + return file; + })(), + librarySettings: {}, + inputs: { + preferred_language: 'eng', + }, + otherArguments: {}, + }, + output: { + processFile: true, + preset: ', -c copy -map 0:v? -map 0:a:1 -disposition:a:0 default -map 0:a:0 -disposition:a:1 0 -map 0:a:2 -disposition:a:2 0 -map 0:a:3 -disposition:a:3 0 -map 0:a:4 -disposition:a:4 0 -map 0:a:5 -disposition:a:5 0 -map 0:s? -map 0:d? ', container: '.mkv', handBrakeMode: false, FFmpegMode: true, From 384f652466f1f13557adf8c0a2ccb381b30874a4 Mon Sep 17 00:00:00 2001 From: HaveAGitGat <43864057+HaveAGitGat@users.noreply.github.com> Date: Wed, 25 May 2022 08:49:29 +0100 Subject: [PATCH 3/7] Fix lint --- .../Tdarr_Plugin_00td_action_re_order_all_streams_v2.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js b/tests/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js index 8b7fa50..9dd2de4 100644 --- a/tests/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js +++ b/tests/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js @@ -73,7 +73,9 @@ const tests = [ file: (() => { const file = _.cloneDeep(require('../sampleData/media/sampleH264_2.json')); const s4 = file.ffProbeData.streams[4]; - file.ffProbeData.streams[4] = file.ffProbeData.streams[4]; + + // eslint-disable-next-line prefer-destructuring + file.ffProbeData.streams[4] = file.ffProbeData.streams[5]; file.ffProbeData.streams[5] = s4; return file; })(), From 03329da35b7778c296cf591cf1e6c7b813da649a Mon Sep 17 00:00:00 2001 From: HaveAGitGat <43864057+HaveAGitGat@users.noreply.github.com> Date: Wed, 25 May 2022 08:56:59 +0100 Subject: [PATCH 4/7] If mp4, only set video stream first, skip other stream ordering --- ...arr_Plugin_00td_action_re_order_all_streams_v2.js | 12 +++++++++--- ...arr_Plugin_00td_action_re_order_all_streams_v2.js | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js b/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js index 9639b9a..21881b2 100644 --- a/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js +++ b/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js @@ -102,9 +102,15 @@ const plugin = (file, librarySettings, inputs, otherArguments) => { + 'This may be due to a corrupt file or permissions issue when scanning the file.'); } - if (file.container === 'mp4' && file.ffProbeData.streams[0].codec_type === 'video') { - response.infoLog += 'File is mp4 and already has the video stream in the correct order!' - + ' Due to FFmpeg issues when reordering streams in mp4 files, other stream ordering will be skipped'; + if (file.container === 'mp4' && file.fileMedium === 'video') { + if (file.ffProbeData.streams[0].codec_type === 'video') { + response.infoLog += 'File is mp4 and already has the video stream in the correct order!' + + ' Due to FFmpeg issues when reordering streams in mp4 files, other stream ordering will be skipped'; + return response; + } + response.processFile = true; + response.infoLog += 'File is mp4 and contains video but video is not first stream, remuxing'; + response.preset = ',-map 0:v? -map 0:a? -map 0:s? -map 0:d? -map 0:t? -c copy'; return response; } diff --git a/tests/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js b/tests/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js index 9dd2de4..96ca95f 100644 --- a/tests/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js +++ b/tests/Community/Tdarr_Plugin_00td_action_re_order_all_streams_v2.js @@ -148,11 +148,11 @@ const tests = [ }, output: { processFile: true, - preset: ' -c copy -map 0:1 -map 0:4 -map 0:2 -map 0:0 -map 0:3 -map 0:5 -map 0:6', + preset: ',-map 0:v? -map 0:a? -map 0:s? -map 0:d? -map 0:t? -c copy', container: '.mp4', handBrakeMode: false, FFmpegMode: true, - infoLog: 'Streams are not in the correct order!', + infoLog: 'File is mp4 and contains video but video is not first stream, remuxing', }, }, ]; From 4190809dd02607e251d2386cba224718db795b3c Mon Sep 17 00:00:00 2001 From: HaveAGitGat <43864057+HaveAGitGat@users.noreply.github.com> Date: Fri, 27 May 2022 07:08:19 +0100 Subject: [PATCH 5/7] Add Tdarr_Plugin_00td_action_remove_audio_by_channel_count --- ...td_action_remove_audio_by_channel_count.js | 93 +++++++++++++++ ...td_action_remove_audio_by_channel_count.js | 106 ++++++++++++++++++ 2 files changed, 199 insertions(+) create mode 100644 Community/Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js create mode 100644 tests/Community/Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js diff --git a/Community/Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js b/Community/Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js new file mode 100644 index 0000000..5067742 --- /dev/null +++ b/Community/Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js @@ -0,0 +1,93 @@ +const details = () => ({ + id: 'Tdarr_Plugin_00td_action_remove_audio_by_channel_count', + Stage: 'Pre-processing', + Name: 'Remove audio streams by channel count', + Type: 'Video', + Operation: 'Transcode', + Description: ` + This plugin removes audio streams based on channel count. The output container is the same as the original. + `, + Version: '1.00', + Tags: 'action', + Inputs: [ + { + name: 'channelCounts', + type: 'string', + defaultValue: '', + inputUI: { + type: 'text', + }, + tooltip: + 'Enter the the channel counts to remove', + }, + ], +}); + +// eslint-disable-next-line no-unused-vars +const plugin = (file, librarySettings, inputs, otherArguments) => { + const lib = require('../methods/lib')(); + // eslint-disable-next-line no-unused-vars,no-param-reassign + inputs = lib.loadDefaultValues(inputs, details); + const response = { + processFile: false, + preset: '', + container: `.${file.container}`, + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: false, + infoLog: '', + }; + + if (inputs.channelCounts.trim() === '') { + response.infoLog += 'No input entered in plugin, skipping'; + return response; + } + + const audioStreams = file.ffProbeData.streams.filter((row) => row.codec_type === 'audio'); + + if (audioStreams.length === 0) { + response.infoLog += 'File has no audio streams, skipping plugin'; + return response; + } + + if (audioStreams.length === 1) { + response.infoLog += 'File only has 1 audio stream, skipping plugin'; + return response; + } + + response.preset += ', -map 0 -c copy -max_muxing_queue_size 9999'; + + const audioToRemove = []; + const channelCounts = inputs.channelCounts.trim().split(','); + + for (let i = 0; i < channelCounts.length; i += 1) { + const channelCount = parseInt(channelCounts[i], 10); + for (let j = 0; j < audioStreams.length; j += 1) { + if (channelCount === audioStreams[j].channels) { + audioToRemove.push(audioStreams[j]); + } + } + } + + if (audioToRemove.length === 0) { + response.infoLog += 'No audio streams to remove!'; + return response; + } + + if (audioToRemove.length === audioStreams.length) { + response.infoLog += 'The number of audio streams to remove equals ' + + 'the total number of audio streams, skipping plugin'; + return response; + } + + audioToRemove.forEach((row) => { + response.preset += ` -map -0:${row.index} `; + response.infoLog += ` Removing stream ${row.index} which has ${row.channels} channels.`; + }); + + response.processFile = true; + return response; +}; + +module.exports.details = details; +module.exports.plugin = plugin; diff --git a/tests/Community/Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js b/tests/Community/Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js new file mode 100644 index 0000000..d304813 --- /dev/null +++ b/tests/Community/Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js @@ -0,0 +1,106 @@ +/* eslint max-len: 0 */ +const _ = require('lodash'); +const run = require('../helpers/run'); + +const tests = [ + { + input: { + file: _.cloneDeep(require('../sampleData/media/sampleH264_1.json')), + librarySettings: {}, + inputs: {}, + otherArguments: {}, + }, + output: { + processFile: false, + preset: '', + container: '.mp4', + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: false, + infoLog: 'No input entered in plugin, skipping', + }, + }, + { + input: { + file: _.cloneDeep(require('../sampleData/media/sampleH264_1.json')), + librarySettings: {}, + inputs: { + channelCounts: '8', + }, + otherArguments: {}, + }, + output: { + processFile: false, + preset: '', + container: '.mp4', + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: false, + infoLog: 'File only has 1 audio stream, skipping plugin', + }, + }, + { + input: { + file: _.cloneDeep(require('../sampleData/media/sampleH264_2.json')), + librarySettings: {}, + inputs: { + channelCounts: '8', + }, + otherArguments: {}, + }, + output: { + processFile: false, + preset: ', -map 0 -c copy -max_muxing_queue_size 9999', + container: '.mkv', + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: false, + infoLog: 'No audio streams to remove!', + }, + }, + { + input: { + file: _.cloneDeep(require('../sampleData/media/sampleH264_2.json')), + librarySettings: {}, + inputs: { + channelCounts: '2', + }, + otherArguments: {}, + }, + output: { + processFile: false, + preset: ', -map 0 -c copy -max_muxing_queue_size 9999', + container: '.mkv', + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: false, + infoLog: 'The number of audio streams to remove equals the total number of audio streams, skipping plugin', + }, + }, + { + input: { + file: (() => { + const file = _.cloneDeep(require('../sampleData/media/sampleH264_2.json')); + file.ffProbeData.streams[1].channels = 8; + file.ffProbeData.streams[2].channels = 6; + return file; + })(), + librarySettings: {}, + inputs: { + channelCounts: '8,6', + }, + otherArguments: {}, + }, + output: { + processFile: true, + preset: ', -map 0 -c copy -max_muxing_queue_size 9999 -map -0:1 -map -0:2 ', + container: '.mkv', + handBrakeMode: false, + FFmpegMode: true, + reQueueAfter: false, + infoLog: ' Removing stream 1 which has 8 channels. Removing stream 2 which has 6 channels.', + }, + }, +]; + +run(tests); From 569ba276be981c4de56e73a24f61a31a690c6ba2 Mon Sep 17 00:00:00 2001 From: HaveAGitGat <43864057+HaveAGitGat@users.noreply.github.com> Date: Fri, 27 May 2022 07:14:39 +0100 Subject: [PATCH 6/7] Update description. --- .../Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Community/Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js b/Community/Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js index 5067742..049f37b 100644 --- a/Community/Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js +++ b/Community/Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js @@ -6,6 +6,9 @@ const details = () => ({ Operation: 'Transcode', Description: ` This plugin removes audio streams based on channel count. The output container is the same as the original. + If the file only has one audio stream, the plugin will be skipped. If the number of audio streams to remove + equals the total number of audio streams, the plugin will be skipped. This ensures there is always at least + one audio stream in the file. `, Version: '1.00', Tags: 'action', From bf50916eff65e79db02b1f33a004f1c5db950cfc Mon Sep 17 00:00:00 2001 From: HaveAGitGat <43864057+HaveAGitGat@users.noreply.github.com> Date: Sat, 28 May 2022 14:42:01 +0100 Subject: [PATCH 7/7] Add example --- ...darr_Plugin_00td_action_remove_audio_by_channel_count.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Community/Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js b/Community/Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js index 049f37b..4b286f8 100644 --- a/Community/Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js +++ b/Community/Tdarr_Plugin_00td_action_remove_audio_by_channel_count.js @@ -21,7 +21,11 @@ const details = () => ({ type: 'text', }, tooltip: - 'Enter the the channel counts to remove', + `Enter the the channel counts to remove. + + \\nExample:\\n + 8,6 + `, }, ], });