From 7167670a1415545d2e7a0164107e084d1a1cca25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B6=B5=E6=9B=A6?= Date: Mon, 8 Sep 2025 23:39:51 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20LX=E9=9F=B3=E6=BA=90=E6=94=AF=E6=8C=81h?= =?UTF-8?q?ttp=5Fproxy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- xiaomusic/httpserver.py | 4 +-- xiaomusic/utils.py | 55 +++++++++++++++++++++++++++-------------- xiaomusic/xiaomusic.py | 24 ++++++++++-------- 3 files changed, 53 insertions(+), 30 deletions(-) diff --git a/xiaomusic/httpserver.py b/xiaomusic/httpserver.py index 496d05a..6d0a57f 100644 --- a/xiaomusic/httpserver.py +++ b/xiaomusic/httpserver.py @@ -342,7 +342,7 @@ async def musiclist(Verifcation=Depends(verification)): async def musicinfo( name: str, musictag: bool = False, Verifcation=Depends(verification) ): - url = xiaomusic.get_music_url(name) + url = await xiaomusic.get_music_url(name) info = { "ret": "OK", "name": name, @@ -361,7 +361,7 @@ async def musicinfos( ): ret = [] for music_name in name: - url = xiaomusic.get_music_url(music_name) + url = await xiaomusic.get_music_url(music_name) info = { "name": music_name, "url": url, diff --git a/xiaomusic/utils.py b/xiaomusic/utils.py index e04e058..4b59e99 100644 --- a/xiaomusic/utils.py +++ b/xiaomusic/utils.py @@ -1312,15 +1312,30 @@ def chmoddir(dir_path: str): log.info(f"chmoddir failed: {e}") -async def fetch_json_get(url, headers): - async with aiohttp.ClientSession() as session: - try: - async with session.get(url, headers=headers) as response: +async def fetch_json_get(url, headers, config): + connector = None + proxy = None + if config and config.proxy: + connector = aiohttp.TCPConnector( + ssl=False, # 如需验证SSL证书,可改为True(需确保代理支持) + limit=10, + ) + proxy = config.proxy + try: + # 2. 传入代理配置创建ClientSession + async with aiohttp.ClientSession(connector=connector) as session: + # 3. 发起带代理的GET请求 + async with session.get( + url, + headers=headers, + proxy=proxy, # 传入格式化后的代理参数 + timeout=10, # 超时时间(秒),避免无限等待 + ) as response: if response.status == 200: data = await response.json() log.info(f"fetch_json_get: {url} success {data}") - # 可选:确保是 dict + # 确保返回结果为dict if isinstance(data, dict): return data else: @@ -1329,15 +1344,19 @@ async def fetch_json_get(url, headers): else: log.error(f"HTTP Error: {response.status} {url}") return {} - except aiohttp.ClientError as e: - log.error(f"ClientError fetching {url}: {e}") - return {} - except asyncio.TimeoutError: - log.error(f"Timeout fetching {url}") - return {} - except Exception as e: - log.error(f"Unexpected error fetching {url}: {e}") - return {} + except aiohttp.ClientError as e: + log.error(f"ClientError fetching {url} (proxy: {proxy}): {e}") + return {} + except asyncio.TimeoutError: + log.error(f"Timeout fetching {url} (proxy: {proxy})") + return {} + except Exception as e: + log.error(f"Unexpected error fetching {url} (proxy: {proxy}): {e}") + return {} + finally: + # 4. 关闭连接器(避免资源泄漏) + if connector and not connector.closed: + await connector.close() class LRUCache(OrderedDict): @@ -1367,7 +1386,7 @@ class MusicUrlCache: self.default_expire_days = default_expire_days self.log = logging.getLogger(__name__) - def get(self, url: str, headers: dict = None) -> str: + async def get(self, url: str, headers: dict = None, config=None) -> str: """获取URL(优先从缓存获取,没有则请求API) Args: @@ -1383,7 +1402,7 @@ class MusicUrlCache: return cached_url # 缓存未命中,请求API - return self._fetch_from_api(url, headers) + return await self._fetch_from_api(url, headers, config) def _get_from_cache(self, url: str) -> str: """从缓存中获取URL""" @@ -1397,9 +1416,9 @@ class MusicUrlCache: except KeyError: return "" - def _fetch_from_api(self, url: str, headers: dict = None) -> str: + async def _fetch_from_api(self, url: str, headers: dict = None, config=None) -> str: """从API获取真实URL""" - data = fetch_json_get(url, headers or {}) + data = await fetch_json_get(url, headers or {}, config) if not isinstance(data, dict): self.log.error(f"Invalid API response format: {data}") diff --git a/xiaomusic/xiaomusic.py b/xiaomusic/xiaomusic.py index a5a0f6f..14aa106 100644 --- a/xiaomusic/xiaomusic.py +++ b/xiaomusic/xiaomusic.py @@ -520,8 +520,10 @@ class XiaoMusic: Returns: tuple: (播放时长(秒), 播放地址) """ - url, origin_url = self.get_music_url(name) - self.log.info(f"get_music_sec_url. name:{name} url:{url}") + url, origin_url = await self.get_music_url(name) + self.log.info( + f"get_music_sec_url. name:{name} url:{url} origin_url:{origin_url}" + ) # 电台直接返回 if self.is_web_radio_music(name): @@ -562,7 +564,7 @@ class XiaoMusic: self.log.info(f"本地歌曲 {name} : {filename} {url} 的时长 {sec} 秒") return sec - def get_music_url(self, name): + async def get_music_url(self, name): """获取音乐播放地址 Args: @@ -571,17 +573,17 @@ class XiaoMusic: tuple: (播放地址, 原始地址) - 网络音乐时可能有原始地址 """ if self.is_web_music(name): - return self._get_web_music_url(name) + return await self._get_web_music_url(name) return self._get_local_music_url(name), None - def _get_web_music_url(self, name): + async def _get_web_music_url(self, name): """获取网络音乐播放地址""" url = self.all_music[name] self.log.info(f"get_music_url web music. name:{name}, url:{url}") # 需要通过API获取真实播放地址 if self.is_need_use_play_music_api(name): - url = self._get_url_from_api(name, url) + url = await self._get_url_from_api(name, url) if not url: return "", None @@ -592,10 +594,10 @@ class XiaoMusic: return url, None - def _get_url_from_api(self, name, url): + async def _get_url_from_api(self, name, url): """通过API获取真实播放地址""" - headers = self._all_web_music_api[name].get("headers", {}) - url = self.url_cache.get(url, headers) + headers = self._web_music_api[name].get("headers", {}) + url = await self.url_cache.get(url, headers, self.config) if not url: self.log.error(f"get_music_url use api fail. name:{name}, url:{url}") return url @@ -618,7 +620,9 @@ class XiaoMusic: if filename.startswith("/"): filename = filename[1:] - self.log.info(f"get_music_url local music. name:{name}, filename:{filename}") + self.log.info( + f"_get_local_music_url local music. name:{name}, filename:{filename}" + ) # 构造URL encoded_name = urllib.parse.quote(filename)