# -*- coding: utf-8 -*- """HTTP 会话复用与音频内容嗅探。 (自 music_downloader.py 拆出,行为与原实现一致。) """ from __future__ import annotations import threading import filetype from core import sync_http as requests # 同步门面(底层 aiohttp,替代 requests) # ============ HTTP 连接复用(提速核心) ============ # 常见浏览器 UA,避免直链 CDN 因空 UA 限速/拒绝 DEFAULT_UA = ( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " "(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" ) # 音频流式下载分块大小(256KB):减少系统调用与磁盘 IO 次数,提升吞吐 DL_CHUNK_SIZE = 256 * 1024 # 线程本地 Session:同线程内复用 TCP/TLS 连接(keep-alive),批量并发显著提速 _SESSION_LOCAL = threading.local() # M4A/MP4 音频在 filetype 里被判为 video/mp4——mp4 是复合容器,仅凭魔数无法 # 区分音频轨与视频轨,故显式放行该 mime。 _CONTAINER_MIMES = frozenset({'video/mp4'}) def _sniff_audio_header(path) -> bool: """按魔数判定文件是否为音频容器(MP3/FLAC/OGG/Opus/WAV/M4A/MP4)。 未知期望尺寸的下载走"非空即通过"保留口径,本函数补上内容防线—— CDN 错误页/风控 JSON 不再能被存成音频交付。 识别交给 filetype(内置完整类型表,覆盖各格式的多种帧头变体), 不再自行维护魔数前缀与 ftyp 偏移;对空文件/未知格式返回 False。 """ try: kind = filetype.guess(str(path)) except OSError: return False if kind is None: return False mime = (kind.mime or '').lower() return mime.startswith('audio/') or mime in _CONTAINER_MIMES def get_http_session() -> requests.Session: """获取当前线程的共享同步会话(连接池由底层 aiohttp 统一维护)。""" session: requests.Session | None = getattr(_SESSION_LOCAL, "session", None) if session is None: session = requests.Session() session.headers.update({"User-Agent": DEFAULT_UA}) _SESSION_LOCAL.session = session return session