Files
MusicServer/app/sdk/platforms/apple/album.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

90 lines
3.2 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.
"""Apple Music 专辑(对应 sdk/apple/album.ts,上游 apple.go 的 SearchAlbum / ParseAlbum / GetAlbumSongs)。
详情:amp-api /v1/catalog/<sf>/albums/<id>?extend=extendedAssetUrls
→ data[0].relationships.tracks.data[](>300 首时分页,next 由 fetchAllTrackResources 跟进)
链接:extract_apple_id(link, 'album'),支持裸数字 id 与 /us/album/<slug>/<id> 链接。
"""
from __future__ import annotations
from typing import Any
from app.sdk.common.utils import as_dict, as_list
from app.sdk.platforms.apple.music_search import search_album
from app.sdk.platforms.apple.util import (
apple_album_to_playlist,
apple_amp_get,
apple_song_from_catalog,
extract_apple_id,
fetch_all_track_resources,
get_apple_config,
)
async def get_album_detail(raw_id: str, page: int = 1, limit: int = 50) -> dict[str, Any]:
"""专辑详情(page/limit 在完整曲目上切片,与其它平台 get_album_detail 契约一致)。"""
album_id = extract_apple_id(str(raw_id or ""), "album")
if not album_id:
raise RuntimeError(f"invalid apple music album id/link: {raw_id}")
cfg = get_apple_config()
body = as_dict(
await apple_amp_get(f"/v1/catalog/{cfg['storefront']}/albums/{album_id}", {"extend": "extendedAssetUrls"})
)
data = as_list(body.get("data"))
album = as_dict(data[0]) if data else {}
if not album:
raise RuntimeError(f"apple album not found: {album_id}")
tracks = await fetch_all_track_resources(as_dict(album.get("relationships")).get("tracks"))
songs = [apple_song_from_catalog(track, album_id) for track in tracks]
p = max(1, int(page or 1))
size = max(1, int(limit or 50))
summary = apple_album_to_playlist(album)
# 上游 fetchPlaylistDetail 的做法:接口未给 trackCount 时以实际曲目数补齐
if not summary["trackCount"] or len(songs) > summary["trackCount"]:
summary["trackCount"] = len(songs)
return {
"source": "apple",
"info": {
"id": album_id,
"name": summary["name"],
"img": summary["cover"],
"desc": summary["description"],
"author": summary["creator"],
"link": summary["link"],
"trackCount": summary["trackCount"],
"releaseDate": summary["extra"]["release_date"],
"recordLabel": summary["extra"]["record_label"],
},
"list": songs[(p - 1) * size : (p - 1) * size + size],
"page": p,
"limit": size,
"total": len(songs),
}
async def get_album_songs(album_id: str) -> list[dict[str, Any]]:
"""上游 GetAlbumSongs:只返回曲目数组。"""
detail = await get_album_detail(album_id, 1, 100000)
return detail["list"]
async def parse_album_link(link: str) -> dict[str, Any]:
"""上游 ParseAlbum:专辑链接 → 详情(曲目全量,不分页)。"""
detail = await get_album_detail(link, 1, 100000)
return {
"source": "apple",
"id": detail["info"]["id"],
"info": detail["info"],
"list": detail["list"],
"page": 1,
"limit": max(detail["total"], 1),
"total": detail["total"],
}
__all__ = ["get_album_detail", "get_album_songs", "parse_album_link", "search_album"]