From c33e8010b38fb62bec41217c8d695dda8c677ca2 Mon Sep 17 00:00:00 2001 From: Isaac Abadi Date: Tue, 3 May 2022 00:34:36 -0400 Subject: [PATCH] Additional args now replace existing ones intelligently --- backend/consts.js | 79 +++++++++++++++++++++++++++++++++++++++++++ backend/downloader.js | 2 +- backend/test/tests.js | 7 ++++ backend/utils.js | 33 ++++++++++++++++++ 4 files changed, 120 insertions(+), 1 deletion(-) diff --git a/backend/consts.js b/backend/consts.js index 849fa4c..9bd2905 100644 --- a/backend/consts.js +++ b/backend/consts.js @@ -222,4 +222,83 @@ exports.AVAILABLE_PERMISSIONS = [ exports.DETAILS_BIN_PATH = 'node_modules/youtube-dl/bin/details' +// args that have a value after it (e.g. -o or -f ) +const YTDL_ARGS_WITH_VALUES = [ + '--default-search', + '--config-location', + '--proxy', + '--socket-timeout', + '--source-address', + '--geo-verification-proxy', + '--geo-bypass-country', + '--geo-bypass-ip-block', + '--playlist-start', + '--playlist-end', + '--playlist-items', + '--match-title', + '--reject-title', + '--max-downloads', + '--min-filesize', + '--max-filesize', + '--date', + '--datebefore', + '--dateafter', + '--min-views', + '--max-views', + '--match-filter', + '--age-limit', + '--download-archive', + '-r', + '--limit-rate', + '-R', + '--retries', + '--fragment-retries', + '--buffer-size', + '--http-chunk-size', + '--external-downloader', + '--external-downloader-args', + '-a', + '--batch-file', + '-o', + '--output', + '--output-na-placeholder', + '--autonumber-start', + '--load-info-json', + '--cookies', + '--cache-dir', + '--encoding', + '--user-agent', + '--referer', + '--add-header', + '--sleep-interval', + '--max-sleep-interval', + '-f', + '--format', + '--merge-output-format', + '--sub-format', + '--sub-lang', + '-u', + '--username', + '-p', + '--password', + '-2', + '--twofactor', + '--video-password', + '--ap-mso', + '--ap-username', + '--ap-password', + '--audio-format', + '--audio-quality', + '--recode-video', + '--postprocessor-args', + '--metadata-from-title', + '--fixup', + '--ffmpeg-location', + '--exec', + '--convert-subs' +]; + +// we're using a Set here for performance +exports.YTDL_ARGS_WITH_VALUES = new Set(YTDL_ARGS_WITH_VALUES); + exports.CURRENT_VERSION = 'v4.2'; diff --git a/backend/downloader.js b/backend/downloader.js index 108501b..99ed686 100644 --- a/backend/downloader.js +++ b/backend/downloader.js @@ -485,7 +485,7 @@ exports.generateArgs = async (url, type, options, user_uid = null, simulated = f } if (options.additionalArgs && options.additionalArgs !== '') { - downloadConfig = downloadConfig.concat(options.additionalArgs.split(',,')); + downloadConfig = utils.injectArgs(downloadConfig, options.additionalArgs.split(',,')); } const rate_limit = config_api.getConfigItem('ytdl_download_rate_limit'); diff --git a/backend/test/tests.js b/backend/test/tests.js index 9ae95a8..ec18dd5 100644 --- a/backend/test/tests.js +++ b/backend/test/tests.js @@ -386,6 +386,13 @@ describe('Downloader', function() { assert(fs.existsSync(nfo_file_path), true); fs.unlinkSync(nfo_file_path); }); + + it('Inject args', async function() { + const original_args = ['--no-resize-buffer', '-o', '%(title)s', '--no-mtime']; + const new_args = ['--age-limit', '25', '--yes-playlist', '--abort-on-error', '-o', '%(id)s']; + const updated_args = utils.injectArgs(original_args, new_args); + assert(updated_args, ['--no-resize-buffer', '--no-mtime', '--age-limit', '25', '--yes-playlist', '--abort-on-error', '-o', '%(id)s']); + }); }); describe('Tasks', function() { diff --git a/backend/utils.js b/backend/utils.js index a6eaf7e..b456659 100644 --- a/backend/utils.js +++ b/backend/utils.js @@ -415,6 +415,38 @@ async function fetchFile(url, path, file_label) { }); } +// adds or replaces args according to the following rules: +// - if it already exists and has value, then replace both arg and value +// - if already exists and doesn't have value, ignore +// - if it doesn't exist and has value, add both arg and value +// - if it doesn't exist and doesn't have value, add arg +function injectArgs(original_args, new_args) { + try { + for (let i = 0; i < new_args.length; i++) { + const new_arg = new_args[i]; + if (!new_arg.startsWith('-') && !new_arg.startsWith('--')) continue; + + if (CONSTS.YTDL_ARGS_WITH_VALUES.has(new_arg)) { + if (original_args.includes(new_arg)) { + const original_index = original_args.indexOf(new_arg); + original_args.splice(original_index, 2); + } + + original_args.push(new_arg, new_args[i + 1]); + } else { + if (!original_args.includes(new_arg)) { + original_args.push(new_arg); + } + } + } + } catch (err) { + logger.warn(err); + logger.warn(`Failed to inject args (${new_args}) into (${original_args})`); + } + + return original_args; +} + // objects function File(id, title, thumbnailURL, isAudio, duration, url, uploader, size, path, upload_date, description, view_count, height, abr) { @@ -458,5 +490,6 @@ module.exports = { wait: wait, checkExistsWithTimeout: checkExistsWithTimeout, fetchFile: fetchFile, + injectArgs: injectArgs, File: File }