Files
MusicServer/app/sdk/platforms/kg/singer.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

86 lines
2.8 KiB
Python

"""酷狗歌手(对应 sdk/kg/singer.ts)。"""
from __future__ import annotations
from typing import Any
from app.sdk.platforms.kg.music_info import get_music_infos_by_list
from app.sdk.platforms.kg.util import create_http_fetch
SINGER_INFO_URL = "http://mobiles.kugou.com/api/v5/singer/info"
SINGER_ALBUM_URL = "http://mobiles.kugou.com/api/v5/singer/album"
SINGER_SONG_URL = "http://mobiles.kugou.com/api/v5/singer/song"
def _check_id(id: Any) -> None:
# kg 源有些歌曲在歌手未被酷狗收录时返回的歌手 id 为 0
if str(id) in ("0", ""):
raise RuntimeError("歌手不存在")
async def get_info(id: str) -> dict[str, Any]:
_check_id(id)
body = await create_http_fetch(f"{SINGER_INFO_URL}?singerid={id}")
body = body or {}
if not body:
raise RuntimeError("get singer info faild.")
imgurl = str(body.get("imgurl") or "")
return {
"source": "kg",
"id": body.get("singerid"),
"info": {
"name": body.get("singername"),
"desc": body.get("intro"),
"avatar": imgurl.replace("{size}", "480") if imgurl else "",
"gender": "man" if body.get("grade") == 1 else "woman",
},
"count": {"music": body.get("songcount"), "album": body.get("albumcount")},
}
def _filter_album_list(raw: list[dict[str, Any]]) -> list[dict[str, Any]]:
return [
{
"id": item.get("albumid"),
"count": item.get("songcount"),
"info": {
"name": item.get("albumname"),
"author": item.get("singername"),
"img": str(item.get("imgurl") or item.get("img") or "").replace("{size}", "480"),
"desc": item.get("intro"),
},
}
for item in raw
]
async def get_album_list(id: str, page: int = 1, limit: int = 10) -> dict[str, Any]:
_check_id(id)
body = await create_http_fetch(f"{SINGER_ALBUM_URL}?singerid={id}&page={page}&pagesize={limit}")
body = body or {}
if not body.get("info"):
raise RuntimeError("get singer album list faild.")
return {
"source": "kg",
"list": _filter_album_list(body.get("info") or []),
"limit": limit,
"page": page,
"total": body.get("total"),
}
async def get_song_list(id: str, page: int = 1, limit: int = 100) -> dict[str, Any]:
_check_id(id)
body = await create_http_fetch(f"{SINGER_SONG_URL}?singerid={id}&page={page}&pagesize={limit}")
body = body or {}
if not body.get("info"):
raise RuntimeError("get singer song list faild.")
songs = await get_music_infos_by_list(body.get("info") or [])
return {
"source": "kg",
"list": songs,
"limit": limit,
"page": page,
"total": body.get("total"),
}