Files
MusicServer/app/sdk/types.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

123 lines
2.7 KiB
Python

"""SDK 共享类型约定。
Python 无编译期类型强制,这里的 TypedDict / Protocol 只作为迁移时的形状文档;
运行时行为与 TS 版一致(普通 dict)。
"""
from __future__ import annotations
from typing import Any, Protocol, TypedDict, runtime_checkable
SOURCE_IDS = (
"kw",
"kg",
"tx",
"wy",
"mg",
"bd",
"joox",
"bili",
"5sing",
"apple",
"xm",
"me",
"qt",
"lr",
)
QUALITIES = ("64k", "128k", "320k", "flac", "flac24bit")
class SongType(TypedDict, total=False):
type: str
size: str
class QualityInfo(TypedDict, total=False):
size: str
class SongInfo(TypedDict, total=False):
songmid: str
hash: str
copyrightId: str
songStringId: str
albumId: str
name: str | None
singer: str
source: str
interval: str | int
albumName: str
img: str | None
lrc: str | None
otherSource: str | None
types: list[SongType]
_types: dict[str, QualityInfo]
typeUrl: dict[str, str]
class MusicUrlResult(TypedDict, total=False):
type: str
url: str
via: str
encrypted: bool
fileKey: str
class LyricInfo(TypedDict, total=False):
lyric: str
tlyric: str
rlyric: str
yrc: str
class SearchResult(TypedDict, total=False):
list: list[dict[str, Any]]
allPage: int
total: int
limit: int
source: str
@runtime_checkable
class MusicSearchModule(Protocol):
async def search(self, keyword: str, page: int = 1, limit: int = 20, retry_num: int = 0) -> SearchResult: ...
async def search(keyword: str, page: int = 1, limit: int = 20) -> SearchResult:
"""占位,供类型检查引用。"""
raise NotImplementedError
class PlatformModule(Protocol):
"""平台模块契约(对应原 sdk/types.ts 的 PlatformModule)。
musicSearch / leaderboard / songList / hotSearch / singer / album / playlist /
parse / userPlaylist 为子模块对象;get_music_url / get_lyric / get_pic 为可等待方法。
各平台按能力自由实现,缺省表示不支持(/sources 的能力位据此判断)。
"""
musicSearch: Any
leaderboard: Any
songList: Any
hotSearch: Any
singer: Any
album: Any
playlist: Any
parse: Any
userPlaylist: Any
def cap(obj: Any, path: str | None = None) -> Any:
"""按 `album.searchAlbum` 形式的嵌套路径取能力位(None 表示不支持)。"""
if obj is None:
return None
if not path:
return obj
cur = obj
for key in path.split("."):
cur = getattr(cur, key, None) if not isinstance(cur, dict) else cur.get(key)
if cur is None:
return None
return cur