From 23b1b409f4ad1d69b8e8c2b12ee2e94cc7f3b151 Mon Sep 17 00:00:00 2001 From: arabcoders Date: Mon, 31 Mar 2025 02:13:33 +0300 Subject: [PATCH] deprecate JSON yt-dlp config & Post-Processors in presets and recommand cli options. --- README.md | 2 +- app/library/Download.py | 2 +- app/library/HttpAPI.py | 3 + app/library/Presets.py | 12 ++ app/library/Tasks.py | 3 +- app/library/YTDLPOpts.py | 24 ++-- app/library/presets.json | 41 +----- ui/components/NewDownload.vue | 16 ++- ui/components/PresetForm.vue | 250 +++++++++++++++++----------------- ui/components/TaskForm.vue | 16 ++- ui/pages/presets.vue | 24 +++- ui/stores/ConfigStore.js | 7 +- ui/utils/index.js | 33 +++++ 13 files changed, 243 insertions(+), 190 deletions(-) diff --git a/README.md b/README.md index c59b6db7..2af4e726 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Web GUI for [yt-dlp](https://github.com/yt-dlp/yt-dlp) with playlist & channel s * Can Handle live streams. * Scheduler to queue channels or playlists to be downloaded automatically at a specified time. * Send notification to targets based on selected events. -* Support per link `yt-dlp JSON config or cli options`, `cookies` & `output format`. +* Support per link `cli options` & `cookies` * Queue multiple URLs separated by comma. * Simple file browser. `Disabled by default` * A built in video player that can play any video file regardless of the format. **With support for sidecar external subtitles**. diff --git a/app/library/Download.py b/app/library/Download.py index 68e33bf9..cfeacb72 100644 --- a/app/library/Download.py +++ b/app/library/Download.py @@ -215,7 +215,7 @@ class Download: f'Task id="{self.info.id}" PID="{os.getpid()}" title="{self.info.title}" preset="{self.preset}" started.' ) - self.logger.debug("Params before passing to yt-dlp.", extra=params) + self.logger.debug(f"Params before passing to yt-dlp. {params}") params["logger"] = NestedLogger(self.logger) diff --git a/app/library/HttpAPI.py b/app/library/HttpAPI.py index f2cc37c6..268c12f6 100644 --- a/app/library/HttpAPI.py +++ b/app/library/HttpAPI.py @@ -453,6 +453,9 @@ class HttpAPI(Common): if "paths" in data and "home" in data["paths"]: response["download_path"] = data["paths"]["home"] + if "format" in data: + response["format"] = data["format"] + for key in data: if key in IGNORED_KEYS: continue diff --git a/app/library/Presets.py b/app/library/Presets.py index 39ae334e..83f65e16 100644 --- a/app/library/Presets.py +++ b/app/library/Presets.py @@ -41,6 +41,9 @@ class Preset: cookies: str = "" """The default cookies to use if non is given.""" + cli: str = "" + """yt-dlp cli command line arguments.""" + default: bool = False def serialize(self) -> dict: @@ -220,6 +223,15 @@ class Presets(metaclass=Singleton): msg = "Invalid postprocessors type. expected list." raise ValueError(msg) + if preset.get("cli"): + try: + from .Utils import arg_converter + + arg_converter(args=preset.get("cli")) + except Exception as e: + msg = f"Invalid cli options. '{e!s}'." + raise ValueError(msg) from e + return True def save(self, presets: list[Preset | dict]) -> "Presets": diff --git a/app/library/Tasks.py b/app/library/Tasks.py index c5633ee9..dc695114 100644 --- a/app/library/Tasks.py +++ b/app/library/Tasks.py @@ -10,8 +10,6 @@ from typing import Any import httpx from aiohttp import web -from app.library.Utils import arg_converter - from .config import Config from .encoder import Encoder from .Events import EventBus, Events, error, info, success @@ -224,6 +222,7 @@ class Tasks(metaclass=Singleton): if task.get("cli"): try: + from .Utils import arg_converter arg_converter(args=task.get("cli")) except Exception as e: msg = f"Invalid cli options. '{e!s}'." diff --git a/app/library/YTDLPOpts.py b/app/library/YTDLPOpts.py index 1a5fd206..18673a71 100644 --- a/app/library/YTDLPOpts.py +++ b/app/library/YTDLPOpts.py @@ -4,7 +4,7 @@ from pathlib import Path from .config import Config from .Presets import Presets from .Singleton import Singleton -from .Utils import IGNORED_KEYS, calc_download_path, merge_dict +from .Utils import IGNORED_KEYS, arg_converter, calc_download_path, merge_dict LOG = logging.getLogger("YTDLPOpts") @@ -71,6 +71,13 @@ class YTDLPOpts(metaclass=Singleton): if not preset or "default" == name: return self + if preset.cli: + try: + self._preset_opts = arg_converter(args=preset.cli, remove_options=True) + except Exception as e: + msg = f"Invalid cli options for preset '{preset.name}'. '{e!s}'." + raise ValueError(msg) from e + if preset.cookies and with_cookies: file = Path(self._config.config_path, "cookies", f"{preset.id}.txt") @@ -94,14 +101,15 @@ class YTDLPOpts(metaclass=Singleton): "temp": self._config.temp_path, } - if preset.postprocessors and isinstance(preset.postprocessors, list) and len(preset.postprocessors) > 0: - self._preset_opts["postprocessors"] = preset.postprocessors + if not preset.cli: + if preset.postprocessors and isinstance(preset.postprocessors, list) and len(preset.postprocessors) > 0: + self._preset_opts["postprocessors"] = preset.postprocessors - if preset.args and isinstance(preset.args, dict) and len(preset.args) > 0: - for key, value in preset.args.items(): - if key in IGNORED_KEYS: - continue - self._preset_opts[key] = value + if preset.args and isinstance(preset.args, dict) and len(preset.args) > 0: + for key, value in preset.args.items(): + if key in IGNORED_KEYS: + continue + self._preset_opts[key] = value return self diff --git a/app/library/presets.json b/app/library/presets.json index 52e0eae7..86c6492c 100644 --- a/app/library/presets.json +++ b/app/library/presets.json @@ -6,6 +6,7 @@ "folder": "", "template": "", "cookies": "", + "cli": "", "default": true }, { @@ -15,69 +16,37 @@ "folder": "", "template": "", "cookies": "", + "cli": "", "default": true }, { "id": "441675ed-b739-40f0-a0b0-1ecfcb9dc48b", "name": "1080p H264/m4a or best available", "format": "bv[height<=1080][ext=mp4]+ba[ext=m4a]/b[ext=mp4]/b[ext=webm]", - "args": { - "format_sort": [ - "vcodec:h264" - ] - }, "folder": "", "template": "", "cookies": "", + "cli": "-S vcodec:h264", "default": true }, { "id": "9719fcc3-4cf2-4d88-b1e4-74dff3dba00e", "name": "720p h264/m4a or best available", "format": "bv[height<=720][ext=mp4]+ba[ext=m4a]/b[ext=mp4]/b[ext=webm]", - "args": { - "format_sort": [ - "vcodec:h264" - ] - }, "folder": "", "template": "", "cookies": "", + "cli": "-S vcodec:h264", "default": true }, { "id": "a6fd4b25-2b3e-458d-bb57-b75e41cc4330", "name": "Audio only", "format": "bestaudio/best", - "args": { - "writethumbnail": true - }, - "postprocessors": [ - { - "key": "FFmpegExtractAudio", - "preferredcodec": "best", - "preferredquality": "5", - "nopostoverwrites": false - }, - { - "key": "FFmpegMetadata", - "add_chapters": true, - "add_metadata": true, - "add_infojson": "if_exists" - }, - { - "key": "EmbedThumbnail", - "already_have_thumbnail": false - }, - { - "key": "FFmpegConcat", - "only_multi_video": true, - "when": "playlist" - } - ], "folder": "", "template": "", "cookies": "", + "cli": "--extract-audio --add-chapters --embed-metadata --embed-thumbnail", "default": true } ] diff --git a/ui/components/NewDownload.vue b/ui/components/NewDownload.vue index fff72859..3e062ec0 100644 --- a/ui/components/NewDownload.vue +++ b/ui/components/NewDownload.vue @@ -23,9 +23,16 @@ @@ -273,4 +280,7 @@ const hasFormatInConfig = computed(() => { return true } }) + +const filter_presets = (flag = true) => config.presets.filter(item => item.default === flag) + diff --git a/ui/components/PresetForm.vue b/ui/components/PresetForm.vue index 7317d393..aedbd1d2 100644 --- a/ui/components/PresetForm.vue +++ b/ui/components/PresetForm.vue @@ -1,43 +1,5 @@