From 1bda1893e4d1c20804a51e460143c1c4705de64b Mon Sep 17 00:00:00 2001 From: arabcoders Date: Mon, 31 Mar 2025 00:12:35 +0300 Subject: [PATCH 1/7] Convert json config in tasks to use cli arguments. --- app/library/HttpAPI.py | 9 +- app/library/Tasks.py | 68 ++++++++------ app/library/Utils.py | 11 ++- app/library/common.py | 9 ++ ui/components/TaskForm.vue | 183 +++++++++++++++---------------------- ui/pages/tasks.vue | 110 ++++------------------ 6 files changed, 154 insertions(+), 236 deletions(-) diff --git a/app/library/HttpAPI.py b/app/library/HttpAPI.py index 74177928..f2cc37c6 100644 --- a/app/library/HttpAPI.py +++ b/app/library/HttpAPI.py @@ -872,15 +872,12 @@ class HttpAPI(Common): if not item.get("timer", None) or str(item.get("timer")).strip() == "": item["timer"] = f"{random.randint(1,59)} */1 * * *" # noqa: S311 - if not item.get("cookies", None): - item["cookies"] = "" - - if not item.get("config", None) or str(item.get("config")).strip() == "": - item["config"] = {} - if not item.get("template", None): item["template"] = "" + if not item.get("cli", None): + item["cli"] = "" + try: ins.validate(item) except ValueError as e: diff --git a/app/library/Tasks.py b/app/library/Tasks.py index b3ac7a33..c5633ee9 100644 --- a/app/library/Tasks.py +++ b/app/library/Tasks.py @@ -3,13 +3,15 @@ import json import logging import os import time -from dataclasses import dataclass, field +from dataclasses import dataclass from datetime import UTC, datetime 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 @@ -28,8 +30,7 @@ class Task: preset: str = "" timer: str = "" template: str = "" - cookies: str = "" - config: dict[str, str] = field(default_factory=dict) + cli: str = "" def serialize(self) -> dict: return self.__dict__ @@ -134,16 +135,20 @@ class Tasks(metaclass=Singleton): with open(self._file) as f: tasks = json.load(f) except Exception as e: - LOG.error(f"Failed to parse tasks from '{self._file}'. '{e}'.") + LOG.error(f"Failed to parse tasks from '{self._file}'. '{e!s}'.") return self if not tasks or len(tasks) < 1: LOG.info(f"No tasks were defined in '{self._file}'.") return self + need_update = False for i, task in enumerate(tasks): try: + task, task_status = self.clean_task(task) task = Task(**task) + if task_status: + need_update = True except Exception as e: LOG.error(f"Failed to parse task at list position '{i}'. '{e!s}'.") continue @@ -157,6 +162,10 @@ class Tasks(metaclass=Singleton): LOG.exception(e) LOG.error(f"Failed to queue task '{i}: {task.name}'. '{e!s}'.") + if need_update: + LOG.info("Updating tasks file to remove old keys.") + self.save(self.get_all()) + return self def clear(self, shutdown: bool = False) -> "Tasks": @@ -213,17 +222,12 @@ class Tasks(metaclass=Singleton): msg = "No URL found." raise ValueError(msg) - if not isinstance(task.get("cookies"), str): - msg = "Invalid cookies type." - raise ValueError(msg) # noqa: TRY004 - - if not isinstance(task.get("config"), dict): - msg = "Invalid config type." - raise ValueError(msg) # noqa: TRY004 - - if not isinstance(task.get("template"), str): - msg = "Invalid template type." - raise ValueError(msg) # noqa: TRY004 + if task.get("cli"): + try: + arg_converter(args=task.get("cli")) + except Exception as e: + msg = f"Invalid cli options. '{e!s}'." + raise ValueError(msg) from e return True @@ -263,6 +267,27 @@ class Tasks(metaclass=Singleton): return self + def clean_task(self, task: dict) -> tuple[dict, bool]: + """ + Clean the task from old keys. + + Args: + task (dict): The task to clean. + + Returns: + tuple[dict, bool]: The cleaned task and a status if the task was cleaned. + + """ + status = False + removedKeys = ["cookies", "config"] + + for key in removedKeys: + if key in task: + status = True + task.pop(key) + + return task, status + async def _runner(self, task: Task): """ Run the task. @@ -283,16 +308,8 @@ class Tasks(metaclass=Singleton): preset: str = str(task.preset or self._default_preset) folder: str = task.folder if task.folder else "" - cookies: str = str(task.cookies) if task.cookies else "" template: str = task.template if task.template else "" - - config = task.config if task.config else {} - if isinstance(config, str) and config: - try: - config = json.loads(config) - except Exception as e: - LOG.error(f"Failed to parse json yt-dlp config for '{task.name}'. {e!s}") - return + cli: str = task.cli if task.cli else "" LOG.info(f"Task '{task.id}: {task.name}' dispatched at '{timeNow}'.") @@ -307,9 +324,8 @@ class Tasks(metaclass=Singleton): "url": task.url, "preset": preset, "folder": folder, - "cookies": cookies, - "config": config, "template": template, + "cli": cli, }, id=task.id, ), diff --git a/app/library/Utils.py b/app/library/Utils.py index 4251bb5e..0bddc15b 100644 --- a/app/library/Utils.py +++ b/app/library/Utils.py @@ -434,12 +434,13 @@ def validate_url(url: str) -> bool: return True -def arg_converter(args: str) -> dict: +def arg_converter(args: str, remove_options: bool = False) -> dict: """ Convert yt-dlp options to a dictionary. Args: args (str): yt-dlp options string. + remove_options (bool): Remove default options. Returns: dict: yt-dlp options dictionary. @@ -472,6 +473,14 @@ def arg_converter(args: str) -> dict: if isinstance(matchFilter, set): diff["match_filter"] = {"filters": list(matchFilter)} + if remove_options: + for key in diff.copy(): + if key in IGNORED_KEYS: + diff.pop(key, None) + + if "_warnings" in diff: + diff.pop("_warnings", None) + from .encoder import Encoder return json.loads(json.dumps(diff, cls=Encoder)) diff --git a/app/library/common.py b/app/library/common.py index 371ca22a..a89d3815 100644 --- a/app/library/common.py +++ b/app/library/common.py @@ -4,6 +4,7 @@ import logging from .config import Config from .DownloadQueue import DownloadQueue from .encoder import Encoder +from .Utils import arg_converter LOG = logging.getLogger("common") @@ -94,6 +95,14 @@ class Common: msg = f"Failed to parse json yt-dlp config for '{url}'. {e!s}" raise ValueError(msg) from e + cli = item.get("cli") + if cli and len(cli) > 1: + try: + config = arg_converter(args=cli, remove_options=True) + except Exception as e: + msg = f"Failed to parse yt-dlp cli options. {e!s}" + raise ValueError(msg) from e + return { "url": url, "preset": preset, diff --git a/ui/components/TaskForm.vue b/ui/components/TaskForm.vue index 63580dd7..5ed51093 100644 --- a/ui/components/TaskForm.vue +++ b/ui/components/TaskForm.vue @@ -50,7 +50,6 @@ -