diff --git a/app/library/DownloadQueue.py b/app/library/DownloadQueue.py index df84ba68..07e92b22 100644 --- a/app/library/DownloadQueue.py +++ b/app/library/DownloadQueue.py @@ -184,8 +184,8 @@ class DownloadQueue(metaclass=Singleton): """ if item.has_extras(): for key in item.extras.copy(): - if not str(key).startswith("playlist"): - item.extras.pop(key, None) + if not self.keep_extra_key(key): + item.extras.pop(key) if not entry: return {"status": "error", "msg": "Invalid/empty data was given."} @@ -395,6 +395,10 @@ class DownloadQueue(metaclass=Singleton): .get_all(), } + if yt_conf.get("external_downloader"): + LOG.warning(f"Using external downloader '{yt_conf.get('external_downloader')}' for '{item.url}'.") + item.extras.update({"external_downloader": True}) + downloaded, id_dict = self._is_downloaded(file=yt_conf.get("download_archive", None), url=item.url) if downloaded is True and id_dict: message = f"This url with ID '{id_dict.get('id')}' has been downloaded already and recorded in archive." @@ -715,3 +719,17 @@ class DownloadQueue(metaclass=Singleton): return False, None return is_downloaded(file, url) + + def keep_extra_key(self, key: str) -> bool: + """ + Check if the extra key should be kept. + + Args: + key (str): The extra key to check. + + Returns: + bool: True if the extra key should be kept, False otherwise. + + """ + keys = ("playlist", "external_downloader") + return any(key == k or key.startswith(k) for k in keys) diff --git a/app/library/ItemDTO.py b/app/library/ItemDTO.py index e9fc570e..2619675a 100644 --- a/app/library/ItemDTO.py +++ b/app/library/ItemDTO.py @@ -134,6 +134,12 @@ class Item: preset = item.get("preset") if preset and isinstance(preset, str) and preset != Item._default_preset(): + from .Presets import Presets + + if not Presets.get_instance().has(preset): + msg = f"Preset '{preset}' does not exist." + raise ValueError(msg) + data["preset"] = preset if item.get("folder") and isinstance(item.get("folder"), str): diff --git a/app/library/Notifications.py b/app/library/Notifications.py index a62e1bf3..cdfb27d3 100644 --- a/app/library/Notifications.py +++ b/app/library/Notifications.py @@ -46,12 +46,14 @@ class TargetRequest: method: str url: str headers: list[TargetRequestHeader] = field(default_factory=list) + data_key: str = "data" def serialize(self) -> dict: return { "type": self.type, "method": self.method, "url": self.url, + "data_key": self.data_key, "headers": [h.serialize() for h in self.headers], } @@ -213,7 +215,8 @@ class Notification(metaclass=Singleton): try: Notification.validate(target) except ValueError as e: - LOG.error(f"Invalid notification target '{target}'. '{e!s}'") + name = target.get("name") or target.get("id") or target.get("request", {}).get("url") or "unknown" + LOG.error(f"Invalid notification target '{name}'. '{e!s}'") continue target = self.make_target(target) @@ -247,6 +250,7 @@ class Notification(metaclass=Singleton): type=target.get("request", {}).get("type", "json"), method=target.get("request", {}).get("method", "POST"), url=target.get("request", {}).get("url"), + data_key=target.get("request", {}).get("data_key", "data"), headers=[ TargetRequestHeader( key=str(h.get("key", "")).strip(), @@ -288,6 +292,9 @@ class Notification(metaclass=Singleton): msg = "Invalid notification target. No URL found." raise ValueError(msg) + if "data_key" not in target["request"]: + target["request"]["data_key"] = "data" + if "method" in target["request"] and target["request"]["method"].upper() not in ["POST", "PUT"]: msg = "Invalid notification target. Invalid method found." raise ValueError(msg) @@ -363,10 +370,17 @@ class Notification(metaclass=Singleton): for h in target.request.headers: reqBody["headers"][h.key] = h.value - reqBody["json" if "json" == target.request.type.lower() else "data"] = self._deep_unpack(ev.serialize()) + body_key = "json" if "json" == target.request.type.lower() else "data" + reqBody[body_key] = self._deep_unpack(ev.serialize()) + + if "data" != target.request.data_key: + reqBody[body_key][target.request.data_key] = reqBody[body_key]["data"] + reqBody[body_key].pop("data", None) if "form" == target.request.type.lower(): - reqBody["data"]["data"] = self._encoder.encode(reqBody["data"]["data"]) + reqBody[body_key][target.request.data_key] = self._encoder.encode( + reqBody[body_key][target.request.data_key] + ) response = await self._client.request(**reqBody) diff --git a/app/library/Presets.py b/app/library/Presets.py index cfec885b..a123e7c3 100644 --- a/app/library/Presets.py +++ b/app/library/Presets.py @@ -266,6 +266,19 @@ class Presets(metaclass=Singleton): return self + def has(self, id_or_name: str) -> bool: + """ + Check if the preset exists by id or name. + + Args: + id_or_name (str): The id or name of the preset. + + Returns: + bool: True if the preset exists, False otherwise. + + """ + return self.get(id_or_name) is not None + def get(self, id_or_name: str) -> Preset | None: """ Get the preset by id or name. diff --git a/ui/components/NotificationForm.vue b/ui/components/NotificationForm.vue index 112e54d4..87130c3f 100644 --- a/ui/components/NotificationForm.vue +++ b/ui/components/NotificationForm.vue @@ -138,7 +138,7 @@ -
data.
+
+
+