Merge pull request #222 from arabcoders/dev
Minor README & EventBus update
This commit is contained in:
commit
28d902b2a9
4 changed files with 41 additions and 19 deletions
27
README.md
27
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.
|
||||
[](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.
|
||||
|
||||
[](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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
@ -384,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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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) });
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue