refactor(api)!: 平台 id 回退——joox/5sing/bili/apple 恢复全名,目录对齐 bd/mg
- 撤销 3381e9b/1b972ec 中 jx/5s/bl/ap 四个短码,恢复 joox/5sing/bili/apple; qian→bd、migu→mg 保留 - 目录与文件对齐保留的新 id:sdk/qian/→sdk/bd/、sdk/migu/→sdk/mg/、 sdk/apis/qian.ts→bd.ts、migu.ts→mg.ts、src/http/migu-stream.ts→mg-stream.ts (规则改为「目录=对外 id」,聚合入口的模块变量同步更名;music.migu.cn 等域名、 上游 music-lib 对照注释、miguGet 等功能标识符不动) - 对外 id 全表:kw kg tx wy qs xm me qt lr mg bd joox 5sing bili apple **破坏性变更**:joox/5sing/bili/apple 四平台的 URL、/sources 返回与 data/auth.json 凭据键恢复全名,已存短码键的登录态需重新登录。 验证:typecheck ✓、pnpm test 112/112 ✓
This commit is contained in:
1 parent
8c02fb5c15
commit
e1357dd412
50 files changed
+178
-178
No files matched your search
+2
-2
@@ -35,7 +35,7 @@ export const getAlbumDetail = async(rawId: string, page = 1, limit = 50) => {
|
||||
if (!summary.trackCount || songs.length > summary.trackCount) summary.trackCount = songs.length
|
||||
|
||||
return {
|
||||
source: 'ap' as const,
|
||||
source: 'apple' as const,
|
||||
info: {
|
||||
id: albumId,
|
||||
name: summary.name,
|
||||
@@ -64,7 +64,7 @@ export const getAlbumSongs = async(id: string): Promise<any[]> => {
|
||||
export const parseAlbumLink = async(link: string) => {
|
||||
const detail = await getAlbumDetail(link, 1, 100000)
|
||||
return {
|
||||
source: 'ap' as const,
|
||||
source: 'apple' as const,
|
||||
id: detail.info.id,
|
||||
info: detail.info,
|
||||
list: detail.list,
|
||||
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
// Apple Music 平台模块(上游 music-lib/apple/apple.go 的 Node/TS 移植,平台 id: ap)
|
||||
// Apple Music 平台模块(上游 music-lib/apple/apple.go 的 Node/TS 移植,平台 id: apple)
|
||||
// 能力:搜索 / 歌词(TTML,匿名 developer token 通常拿不到,见 lyric.ts)/ 封面 /
|
||||
// 专辑(搜索+详情+链接解析)/ 歌单(搜索+详情+分类+分类歌单+链接解析)/
|
||||
// 链接解析(song/album/playlist)/ 取流(**仅 preview 试听片段**,见 sdk/apis/apple.ts)。
|
||||
// 凭据:上游 New(cookie) → getCredentials('ap'),cookie 形如
|
||||
// 凭据:上游 New(cookie) → getCredentials('apple'),cookie 形如
|
||||
// "media-user-token=xxx;storefront=cn;token=xxx",也支持 storefront/mediaUserToken/token 直填字段。
|
||||
// 未实现(上游也没有):userPlaylist、榜单、热搜、歌手、评论、扫码登录。
|
||||
import appleApi from '../apis/apple.ts'
|
||||
@@ -72,7 +72,7 @@ const apple = {
|
||||
|
||||
playlist,
|
||||
|
||||
// 契约别名:Apple 的歌单分类即 genre curators,挂到 songList 键供 /song-list/ap 复用
|
||||
// 契约别名:Apple 的歌单分类即 genre curators,挂到 songList 键供 /song-list/apple 复用
|
||||
songList: {
|
||||
sortList: [{ name: '热门', id: '1526756058' }],
|
||||
getTags() {
|
||||
@@ -96,7 +96,7 @@ const apple = {
|
||||
|
||||
/** 登录状态(media-user-token 存在性判断;无在线校验接口) */
|
||||
export const status = () => {
|
||||
const cred = getCredentials('ap') as any
|
||||
const cred = getCredentials('apple') as any
|
||||
const cfg = getAppleConfig()
|
||||
return (cfg.mediaUserToken || cred?.cookie)
|
||||
? { logged: true, updatedAt: cred?.updatedAt }
|
||||
|
||||
@@ -39,7 +39,7 @@ export const search = async(keyword: string, page = 1, limit = 20) => {
|
||||
allPage: hasNext ? p + 1 : p,
|
||||
total: (p - 1) * l + list.length,
|
||||
limit: l,
|
||||
source: 'ap' as const,
|
||||
source: 'apple' as const,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ export const searchAlbum = async(keyword: string, page = 1, limit = 20) => {
|
||||
total: (p - 1) * l + list.length,
|
||||
page: p,
|
||||
limit: l,
|
||||
source: 'ap' as const,
|
||||
source: 'apple' as const,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ export const searchPlaylist = async(keyword: string, page = 1, limit = 20) => {
|
||||
total: (p - 1) * l + list.length,
|
||||
page: p,
|
||||
limit: l,
|
||||
source: 'ap' as const,
|
||||
source: 'apple' as const,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,8 +53,8 @@ export const appleCuratorCategories: Array<{ id: string, name: string }> = [
|
||||
|
||||
/** 上游 GetPlaylistCategories:静态返回 Apple Music genre curators */
|
||||
export const getCategories = async() => ({
|
||||
source: 'ap' as const,
|
||||
list: appleCuratorCategories.map(item => ({ id: item.id, name: item.name, group: 'Apple Music 分类', source: 'ap' as const })),
|
||||
source: 'apple' as const,
|
||||
list: appleCuratorCategories.map(item => ({ id: item.id, name: item.name, group: 'Apple Music 分类', source: 'apple' as const })),
|
||||
})
|
||||
|
||||
/** 上游 GetCategoryPlaylists:按 curator 分类取歌单(cn storefront,单请求上限 25,循环补齐) */
|
||||
@@ -88,7 +88,7 @@ export const getCategoryPlaylists = async(categoryID: string, page = 1, limit =
|
||||
}
|
||||
|
||||
return {
|
||||
source: 'ap' as const,
|
||||
source: 'apple' as const,
|
||||
list: all.slice(0, l),
|
||||
page: p,
|
||||
limit: l,
|
||||
@@ -118,7 +118,7 @@ export const getPlaylistDetail = async(rawId: string, page = 1, limit = 100) =>
|
||||
if (!summary.trackCount || songs.length > summary.trackCount) summary.trackCount = songs.length
|
||||
|
||||
return {
|
||||
source: 'ap' as const,
|
||||
source: 'apple' as const,
|
||||
info: {
|
||||
id: playlistId,
|
||||
name: summary.name,
|
||||
@@ -145,7 +145,7 @@ export const getPlaylistSongs = async(id: string): Promise<any[]> => {
|
||||
export const parsePlaylistLink = async(link: string) => {
|
||||
const detail = await getPlaylistDetail(link, 1, 100000)
|
||||
return {
|
||||
source: 'ap' as const,
|
||||
source: 'apple' as const,
|
||||
id: detail.info.id,
|
||||
info: detail.info,
|
||||
list: detail.list,
|
||||
|
||||
+5
-5
@@ -1,6 +1,6 @@
|
||||
// Apple Music(music.apple.com / amp-api.music.apple.com)公共工具
|
||||
// 上游 music-lib/apple/apple.go 的移植基础层:
|
||||
// - New(cookie) → getCredentials('ap'):cookie 支持 "media-user-token=xxx;storefront=cn;token=xxx"
|
||||
// - New(cookie) → getCredentials('apple'):cookie 支持 "media-user-token=xxx;storefront=cn;token=xxx"
|
||||
// - fetchAppleToken():从 music.apple.com 首页 → index-legacy JS 抓 developer token(amp-api 的 Bearer)
|
||||
// 当前(2026-10)Apple 下发的 JWT 以 eyJ0eXAi({"typ":...})开头而非上游正则写的 eyJh,
|
||||
// 故这里泛化为任意 JWT(eyJ…)并优先选择 issuer=AMPWebPlay 的 token;带回退与失效重取见 getAppleToken/invalidateAppleToken。
|
||||
@@ -42,7 +42,7 @@ export const parseCookieParts = (cookie: string): Record<string, string> => {
|
||||
|
||||
/** 读取 apple 平台运行时配置(对应上游 New(cookie)) */
|
||||
export const getAppleConfig = (): AppleRuntimeConfig => {
|
||||
const cred = (getCredentials('ap') as any) || {}
|
||||
const cred = (getCredentials('apple') as any) || {}
|
||||
const parts = parseCookieParts(String(cred.cookie ?? ''))
|
||||
const storefront = String(cred.storefront || parts.storefront || DEFAULT_STOREFRONT).trim()
|
||||
return {
|
||||
@@ -297,7 +297,7 @@ export const appleSongFromCatalog = (res: any, defaultAlbumId = ''): any => {
|
||||
lrc: null,
|
||||
types: [],
|
||||
_types: {},
|
||||
source: 'ap' as const,
|
||||
source: 'apple' as const,
|
||||
link: attr.url || '', // music.apple.com 网页地址
|
||||
previewUrl: previewURL, // 30-90 秒试听片段直链(Apple 不提供完整曲目明文流)
|
||||
duration: durationSec,
|
||||
@@ -316,7 +316,7 @@ export const appleAlbumToPlaylist = (res: any): any => {
|
||||
creator: attr.artistName || '',
|
||||
description: attr.editorialNotes?.short || '',
|
||||
link: attr.url || '',
|
||||
source: 'ap' as const,
|
||||
source: 'apple' as const,
|
||||
extra: {
|
||||
release_date: attr.releaseDate || '',
|
||||
record_label: attr.recordLabel || '',
|
||||
@@ -340,7 +340,7 @@ export const applePlaylistToPlaylist = (res: any): any => {
|
||||
creator: attr.curatorName || '',
|
||||
description,
|
||||
link: attr.url || '',
|
||||
source: 'ap' as const,
|
||||
source: 'apple' as const,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user