From 706dba9205fccfe7c93ec67ed071ddd84c66f77c Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Sat, 22 Mar 2025 22:48:01 +0300 Subject: [PATCH 1/3] README update --- README.md | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index a4a2755e..4a27d523 100644 --- a/README.md +++ b/README.md @@ -4,31 +4,30 @@ Web GUI for [yt-dlp](https://github.com/yt-dlp/yt-dlp) with playlist & channel support. -YTPTube started as a fork of [meTube](https://github.com/alexta69/metube), Since then it went under heavy changes, and it supports many new features. +[![Short screenshot](https://raw.githubusercontent.com/ArabCoders/ytptube/master/sc_short.png)](https://raw.githubusercontent.com/ArabCoders/ytptube/master/sc_full.png) # YTPTube Features. * Multi-downloads support. -* Handle live streams. -* Schedule channels or playlists to be downloaded automatically at a specified time. +* 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`. * Queue multiple URLs separated by comma. * A built in video player that can play any video file regardless of the format. **With support for sidecar external subtitles**. * New `POST /api/history` endpoint that allow one or multiple links to be sent at the same time. * New `GET /api/history/add?url=http://..` endpoint that allow to add single item via GET request. -* Completely redesigned the frontend UI. -* Switched out of binary file storage in favor of SQLite. +* Modern frontend UI. +* SQLite as database backend. * Basic Authentication support. * Support for curl_cffi, see [yt-dlp documentation](https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#impersonation) * Support for both advanced and basic mode for WebUI. * Bundled tools in container: curl-cffi, ffmpeg, ffprobe, aria2, rtmpdump, mkvtoolsnix, mp4box. -[![Short screenshot](https://raw.githubusercontent.com/ArabCoders/ytptube/master/sc_short.png)](https://raw.githubusercontent.com/ArabCoders/ytptube/master/sc_full.png) # Recommended basic `ytdlp.json` file settings -Your `ytdlp.json` config should include the following basic options for optimal working conditions. +Your `/config/ytdlp.json` config should include the following basic options for optimal working conditions. ```json { @@ -291,6 +290,20 @@ Disables the `Information` button. For API endpoints, please refer to the [API documentation](API.md). it's somewhat outdated, but it's a good starting point. +# How to autoload yt-dlp plugins? + +Loading yt-dlp plugin in YTPTube is is quite simple, we already have everything setup for you. simply, create a folder +inside the `/config` directory named `yt-dlp` so, the path will be `/config/yt-dlp`. then follow +[yt-dlp plugins docs](https://github.com/yt-dlp/yt-dlp?tab=readme-ov-file#plugins) to know how to install the plugins. + +Once you have installed the plugins, restart the container and the plugins will be auto-loaded on demand. + +# The origin of the project. + +The project first started as a fork [meTube](https://github.com/alexta69/metube), since then it has been completely +rewritten and redesigned. The original project was a great starting point, but it didn't align with my vision for the +project and what i wanted to achieve with it. + # Social contact If you have short or quick questions, you are free to join my [discord server](https://discord.gg/G3GpVR8xpb) and ask From c46aa1cfe4bbcc248ea82ce9433360c680873c59 Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Sun, 23 Mar 2025 00:22:33 +0300 Subject: [PATCH 2/3] minor fix to EventBus, and trim all preset form fields. --- app/library/Events.py | 6 +++--- app/library/Notifications.py | 13 +++++++++---- ui/components/PresetForm.vue | 7 +++++++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/library/Events.py b/app/library/Events.py index 281edac4..7fd52b47 100644 --- a/app/library/Events.py +++ b/app/library/Events.py @@ -160,7 +160,7 @@ class Event: id: str = field(default_factory=lambda: str(uuid.uuid4()), init=False) """The id of the event.""" - created_at: str = field(default_factory=lambda: str(datetime.datetime.now(tz=datetime.timezone.utc).isoformat())) + created_at: str = field(default_factory=lambda: str(datetime.datetime.now(tz=datetime.UTC).isoformat())) """The time the event was created.""" event: str @@ -209,8 +209,8 @@ class EventListener: async def handle(self, event: Event, **kwargs): if self.is_coroutine: return self.call_back(event, self.name, **kwargs) - else: - return asyncio.create_task(self.call_back(event, self.name, **kwargs)) + + return asyncio.create_task(self.call_back(event, self.name, **kwargs)) class EventBus(metaclass=Singleton): diff --git a/app/library/Notifications.py b/app/library/Notifications.py index f372fbb5..add6eefd 100644 --- a/app/library/Notifications.py +++ b/app/library/Notifications.py @@ -2,8 +2,9 @@ import asyncio import json import logging import os +from collections.abc import Awaitable from dataclasses import dataclass, field -from datetime import UTC, datetime +from datetime import datetime from typing import Any import httpx @@ -11,7 +12,7 @@ from aiohttp import web from .config import Config from .encoder import Encoder -from .Events import EventBus, Event, Events +from .Events import Event, EventBus, Events from .ItemDTO import ItemDTO from .Singleton import Singleton from .Utils import ag, validate_uuid @@ -323,7 +324,7 @@ class Notification(metaclass=Singleton): return True - async def send(self, ev: Event) -> list[dict]: + async def send(self, ev: Event, wait: bool = True) -> list[dict] | Awaitable[list[dict]]: if len(self._targets) < 1: return [] @@ -339,7 +340,10 @@ class Notification(metaclass=Singleton): tasks.append(self._send(target, ev)) - return await asyncio.gather(*tasks) + if wait: + return await asyncio.gather(*tasks) + + return tasks async def _send(self, target: Target, ev: Event) -> dict: try: @@ -367,6 +371,7 @@ class Notification(metaclass=Singleton): if "form" == target.request.type.lower(): reqBody["data"]["data"] = self._encoder.encode(reqBody["data"]["data"]) + logging.getLogger("httpx").setLevel(logging.WARNING) response = await self._client.request(**reqBody) respData = {"url": target.request.url, "status": response.status_code, "text": response.text} diff --git a/ui/components/PresetForm.vue b/ui/components/PresetForm.vue index 3ac968ad..7317d393 100644 --- a/ui/components/PresetForm.vue +++ b/ui/components/PresetForm.vue @@ -345,6 +345,13 @@ const checkInfo = async () => { } } + // trim all fields in copy only if they are strings + for (const key in copy) { + if (typeof copy[key] === 'string') { + copy[key] = copy[key].trim() + } + } + emitter('submit', { reference: toRaw(props.reference), preset: toRaw(copy) }); } From 37ef9314cbaa84b6e0449bee135585ed88b07129 Mon Sep 17 00:00:00 2001 From: ArabCoders Date: Sun, 23 Mar 2025 00:46:24 +0300 Subject: [PATCH 3/3] fix notification.emit return to return coro incase we don't have any targets. --- app/library/Notifications.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/library/Notifications.py b/app/library/Notifications.py index add6eefd..80230ab8 100644 --- a/app/library/Notifications.py +++ b/app/library/Notifications.py @@ -389,11 +389,8 @@ class Notification(metaclass=Singleton): return {"url": target.request.url, "status": 500, "text": str(ev)} def emit(self, e: Event, _, **kwargs): # noqa: ARG002 - if len(self._targets) < 1: - return [] - - if not NotificationEvents.is_valid(e.event): - return [] + if len(self._targets) < 1 or not NotificationEvents.is_valid(e.event): + return asyncio.sleep(0) return self.send(e)