From c5924b02cc316e171e0abc46beaba5ddf9d48cb6 Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Thu, 27 Feb 2025 14:58:06 +0300 Subject: [PATCH] support format key in ytdlp.json, using the key will ignore the selected preset. --- app/library/DownloadQueue.py | 4 ++-- app/library/HttpAPI.py | 29 +++++++++++++++++++++++++++-- app/library/Utils.py | 6 +++++- ui/components/NewDownload.vue | 35 +++++++++++++++++++++++++++++------ ui/components/TaskForm.vue | 35 ++++++++++++++++++++++++++++------- ui/utils/index.js | 2 +- 6 files changed, 92 insertions(+), 19 deletions(-) diff --git a/app/library/DownloadQueue.py b/app/library/DownloadQueue.py index 10079d4e..fc718055 100644 --- a/app/library/DownloadQueue.py +++ b/app/library/DownloadQueue.py @@ -395,7 +395,7 @@ class DownloadQueue(metaclass=Singleton): "func": lambda _, msg: logs.append(msg), "level": logging.WARNING, }, - **merge_config(self.config.ytdl_options, config), + **get_opts(preset, merge_config(self.config.ytdl_options, config)), } if cookies: @@ -408,7 +408,7 @@ class DownloadQueue(metaclass=Singleton): entry = await asyncio.wait_for( fut=asyncio.get_running_loop().run_in_executor( - None, extract_info, get_opts(preset, yt_conf), url, bool(self.config.ytdl_debug) + None, extract_info, yt_conf, url, bool(self.config.ytdl_debug) ), timeout=self.config.extract_info_timeout, ) diff --git a/app/library/HttpAPI.py b/app/library/HttpAPI.py index e49453da..7369cf46 100644 --- a/app/library/HttpAPI.py +++ b/app/library/HttpAPI.py @@ -32,7 +32,15 @@ from .Playlist import Playlist from .Segments import Segments from .Subtitle import Subtitle from .Tasks import Task, Tasks -from .Utils import StreamingError, arg_converter, calc_download_path, get_video_info, validate_url, validate_uuid +from .Utils import ( + IGNORED_KEYS, + StreamingError, + arg_converter, + calc_download_path, + get_video_info, + validate_url, + validate_uuid, +) LOG = logging.getLogger("http_api") MIME = magic.Magic(mime=True) @@ -347,11 +355,28 @@ class HttpAPI(Common): return web.json_response(data={"error": "args param is required."}, status=web.HTTPBadRequest.status_code) try: - return web.json_response(data=arg_converter(args), status=web.HTTPOk.status_code) + response = {"opts": {}, "output_template": None, "download_path": None} + + data = arg_converter(args) + + if "outtmpl" in data and "default" in data["outtmpl"]: + response["output_template"] = data["outtmpl"]["default"] + + if "paths" in data and "home" in data["paths"]: + response["download_path"] = data["paths"]["home"] + + for key in data: + if key in IGNORED_KEYS: + continue + if not key.startswith("_"): + response["opts"][key] = data[key] + + return web.json_response(data=response, status=web.HTTPOk.status_code) except Exception as e: err = str(e).strip() err = err.split("\n")[-1] if "\n" in err else err LOG.error(f"Failed to convert args. '{err}'.") + LOG.exception(e) return web.json_response( data={"error": f"Failed to convert args. '{err}'."}, status=web.HTTPBadRequest.status_code ) diff --git a/app/library/Utils.py b/app/library/Utils.py index 078ec1c3..b8e3fe7d 100644 --- a/app/library/Utils.py +++ b/app/library/Utils.py @@ -23,7 +23,6 @@ IGNORED_KEYS: tuple[str] = ( "outtmpl", "progress_hooks", "postprocessor_hooks", - "format", "download_archive", ) YTDLP_INFO_CLS: yt_dlp.YoutubeDL = None @@ -45,6 +44,11 @@ def get_opts(preset: str, ytdl_opts: dict) -> dict: ytdl extra options """ + if "format" in ytdl_opts and len(ytdl_opts["format"]) > 2: + format = ytdl_opts["format"] + LOG.info(f"Format '{format}' was given via yt-dlp options. Therefore, the preset will be ignored.") + return ytdl_opts + opts = copy.deepcopy(ytdl_opts) if "default" == preset: diff --git a/ui/components/NewDownload.vue b/ui/components/NewDownload.vue index 885989c5..8cf879ee 100644 --- a/ui/components/NewDownload.vue +++ b/ui/components/NewDownload.vue @@ -20,8 +20,9 @@
- @@ -81,7 +82,7 @@ @@ -93,8 +94,10 @@ Extends current global yt-dlp config with given options. Some fields are ignored like - format cookiefile, paths, and outtmpl etc. - Warning: Use with caution some of those options can break yt-dlp or the frontend. + cookiefile, paths, and outtmpl etc. Warning: Use with caution + some of those options can break yt-dlp or the frontend. If Format key is present + in the config, the preset and all it's options will be + ignored.
@@ -242,7 +245,15 @@ const convertOptions = async () => { try { convertInProgress.value = true - ytdlpConfig.value = await convertCliOptions(ytdlpConfig.value) + const response = await convertCliOptions(ytdlpConfig.value) + ytdlpConfig.value = JSON.stringify(response.opts, null, 2) + if (response.output_template) { + output_template.value = response.output_template + } + if (response.download_path) { + downloadPath.value = response.download_path + } + } catch (e) { toast.error(e.message) } finally { @@ -262,4 +273,16 @@ onUnmounted(() => { socket.off('status', statusHandler) socket.off('error', unlockDownload) }) + +const hasFormatInConfig = computed(() => { + if (!ytdlpConfig.value) { + return false + } + try { + const config = JSON.parse(ytdlpConfig.value) + return "format" in config + } catch (e) { + return false + } +}) diff --git a/ui/components/TaskForm.vue b/ui/components/TaskForm.vue index e625494f..338dbe53 100644 --- a/ui/components/TaskForm.vue +++ b/ui/components/TaskForm.vue @@ -32,7 +32,7 @@
@@ -40,7 +40,7 @@
- The YouTube channel or playlist URL + The channel or playlist URL.
@@ -69,7 +69,9 @@
- @@ -79,7 +81,8 @@
- Select the preset to use for this URL. + Select the preset to use for this URL. The preset will be ignored if format key is present in + config.
@@ -138,8 +141,8 @@ Extends current global yt-dlp config with given options. Some fields are ignored like - format cookiefile, paths, and outtmpl etc. - Warning: Use with caution some of those options can break yt-dlp or the frontend. + cookiefile, paths, and outtmpl etc. Warning: Use with caution + some of those options can break yt-dlp or the frontend. @@ -278,7 +281,14 @@ const convertOptions = async () => { try { convertInProgress.value = true - form.config = await convertCliOptions(form.config) + const response = await convertCliOptions(form.config) + form.config = JSON.stringify(response.opts, null, 2) + if (response.output_template) { + form.template = response.output_template + } + if (response.download_path) { + form.folder = response.download_path + } } catch (e) { toast.error(e.message) } finally { @@ -286,4 +296,15 @@ const convertOptions = async () => { } } +const hasFormatInConfig = computed(() => { + if (!form.config) { + return false + } + try { + const config = JSON.parse(form.config) + return "format" in config + } catch (e) { + return false + } +}) diff --git a/ui/utils/index.js b/ui/utils/index.js index 69cdfabc..47960e61 100644 --- a/ui/utils/index.js +++ b/ui/utils/index.js @@ -400,7 +400,7 @@ const convertCliOptions = async opts => { throw new Error(`Error: (${response.status}): ${data.error}`) } - return JSON.stringify(data, null, 2) + return data } export {