import os import re import tempfile from pathlib import Path from urllib.parse import urlencode, unquote import aiohttp from config import create_aiohttp_session, get_aiohttp_request_kwargs DOWNLOAD_DIR = Path("downloads") DOWNLOAD_DIR.mkdir(exist_ok=True) def sanitize_filename(filename: str) -> str: filename = os.path.basename(filename).strip() filename = re.sub(r"[\\/:*?\"<>|]+", "_", filename) return filename or "downloaded_file" async def download_yandex_files(public_url: str, progress_callback=None) -> str: base_url = "https://cloud-api.yandex.net/v1/disk/public/resources/download?" final_url = base_url + urlencode({"public_key": public_url}) timeout = aiohttp.ClientTimeout(total=None, sock_connect=30, sock_read=300) async with create_aiohttp_session(timeout=timeout) as session: request_kwargs = get_aiohttp_request_kwargs() async with session.get(final_url, **request_kwargs) as response: response.raise_for_status() payload = await response.json() download_url = payload["href"] async with session.get(download_url, **request_kwargs) as response: response.raise_for_status() content_disposition = response.headers.get("Content-Disposition", "") filename = download_url.split("/")[-1] if "filename*" in content_disposition: try: encoded = content_disposition.split("filename*=")[1].strip() parts = encoded.split("''", 1) if len(parts) == 2: filename = unquote(parts[1], encoding=parts[0] or "utf-8") except Exception: pass filename = sanitize_filename(filename) suffix = Path(filename).suffix or ".bin" with tempfile.NamedTemporaryFile(delete=False, suffix=suffix, dir=DOWNLOAD_DIR) as tmp_file: total_size = int(response.headers.get("Content-Length", 0)) downloaded_size = 0 async for chunk in response.content.iter_chunked(1024 * 64): tmp_file.write(chunk) downloaded_size += len(chunk) if progress_callback: await progress_callback(downloaded_size, total_size) return tmp_file.name