Files
MusicServer/app/sdk/platforms/qt/music_search.py
T
snowy-yang dfc06bf4de feat(python): 完成 Python 全量迁移——剩余平台、登录通道与公共层修复
- 新增 5sing/apple/xm/me/qt/lr 平台包与取流实现(含 xm-sign、MissEvan 签名、蜻蜓 HMAC、Apple developer token)
- 新增 wy/kg/tx/lr 登录:扫码、手机号、账密(kg 20028 风控指纹)、cookie 绑定、kg/tx 续期
- request 层:保留多值 Set-Cookie;JSON body 紧凑化(修复 kg 网关验签);直连不经系统代理(对齐 Node)
- 登录路由统一 Body(embed=True),修复扫码轮询 422;lifespan 接入登录续期调度
- ruff/format/pyright 全绿;14 平台真实联网与 HTTP 路由验证通过
2026-10-23 21:55:45 +08:00

55 lines
2.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""蜻蜓FM 搜索(对应 sdk/qt/musicSearch.ts,官网 SSR 频道结果页解析)。
接口: https://www.qingting.fm/search/channel_ondemand/<keyword>(302 → www.qtfm.cn,见 http.py)
实测(2026-10-02)SSR 渲染且与关键词强相关;?keyword= 混合页的结果区为客户端渲染
(服务端只吐热门推荐),JSON 搜索端点(webapi/webbff/searchapi)均 404——本页是唯一匿名搜索通道。
"""
from __future__ import annotations
import re
from typing import Any
from app.sdk.platforms.fivesing.util import encode_uri_component
from app.sdk.platforms.qt.http import ssr_get
async def search(keyword: str, page: int = 1, limit: int = 20, retry_num: int = 0) -> dict[str, Any]:
del retry_num # 契约参数,SSR 搜索无重试语义
result = await ssr_get(
f"https://www.qingting.fm/search/channel_ondemand/{encode_uri_component(keyword)}?page={page}"
)
if result["statusCode"] != 200:
raise RuntimeError(f"搜索失败(HTTP {result['statusCode']})")
html = str(result["html"])
# 结果项:href=/channels/<id> … <span title="<名称>">,封面在随后的 img src
items = []
for match in re.finditer(r'href="/channels/(\d+)"[\s\S]{0,400}?<span title="([^"]*)">', html):
after = html[match.start() : match.start() + 700]
img = re.search(r'<img src="(http[^"]+)"', after)
items.append(
{
"songmid": match.group(1),
"name": match.group(2),
"singer": "",
"albumId": "",
"albumName": "",
"interval": 0,
"img": img.group(1).replace("http://", "https://") if img else None,
"lrc": "",
"lrcx": "",
"types": [],
"_types": {},
"disabled": False,
}
)
songs = [item for item in items if item["name"]][:limit]
return {
"allPage": page + (1 if len(songs) >= 10 else 0),
"total": len(songs),
"limit": limit,
"source": "qt",
"list": songs,
}