{{ filterItem(cond) }}
+ {{ JSON.stringify(cleanObject(cond, remove_keys), null, 2) }}
diff --git a/app/library/HttpAPI.py b/app/library/HttpAPI.py index b97c8dd1..7d050ac3 100644 --- a/app/library/HttpAPI.py +++ b/app/library/HttpAPI.py @@ -871,6 +871,74 @@ class HttpAPI(Common): await self._notify.emit(Events.CONDITIONS_UPDATE, data=items) return web.json_response(data=items, status=web.HTTPOk.status_code, dumps=self.encoder.encode) + @route("POST", "api/conditions/test") + async def conditions_test(self, request: Request) -> Response: + """ + Test condition against URL. + + Args: + request (Request): The request object. + + Returns: + Response: The response object + + """ + data = await request.json() + + if not isinstance(data, dict): + return web.json_response( + {"error": "Invalid request body expecting dict."}, + status=web.HTTPBadRequest.status_code, + ) + + url = data.get("url") + if not url: + return web.json_response({"error": "url is required."}, status=web.HTTPBadRequest.status_code) + + cond = data.get("condition") + if not cond: + return web.json_response({"error": "condition name is required."}, status=web.HTTPBadRequest.status_code) + + try: + opts = {} + + if ytdlp_proxy := self.config.get_ytdlp_args().get("proxy", None): + opts["proxy"] = ytdlp_proxy + + preset = data.get("preset", self.config.default_preset) + ytdlp_opts = YTDLPOpts.get_instance().preset(name=preset, with_cookies=True).add(opts).get_all() + key = self.cache.hash(url + str(preset)) + if not self.cache.has(key): + data = extract_info( + config=ytdlp_opts, + url=url, + debug=False, + no_archive=True, + follow_redirect=True, + sanitize_info=True, + ) + self.cache.set(key=key, value=data, ttl=600) + else: + data = self.cache.get(key) + except Exception as e: + LOG.exception(e) + return web.json_response( + data={"error": f"Failed to extract video info. '{e!s}'"}, + status=web.HTTPInternalServerError.status_code, + ) + + matched = Conditions.get_instance().single_match(name=cond, info=data) + if matched is None: + return web.json_response( + data={"error": f"Condition '{cond}' doesn't match the data from the URL."}, + status=web.HTTPNotFound.status_code, + ) + + return web.json_response( + data={"message": f"Condition '{cond}' matched the data from the URL."}, + status=web.HTTPOk.status_code, + ) + @route("GET", "api/presets") async def presets(self, request: Request) -> Response: """ diff --git a/app/library/conditions.py b/app/library/conditions.py index b91beba1..cb764052 100644 --- a/app/library/conditions.py +++ b/app/library/conditions.py @@ -317,3 +317,26 @@ class Conditions(metaclass=Singleton): continue return None + + def single_match(self, name: str, info: dict) -> Condition | None: + """ + Check if condition matches the info dict. + + Args: + name (str): The condition name to check. + info (dict): The info dict to check. + + Returns: + Condition|None: The condition if found, None otherwise. + + """ + if len(self._items) < 1 or not info or not isinstance(info, dict) or len(info) < 1: + return None + + item = self.get(name) + if not item or not item.filter: + return None + + from yt_dlp.utils import match_str + + return item if match_str(item.filter, info) else None diff --git a/ui/composables/useConfirm.ts b/ui/composables/useConfirm.ts index 45976a4d..90ed293d 100644 --- a/ui/composables/useConfirm.ts +++ b/ui/composables/useConfirm.ts @@ -14,6 +14,10 @@ function alert(msg: string): boolean { return window.confirm(msg) } -export default function useConfirm() { - return { confirm, alert, reduceConfirm } +function prompt(msg: string, defaultValue: string = ''): string | null { + return window.prompt(msg, defaultValue) +} + +export default function useConfirm() { + return { confirm, alert, prompt, reduceConfirm } } diff --git a/ui/pages/conditions.vue b/ui/pages/conditions.vue index 96433fa9..72694b2a 100644 --- a/ui/pages/conditions.vue +++ b/ui/pages/conditions.vue @@ -66,7 +66,7 @@
{{ filterItem(cond) }}
+ {{ JSON.stringify(cleanObject(cond, remove_keys), null, 2) }}
availability = 'needs_auth' & channel_id = 'channel_id'.
and set proxy for that specific video, while leaving the rest of the videos to be downloaded normally.
+