From 68228294b0948d918dca3b03ef376795468295b8 Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Sun, 9 Mar 2025 05:09:26 +0300 Subject: [PATCH 1/4] made api/history/add easier to script --- app/library/HttpAPI.py | 13 +++++++++---- app/library/Presets.py | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/library/HttpAPI.py b/app/library/HttpAPI.py index 8ce7b562..10bfa23c 100644 --- a/app/library/HttpAPI.py +++ b/app/library/HttpAPI.py @@ -614,19 +614,24 @@ class HttpAPI(Common): preset = request.query.get("preset") if preset: - exists = Presets.get_instance().get(preset) + exists = Presets.get_instance().get(name=preset) if not exists: return web.json_response( - data={"error": f"Preset '{preset}' does not exist."}, status=web.HTTPBadRequest.status_code + data={"status": False, "message": f"Preset '{preset}' does not exist."}, + status=web.HTTPBadRequest.status_code, ) data["preset"] = preset try: status = await self.add(**self.format_item(data)) except ValueError as e: - return web.json_response(data={"error": str(e)}, status=web.HTTPBadRequest.status_code) + return web.json_response(data={"status": False, "message": str(e)}, status=web.HTTPBadRequest.status_code) - return web.json_response(data=status, status=web.HTTPOk.status_code, dumps=self.encoder.encode) + return web.json_response( + data={"status": True, "message": "URL added", "item": status}, + status=web.HTTPOk.status_code, + dumps=self.encoder.encode, + ) @route("POST", "api/history") async def history_item_add(self, request: Request) -> Response: diff --git a/app/library/Presets.py b/app/library/Presets.py index e2f8a271..d9aa29e2 100644 --- a/app/library/Presets.py +++ b/app/library/Presets.py @@ -251,7 +251,7 @@ class Presets(metaclass=Singleton): try: with open(self._file, "w") as f: - json.dump(obj=[preset.serialize() for preset in presets], fp=f, indent=4) + json.dump(obj=[preset.serialize() for preset in presets if preset.default is False], fp=f, indent=4) LOG.info(f"Presets saved to '{self._file}'.") except Exception as e: From 3a8b67ff82d79f499f78d5cedfadb43a86101983 Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Sun, 9 Mar 2025 05:22:16 +0300 Subject: [PATCH 2/4] normalize return response for api/history/add --- API.md | 14 ++++++-------- app/library/HttpAPI.py | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/API.md b/API.md index e396eeb1..729dd049 100644 --- a/API.md +++ b/API.md @@ -171,21 +171,19 @@ or an error: **Purpose**: **(Quick Add)** Add a single URL to the download queue via GET. **Query Parameters**: -- `?url=` +- `url=` +- `preset=` **Response**: ```json { - "status": "(ok|error)", -} -``` -or an error: -```json -{ - "error": "text" + "status": true|false, # true if added to the queue. false otherwise. + "message": "..." # the response message. } ``` + - If `url` is missing, returns `400 Bad Request`. +- If `preset` is set and not found, returns `404 Not Found`. --- diff --git a/app/library/HttpAPI.py b/app/library/HttpAPI.py index 10bfa23c..5cf0e176 100644 --- a/app/library/HttpAPI.py +++ b/app/library/HttpAPI.py @@ -628,7 +628,7 @@ class HttpAPI(Common): return web.json_response(data={"status": False, "message": str(e)}, status=web.HTTPBadRequest.status_code) return web.json_response( - data={"status": True, "message": "URL added", "item": status}, + data={"status": status.get("status") == "ok", "message": status.get("msg", "URL added")}, status=web.HTTPOk.status_code, dumps=self.encoder.encode, ) From 329a8f51b1aefb8244ebe5099e1bb1698dbf057f Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Mon, 10 Mar 2025 00:52:42 +0300 Subject: [PATCH 3/4] add reference to the iOS shortcut. --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4e8fc85c..57842429 100644 --- a/README.md +++ b/README.md @@ -119,8 +119,15 @@ Change the the variable `url` and `preset` variables to match your YTPTube insta ### iOS Shortcuts -not yet available. +You can download [Add To YTPTube](https://www.icloud.com/shortcuts/18b8f70666a04a06aed09424f97ce951) shortcut and use it to send links to your YTPTube instance. +You have to edit the shortcut and replace the following: +- `https://ytp.example.org` with your YTPTube instance. +- `username:password` replace this with your own username & password or leave it empty if you don't have authentication enabled. + +This shortcut is powerful, as it's allow you to select your preset on the fly pulled directly from your instance. +Combined with the new and powerful presets system, you could add presets for specific websites that need cookies, +and use that preset to download directly from your iOS device. ## Running behind a reverse proxy From dcab2530ec8ed7a7f7ac6b53c19180194ee7972a Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Mon, 10 Mar 2025 00:53:04 +0300 Subject: [PATCH 4/4] Improve history status display and added button to play the video incase thumbnail is hidden. --- ui/components/History.vue | 93 ++++++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 36 deletions(-) diff --git a/ui/components/History.vue b/ui/components/History.vue index 4bd0fe81..a37e03f5 100644 --- a/ui/components/History.vue +++ b/ui/components/History.vue @@ -86,6 +86,10 @@
+ + + @@ -118,11 +122,6 @@
-
- - Live stream is scheduled to start at {{ moment(item.live_in).format() }} - -
{{ item.error }}
@@ -130,23 +129,16 @@ {{ item.msg }}
- - - - - - Live Ended - {{ ucFirst(item.status) }} - + + + {{ setStatus(item) }} - - - - - - Live - +
+
+ + {{ moment(item.live_in).fromNow() }}
@@ -155,13 +147,6 @@ {{ moment(item.datetime).fromNow() }}
-
- - {{ moment(item.live_in).fromNow() }} - -
{{ formatBytes(item.file_size) }}
@@ -400,25 +385,61 @@ const clearIncomplete = () => { } const setIcon = item => { - if (item.status === 'finished' && item.is_live) { - return 'fa-solid fa-globe' + if ('finished' === item.status) { + return item.is_live ? 'fa-solid fa-globe' : 'fa-solid fa-circle-check' } - if (item.status === 'finished') { - return 'fa-solid fa-circle-check' - } - - if (item.status === 'error') { + if ('error' === item.status) { return 'fa-solid fa-circle-xmark' } - if (item.status === 'cancelled') { + if ('cancelled' === item.status) { return 'fa-solid fa-eject' } + if ('not_live' === item.status) { + return 'fa-solid fa-hourglass-half fa-spin' + } + return 'fa-solid fa-circle' } +const setIconColor = item => { + if (item.status === 'finished') { + return 'has-text-success' + } + + if ('not_live' === item.status) { + return 'has-text-info' + } + + if ('cancelled' === item.status) { + return 'has-text-warning' + } + + return 'has-text-danger' +} + +const setStatus = item => { + if ('finished' === item.status) { + return item.is_live ? 'Live Ended' : 'Completed' + } + + if ('error' === item.status) { + return 'Error' + } + + if ('cancelled' === item.status) { + return 'User Cancelled' + } + + if ('not_live' === item.status) { + return 'Live Stream' + } + + return item.status +} + const requeueIncomplete = () => { if (false === confirm('Are you sure you want to re-queue all incomplete downloads?')) { return false