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 路由验证通过
This commit is contained in:
snowy-yang committed 2026-10-23 21:55:45 +08:00
1 parent 800871ef6e
commit dfc06bf4de
182 files changed
+26620

No files matched your search

+60
View File
@@ -0,0 +1,60 @@
"""咪咕音乐搜索(对应 sdk/mg/musicSearch.ts)。
search_all.do(Android_migu 参数),searchSwitch 控制返回类别 —— 歌曲/专辑/歌单三个
子模块共用这一个接口,只切换 searchSwitch。
上游对应 music-lib/migu/migu.go 的 (*Migu).Search。
"""
from __future__ import annotations
import json
import math
from typing import Any
from app.sdk.platforms.mg.util import build_url, convert_item_to_song, migu_get, parse_int
SEARCH_ALL_URL = "http://pd.musicapp.migu.cn/MIGUM2.0/v1.0/content/search_all.do"
def search_switch(kind: str) -> str:
"""搜索开关:只开某一类(song/album/songlist),bestShow 保留最优推荐。"""
payload = {
"song": 1 if kind == "song" else 0,
"album": 1 if kind == "album" else 0,
"singer": 0,
"tagSong": 0,
"mvSong": 0,
"songlist": 1 if kind == "songlist" else 0,
"bestShow": 1,
}
return json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
async def search_all(text: str, kind: str, page: int = 1, limit: int = 20) -> Any:
url = build_url(
SEARCH_ALL_URL,
{
"ua": "Android_migu",
"version": "5.0.1",
"text": text,
"pageNo": page,
"pageSize": limit,
"searchSwitch": search_switch(kind),
},
)
return await migu_get(url)
async def search(keyword: str, page: int = 1, limit: int = 20, retry_num: int = 0) -> dict[str, Any]:
body = await search_all(keyword, "song", page, limit)
data = body.get("songResultData") if isinstance(body, dict) else None
result = (data or {}).get("result") or []
songs = [song for item in result if (song := convert_item_to_song(item, True)) is not None]
total = parse_int((data or {}).get("totalCount")) or len(songs)
return {
"list": songs,
"allPage": max(1, math.ceil(total / limit)),
"total": total,
"limit": limit,
"source": "mg",
}