diff --git a/poetry.lock b/poetry.lock index e7dee3b..8b4e7fc 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1397,4 +1397,4 @@ test = ["pytest (>=8.1,<9.0)", "pytest-rerunfailures (>=14.0,<15.0)"] [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "d44ec77f5a7767eb93e8e802f0c278efbf7a5121e99d3a18bf0a3723474273d9" +content-hash = "86633a0ddb52e149c7fac8f3d8bb0bc4a6d5746d57cb01797f5d14712362089a" diff --git a/pyproject.toml b/pyproject.toml index 1926897..a1f9c0f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ requests = "^2.32.3" curl-cffi = "^0.7.3" pycryptodome = "^3.21.0" aiogram = "^3.14.0" +aiohttp = "^3.10" [tool.poetry.group.dev.dependencies] mypy = "^1.13.0" diff --git a/ytdl_inline_bot/bot.py b/ytdl_inline_bot/bot.py index 7e82bb2..776403b 100644 --- a/ytdl_inline_bot/bot.py +++ b/ytdl_inline_bot/bot.py @@ -36,9 +36,10 @@ InputMediaPhoto, InlineKeyboardButton, InlineKeyboardMarkup, - FSInputFile, URLInputFile, + FSInputFile, ) from yt_dlp import YoutubeDL +import aiohttp # Enable logging logging.basicConfig( @@ -309,31 +310,38 @@ async def download_video_and_replace(url: str, inline_message_id: str, user_id: logger.info(f"Video uploaded. Preparing thumbnail for the video.") - video_id = extract_youtube_video_id(url) - if video_id: - thumbnail_url = get_youtube_thumbnail_url(video_id, 'mqdefault') - thumbnail_file = URLInputFile(url=thumbnail_url) - else: - thumbnail_url = None - thumbnail_file = None - - logger.info(f"Replacing the placeholder with the video {video_msg.video.file_id} and thumbnail {thumbnail_url}") - - await retry_operation( - bot.edit_message_media, - max_retries=2, - delay=1, - inline_message_id=inline_message_id, - media=InputMediaVideo( - media=video_msg.video.file_id, - caption=(metadata.title + " " + url), - thumbnail=thumbnail_file, - width=metadata.width, - height=metadata.height, - duration=metadata.duration, - supports_streaming=True + thumbnail_filename = None # Initialize thumbnail filename + try: + video_id = extract_youtube_video_id(url) + if video_id: + thumbnail_url = get_youtube_thumbnail_url(video_id, 'mqdefault') + thumbnail_filename = await download_file(thumbnail_url) # Download the thumbnail + thumbnail_file = FSInputFile(thumbnail_filename) + else: + thumbnail_url = None + thumbnail_file = None + + logger.info(f"Replacing the placeholder with the video {video_msg.video.file_id} and thumbnail {thumbnail_url}") + + await retry_operation( + bot.edit_message_media, + max_retries=2, + delay=1, + inline_message_id=inline_message_id, + media=InputMediaVideo( + media=video_msg.video.file_id, + caption=(metadata.title + " " + url), + thumbnail=thumbnail_file, + width=metadata.width, + height=metadata.height, + duration=metadata.duration, + supports_streaming=True + ) ) - ) + finally: + # Delete the thumbnail file from disk + if thumbnail_filename and os.path.exists(thumbnail_filename): + os.remove(thumbnail_filename) # Update rate limit timestamp for non-VIP users only on successful download if user_id != VIP_USER_ID: @@ -362,6 +370,25 @@ async def download_video_and_replace(url: str, inline_message_id: str, user_id: media=InputMediaVideo(media=ERR_LOADING_VIDEO_URL, caption="Failed to replace the placeholder video.", width=ERR_VIDEO_WIDTH, height=ERR_VIDEO_HEIGHT, duration=ERR_VIDEO_DURATION, supports_streaming=False) ) +async def download_file(url: str) -> str: + """ + Downloads a file from a URL to a local file with a random filename. + Returns the filename. + """ + filename = f"thumb_{uuid.uuid4().hex}.jpg" # Added .jpg extension + async with aiohttp.ClientSession() as session: + async with session.get(url) as response: + if response.status == 200: + with open(filename, 'wb') as f: + while True: + chunk = await response.content.read(1024) + if not chunk: + break + f.write(chunk) + else: + raise Exception(f"Failed to download file from {url}, status code {response.status}") + return filename + async def async_download_video(ydl_opts: Dict[str, Any], url: str) -> None: """Asynchronously downloads a video using yt-dlp.""" loop = asyncio.get_event_loop()