mirror of
https://github.com/tropicoo/yt-dlp-bot.git
synced 2024-09-20 06:46:08 +08:00
Version 1.5
This commit is contained in:
parent
f43d27319c
commit
7a33dc0434
|
@ -13,4 +13,4 @@
|
|||
**/*Dockerfile*
|
||||
LICENSE
|
||||
README.md
|
||||
pyproject.toml
|
||||
.ruff.toml
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
[tool.ruff]
|
||||
line-length = 88
|
||||
lint.select = ["F", "E", "W", "I001"]
|
||||
lint.ignore = ["E501"] # Skip line length violations
|
||||
src = ["app_api", "app_bot", "app_worker"]
|
||||
|
||||
[tool.ruff.format]
|
||||
[lint]
|
||||
select = ["F", "E", "W", "I001"]
|
||||
ignore = ["E501"] # Skip line length violations
|
||||
|
||||
[format]
|
||||
indent-style = "space"
|
||||
quote-style = "single"
|
||||
line-ending = "lf"
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Simple and reliable self-hosted Video Download Telegram Bot.
|
||||
|
||||
Version: 1.4.5. [Release details](RELEASES.md).
|
||||
Version: 1.5. [Release details](RELEASES.md).
|
||||
|
||||
![frames](.assets/download_success.png)
|
||||
|
||||
|
|
20
RELEASES.md
20
RELEASES.md
|
@ -1,3 +1,22 @@
|
|||
## Release 1.5
|
||||
|
||||
Release date: March 20, 2024
|
||||
|
||||
## New Features
|
||||
|
||||
N/A
|
||||
|
||||
## Important
|
||||
|
||||
N/A
|
||||
|
||||
## Misc
|
||||
|
||||
- Migrated from Pyrogram to Pyrofork
|
||||
- Migrated from Python 3.11 to 3.12
|
||||
|
||||
---
|
||||
|
||||
## Release 1.4.5
|
||||
|
||||
Release date: November 23, 2023
|
||||
|
@ -15,6 +34,7 @@ N/A
|
|||
- Improved error handling
|
||||
|
||||
---
|
||||
|
||||
## Release 1.4.4
|
||||
|
||||
Release date: November 11, 2023
|
||||
|
|
|
@ -8,7 +8,7 @@ from api.api.api_v1.schemas.ytdlp import YTDLPLatestVersion
|
|||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get('/')
|
||||
@router.get('/', response_model_by_alias=False)
|
||||
async def yt_dlp_version(db: AsyncSession = Depends(get_db)) -> YTDLPLatestVersion:
|
||||
ctx = await YtdlpVersionChecker().get_version_context(db)
|
||||
return YTDLPLatestVersion(
|
||||
|
|
|
@ -6,26 +6,20 @@ from pyrogram import Client
|
|||
from pyrogram.enums import ParseMode
|
||||
from pyrogram.errors import RPCError
|
||||
|
||||
from bot.core.config.config import get_main_config
|
||||
from bot.core.schema import UserSchema
|
||||
from bot.core.schema import ConfigSchema, UserSchema
|
||||
from bot.core.utils import bold
|
||||
|
||||
|
||||
class VideoBot(Client):
|
||||
class VideoBotClient(Client):
|
||||
"""Extended Pyrogram's `Client` class."""
|
||||
|
||||
_RUN_FOREVER_SLEEP_SECONDS = 86400
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.conf = get_main_config()
|
||||
super().__init__(
|
||||
name='default_name',
|
||||
api_id=self.conf.telegram.api_id,
|
||||
api_hash=self.conf.telegram.api_hash,
|
||||
bot_token=self.conf.telegram.token,
|
||||
)
|
||||
def __init__(self, *args, conf: ConfigSchema, **kwargs) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
self._log = logging.getLogger(self.__class__.__name__)
|
||||
self._log.info('Initializing bot client')
|
||||
self.conf = conf
|
||||
|
||||
self.allowed_users: dict[int, UserSchema] = {}
|
||||
self.admin_users: dict[int, UserSchema] = {}
|
|
@ -5,8 +5,9 @@ from pyrogram.handlers import MessageHandler
|
|||
from yt_shared.rabbit import get_rabbitmq
|
||||
from yt_shared.utils.tasks.tasks import create_task
|
||||
|
||||
from bot.core.bot import VideoBot
|
||||
from bot.bot.client import VideoBotClient
|
||||
from bot.core.callbacks import TelegramCallback
|
||||
from bot.core.config.config import get_main_config
|
||||
from bot.core.tasks.ytdlp import YtdlpNewVersionNotifyTask
|
||||
from bot.core.workers.manager import RabbitWorkerManager
|
||||
|
||||
|
@ -19,7 +20,14 @@ class BotLauncher:
|
|||
def __init__(self) -> None:
|
||||
"""Constructor."""
|
||||
self._log = logging.getLogger(self.__class__.__name__)
|
||||
self._bot = VideoBot()
|
||||
self._conf = get_main_config()
|
||||
self._bot = VideoBotClient(
|
||||
name='default_name',
|
||||
api_id=self._conf.telegram.api_id,
|
||||
api_hash=self._conf.telegram.api_hash,
|
||||
bot_token=self._conf.telegram.token,
|
||||
conf=self._conf,
|
||||
)
|
||||
self._rabbit_mq = get_rabbitmq()
|
||||
self._rabbit_worker_manager = RabbitWorkerManager(bot=self._bot)
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
from bot.core.bot.bot import VideoBot
|
||||
from bot.core.bot.launcher import BotLauncher
|
||||
|
||||
__all__ = [
|
||||
'BotLauncher',
|
||||
'VideoBot',
|
||||
]
|
|
@ -4,7 +4,7 @@ from pyrogram.enums import ParseMode
|
|||
from pyrogram.types import Message
|
||||
from yt_shared.emoji import SUCCESS_EMOJI
|
||||
|
||||
from bot.core.bot import VideoBot
|
||||
from bot.bot.client import VideoBotClient
|
||||
from bot.core.service import UrlParser, UrlService
|
||||
from bot.core.utils import bold, get_user_id
|
||||
|
||||
|
@ -19,14 +19,14 @@ class TelegramCallback:
|
|||
self._url_service = UrlService()
|
||||
|
||||
@staticmethod
|
||||
async def on_start(client: VideoBot, message: Message) -> None:
|
||||
async def on_start(client: VideoBotClient, message: Message) -> None:
|
||||
await message.reply(
|
||||
bold('Send video URL to start processing'),
|
||||
parse_mode=ParseMode.HTML,
|
||||
reply_to_message_id=message.id,
|
||||
)
|
||||
|
||||
async def on_message(self, client: VideoBot, message: Message) -> None:
|
||||
async def on_message(self, client: VideoBotClient, message: Message) -> None:
|
||||
"""Receive video URL and send to the download worker."""
|
||||
self._log.debug('Received Telegram Message: %s', message)
|
||||
text = message.text
|
||||
|
|
|
@ -3,22 +3,19 @@ import logging
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from yt_shared.enums import TaskSource, TelegramChatType
|
||||
from yt_shared.schemas.error import ErrorDownloadGeneralPayload, ErrorDownloadPayload
|
||||
from yt_shared.schemas.success import SuccessDownloadPayload
|
||||
from yt_shared.schemas.base_rabbit import BaseRabbitDownloadPayload
|
||||
|
||||
from bot.core.schema import AnonymousUserSchema, UserSchema
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bot.core.bot import VideoBot
|
||||
from bot.bot import VideoBotClient
|
||||
|
||||
|
||||
class AbstractDownloadHandler(abc.ABC):
|
||||
def __init__(
|
||||
self,
|
||||
body: SuccessDownloadPayload
|
||||
| ErrorDownloadPayload
|
||||
| ErrorDownloadGeneralPayload,
|
||||
bot: 'VideoBot',
|
||||
body: BaseRabbitDownloadPayload,
|
||||
bot: 'VideoBotClient',
|
||||
) -> None:
|
||||
self._log = logging.getLogger(self.__class__.__name__)
|
||||
self._body = body
|
||||
|
|
|
@ -23,7 +23,7 @@ from bot.core.schema import AnonymousUserSchema, UserSchema, VideoCaptionSchema
|
|||
from bot.core.utils import bold, is_user_upload_silent
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bot.core.bot import VideoBot
|
||||
from bot.bot.client import VideoBotClient
|
||||
|
||||
|
||||
class BaseUploadContext(RealBaseModel):
|
||||
|
@ -52,7 +52,7 @@ class AbstractUploadTask(AbstractTask, abc.ABC):
|
|||
self,
|
||||
media_object: BaseMedia,
|
||||
users: list[AnonymousUserSchema | UserSchema],
|
||||
bot: 'VideoBot',
|
||||
bot: 'VideoBotClient',
|
||||
semaphore: asyncio.Semaphore,
|
||||
context: SuccessDownloadPayload,
|
||||
) -> None:
|
||||
|
|
|
@ -12,11 +12,11 @@ from bot.core.config.config import get_main_config
|
|||
from bot.core.utils import bold, code
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bot.core.bot import VideoBot
|
||||
from bot.bot import VideoBotClient
|
||||
|
||||
|
||||
class YtdlpNewVersionNotifyTask(AbstractTask):
|
||||
def __init__(self, bot: 'VideoBot') -> None:
|
||||
def __init__(self, bot: 'VideoBotClient') -> None:
|
||||
super().__init__()
|
||||
self._bot = bot
|
||||
self._version_checker = YtdlpVersionChecker()
|
||||
|
|
|
@ -100,9 +100,5 @@ def is_user_upload_silent(
|
|||
user: UserSchema | AnonymousUserSchema, conf: ConfigSchema
|
||||
) -> bool:
|
||||
if isinstance(user, AnonymousUserSchema):
|
||||
if conf.telegram.api.silent:
|
||||
return True
|
||||
elif user.upload.silent:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return conf.telegram.api.silent
|
||||
return user.upload.silent
|
||||
|
|
|
@ -13,7 +13,7 @@ from bot.core.config.config import get_main_config
|
|||
from bot.core.exceptions import InvalidBodyError
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bot.core.bot import VideoBot
|
||||
from bot.bot.client import VideoBotClient
|
||||
|
||||
|
||||
class RabbitWorkerType(enum.Enum):
|
||||
|
@ -26,7 +26,7 @@ class AbstractDownloadResultWorker(AbstractTask):
|
|||
QUEUE_TYPE: str | None = None
|
||||
SCHEMA_CLS: tuple[Type[BaseModel]] = ()
|
||||
|
||||
def __init__(self, bot: 'VideoBot') -> None:
|
||||
def __init__(self, bot: 'VideoBotClient') -> None:
|
||||
super().__init__()
|
||||
self._conf = get_main_config()
|
||||
self._bot = bot
|
||||
|
|
|
@ -9,13 +9,13 @@ from bot.core.workers.error import ErrorDownloadResultWorker
|
|||
from bot.core.workers.success import SuccessDownloadResultWorker
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bot.core.bot import VideoBot
|
||||
from bot.bot.client import VideoBotClient
|
||||
|
||||
|
||||
class RabbitWorkerManager:
|
||||
_TASK_TYPES = (ErrorDownloadResultWorker, SuccessDownloadResultWorker)
|
||||
|
||||
def __init__(self, bot: 'VideoBot') -> None:
|
||||
def __init__(self, bot: 'VideoBotClient') -> None:
|
||||
self._log = logging.getLogger(self.__class__.__name__)
|
||||
self._bot = bot
|
||||
self._workers: dict[RabbitWorkerType, Task] = {}
|
||||
|
|
|
@ -1 +1 @@
|
|||
__version__ = '1.4.5'
|
||||
__version__ = '1.5'
|
||||
|
|
|
@ -5,7 +5,7 @@ import asyncio
|
|||
|
||||
import uvloop
|
||||
|
||||
from bot.core.bot import BotLauncher
|
||||
from bot.bot.launcher import BotLauncher
|
||||
from bot.core.log import setup_logging
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
PyYAML==6.0.1
|
||||
Pyrogram==2.0.106
|
||||
addict==2.4.0
|
||||
pyrofork==2.3.19.post2
|
||||
tenacity==8.2.3
|
||||
tgcrypto==1.2.5
|
||||
typing_extensions==4.10.0
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM python:3.11-alpine
|
||||
FROM python:3.12-alpine
|
||||
|
||||
RUN apk add --no-cache \
|
||||
tzdata \
|
||||
|
|
|
@ -1,19 +1,21 @@
|
|||
import abc
|
||||
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
from yt_shared.enums import RabbitPayloadType
|
||||
|
||||
|
||||
class RealBaseModel(BaseModel):
|
||||
class RealBaseModel(BaseModel, abc.ABC):
|
||||
"""Base Pydantic model. All models should inherit from this."""
|
||||
|
||||
model_config = ConfigDict(extra='forbid')
|
||||
|
||||
|
||||
class BaseOrmModel(RealBaseModel):
|
||||
class BaseOrmModel(RealBaseModel, abc.ABC):
|
||||
model_config = ConfigDict(from_attributes=True, **RealBaseModel.model_config)
|
||||
|
||||
|
||||
class BaseRabbitPayloadModel(RealBaseModel):
|
||||
class BaseRabbitPayloadModel(RealBaseModel, abc.ABC):
|
||||
"""Base RabbitMQ payload model. All RabbitMQ models should inherit from this."""
|
||||
|
||||
type: RabbitPayloadType
|
||||
|
|
15
yt_shared/yt_shared/schemas/base_rabbit.py
Normal file
15
yt_shared/yt_shared/schemas/base_rabbit.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
import abc
|
||||
|
||||
from pydantic import StrictInt
|
||||
|
||||
from yt_shared.enums import TelegramChatType
|
||||
from yt_shared.schemas.base import BaseRabbitPayloadModel
|
||||
from yt_shared.schemas.media import InbMediaPayload
|
||||
|
||||
|
||||
class BaseRabbitDownloadPayload(BaseRabbitPayloadModel, abc.ABC):
|
||||
context: InbMediaPayload
|
||||
from_chat_id: StrictInt | None
|
||||
from_chat_type: TelegramChatType | None
|
||||
from_user_id: StrictInt | None
|
||||
message_id: StrictInt | None
|
|
@ -1,23 +1,17 @@
|
|||
import uuid
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import StrictInt, StrictStr
|
||||
from pydantic import StrictStr
|
||||
|
||||
from yt_shared.enums import RabbitPayloadType, TelegramChatType
|
||||
from yt_shared.schemas.base import BaseRabbitPayloadModel
|
||||
from yt_shared.schemas.media import InbMediaPayload
|
||||
from yt_shared.enums import RabbitPayloadType
|
||||
from yt_shared.schemas.base_rabbit import BaseRabbitDownloadPayload
|
||||
|
||||
|
||||
class ErrorDownloadGeneralPayload(BaseRabbitPayloadModel):
|
||||
class ErrorDownloadGeneralPayload(BaseRabbitDownloadPayload):
|
||||
type: Literal[RabbitPayloadType.GENERAL_ERROR] = RabbitPayloadType.GENERAL_ERROR
|
||||
task_id: uuid.UUID | StrictStr | None
|
||||
from_chat_id: StrictInt | None
|
||||
from_chat_type: TelegramChatType | None
|
||||
from_user_id: StrictInt | None
|
||||
message_id: StrictInt | None
|
||||
message: StrictStr
|
||||
url: StrictStr
|
||||
context: InbMediaPayload
|
||||
exception_msg: StrictStr
|
||||
exception_type: StrictStr
|
||||
yt_dlp_version: StrictStr | None
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import abc
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
from typing import Literal
|
||||
|
@ -34,7 +35,7 @@ class InbMediaPayload(RealBaseModel):
|
|||
added_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
|
||||
|
||||
class BaseMedia(RealBaseModel):
|
||||
class BaseMedia(RealBaseModel, abc.ABC):
|
||||
"""Model representing abstract downloaded media with common fields."""
|
||||
|
||||
file_type: MediaFileType
|
||||
|
|
|
@ -1,22 +1,17 @@
|
|||
import uuid
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import StrictInt, StrictStr
|
||||
from pydantic import StrictStr
|
||||
|
||||
from yt_shared.enums import RabbitPayloadType, TelegramChatType
|
||||
from yt_shared.schemas.base import BaseRabbitPayloadModel
|
||||
from yt_shared.schemas.media import DownMedia, InbMediaPayload
|
||||
from yt_shared.enums import RabbitPayloadType
|
||||
from yt_shared.schemas.base_rabbit import BaseRabbitDownloadPayload
|
||||
from yt_shared.schemas.media import DownMedia
|
||||
|
||||
|
||||
class SuccessDownloadPayload(BaseRabbitPayloadModel):
|
||||
class SuccessDownloadPayload(BaseRabbitDownloadPayload):
|
||||
"""Payload with downloaded media context."""
|
||||
|
||||
type: Literal[RabbitPayloadType.SUCCESS] = RabbitPayloadType.SUCCESS
|
||||
task_id: uuid.UUID
|
||||
from_chat_id: StrictInt | None
|
||||
from_chat_type: TelegramChatType | None
|
||||
from_user_id: StrictInt | None
|
||||
message_id: StrictInt | None
|
||||
media: DownMedia
|
||||
context: InbMediaPayload
|
||||
yt_dlp_version: StrictStr | None
|
||||
|
|
Loading…
Reference in a new issue