import asyncio import logging import os from aiogram import Router from aiogram.filters import Command from aiogram.types import Message, FSInputFile from bot.utils.database import get_file_id, save_file_id from bot.utils.yadisk_download import download_yandex_file from bot.utils.s3_client import upload_file router = Router() logger = logging.getLogger("yadisk") MAX_TELEGRAM_FILE_SIZE = 50 * 1024 * 1024 def is_valid_yandex_public_link(value: str) -> bool: value = value.strip().lower() return ( value.startswith("https://disk.yandex.") or value.startswith("http://disk.yandex.") or value.startswith("https://yadi.sk/") or value.startswith("http://yadi.sk/") ) @router.message(Command("ydf")) async def yandex_download_handler(message: Message): text = (message.text or "").strip() parts = text.split(maxsplit=1) if len(parts) < 2 or not parts[1].strip(): await message.answer("Укажите ссылку: /ydf https://yadi.sk/...") return url = parts[1].strip() if url.startswith("(new)"): url = url.replace("(new)", "", 1).strip() if not url: await message.answer("После (new) укажите ссылку.") return await save_file_id(url, None) if not is_valid_yandex_public_link(url): await message.answer("Это не похоже на публичную ссылку Яндекс.Диска.") return cached_id = await get_file_id(url) if cached_id: await message.answer_document( cached_id, caption="Файл из кеша Telegram. /ydf (new) [ссылка] для обновления.", ) return status_msg = await message.answer("Начинаю загрузку с Яндекс.Диска...") last_text = "Начинаю загрузку с Яндекс.Диска..." async def progress(downloaded: int, total: int): nonlocal last_text if total <= 0: return pct = int(downloaded / total * 100) new_text = f"Загрузка: {pct}%" if new_text != last_text and pct % 5 == 0: try: await status_msg.edit_text(new_text) last_text = new_text except Exception: pass try: file_path = await download_yandex_file(url, progress_callback=progress) except Exception as exc: logger.exception("Ошибка скачивания с Яндекс.Диска") await status_msg.edit_text("Не удалось скачать файл. Проверьте ссылку.") return try: file_size = os.path.getsize(file_path) if file_size < MAX_TELEGRAM_FILE_SIZE: doc = FSInputFile(file_path) sent = await message.answer_document(doc) if sent.document and sent.document.file_id: await save_file_id(url, sent.document.file_id) await status_msg.delete() else: await status_msg.edit_text("Файл больше 50MB, загружаю в облако...") s3_url = await asyncio.to_thread(upload_file, file_path) if s3_url: await message.answer(f"Файл доступен для скачивания: {s3_url}") await status_msg.delete() else: await status_msg.edit_text("Не удалось загрузить файл в облако.") finally: try: os.remove(file_path) except OSError: pass