feat(api): 列表接口分页统一 path 段——boards/song-list/singer songs与albums/album 支持可选 /:page,弃用 ?page=
This commit is contained in:
1 parent
baa34a501c
commit
436b102ae2
3 files changed
+69
-47
No files matched your search
@@ -33,12 +33,12 @@ pnpm typecheck # 仅类型检查,不运行
|
||||
| `GET /lyric/:source/:id` | 获取歌词(返回 lyric/tlyric/yrc) |
|
||||
| `GET /pic/:source/:id` | 获取封面 |
|
||||
| `GET /boards/:source` | 榜单列表 |
|
||||
| `GET /boards/:source/:boardId` | 榜单详情 |
|
||||
| `GET /boards/:source/:boardId[/:page]` | 榜单详情(分页 path 段,第 1 页省略) |
|
||||
| `GET /hot-search/:source` | 热搜列表 |
|
||||
| `GET /song-list/:source?page=1` | 歌单列表 |
|
||||
| `GET /song-list/:source[/:page]` | 歌单列表(分页 path 段) |
|
||||
| `GET /singer/:source/:id` | 歌手信息(kg/tx/wy) |
|
||||
| `GET /singer/:source/:id/songs?page=1&limit=30` | 歌手歌曲列表(kg/tx/wy) |
|
||||
| `GET /singer/:source/:id/albums?page=1&limit=10` | 歌手专辑列表(kg/tx/wy) |
|
||||
| `GET /singer/:source/:id/songs[/:page]?limit=30` | 歌手歌曲列表(kg/tx/wy) |
|
||||
| `GET /singer/:source/:id/albums[/:page]?limit=10` | 歌手专辑列表(kg/tx/wy) |
|
||||
| `GET /album/:source/:id?page=1` | 专辑详情与曲目(kg/kw/tx/xm) |
|
||||
| `POST /login/wy/qr` → `POST /login/wy/qr/check` | 网易云扫码登录(扫码后轮询完成登录) |
|
||||
| `POST /login/wy/cellphone` | 网易云手机号登录(password 或 captcha) |
|
||||
|
||||
+53
-38
@@ -334,19 +334,24 @@ export const musicRoutes = async(fastify: any) => {
|
||||
return m.leaderboard.getList(boardId, page).catch(err => { throw upstream(err.message) })
|
||||
}
|
||||
|
||||
fastify.get('/boards/:source/:boardId', {
|
||||
schema: {
|
||||
// 分页列表接口:页码为可选 path 段(第 1 页省略,下一页 /2),与 /search 同构
|
||||
const pagedGet = (url: string, schemaFactory: (withPage: boolean) => any, handler: (request) => any) => {
|
||||
fastify.get(url, { schema: schemaFactory(false) }, handler)
|
||||
fastify.get(`${url}/:page`, { schema: schemaFactory(true) }, handler)
|
||||
}
|
||||
|
||||
const boardDetailSchema = (withPage: boolean) => ({
|
||||
summary: '获取榜单详情',
|
||||
tags: ['榜单'],
|
||||
params: params({
|
||||
source: pSource('boards'),
|
||||
boardId: { type: 'string', description: '榜单 id,兼容榜单列表返回的带前缀 id(kw__93)与裸 bangid(93)', example: 'kw__93' },
|
||||
}),
|
||||
querystring: qs({ page: pPage }),
|
||||
page: pPage,
|
||||
}, withPage ? undefined : ['source', 'boardId']),
|
||||
response: responses('BoardDetailResult'),
|
||||
},
|
||||
}, async(request) => boardHandler(
|
||||
request.params.source, request.params.boardId, request.query.page,
|
||||
})
|
||||
pagedGet('/boards/:source/:boardId', boardDetailSchema, async(request) => boardHandler(
|
||||
request.params.source, request.params.boardId, Number(request.params.page) || 1,
|
||||
))
|
||||
|
||||
// ---------- 歌单 & 热搜 ----------
|
||||
@@ -369,21 +374,23 @@ export const musicRoutes = async(fastify: any) => {
|
||||
return m.songList.getList(sortId ?? m.songList.sortList?.[0]?.id, tagId, page).catch(err => { throw upstream(err.message) })
|
||||
}
|
||||
|
||||
fastify.get('/song-list/:source', {
|
||||
schema: {
|
||||
const songListSchema = (withPage: boolean) => ({
|
||||
summary: '获取歌单列表',
|
||||
tags: ['歌单'],
|
||||
params: params({ source: pSource('songList') }),
|
||||
querystring: qs({
|
||||
params: params({
|
||||
source: pSource('songList'),
|
||||
page: pPage,
|
||||
}, withPage ? undefined : ['source']),
|
||||
querystring: qs({
|
||||
limit: pLimit,
|
||||
sortId: { type: ['integer', 'string'], description: '排序 id(平台相关,见 /sources 对应平台文档;省略时用平台默认)' },
|
||||
tagId: { type: ['integer', 'string'], description: '标签 id(平台相关,kw 为 `173-digest` 形态字符串;0 为全部)' },
|
||||
}),
|
||||
response: responses('SongListResult'),
|
||||
},
|
||||
}, async(request) => {
|
||||
const { page, sortId, tagId } = request.query
|
||||
return songListHandler(request.params.source, page, sortId, tagId)
|
||||
})
|
||||
pagedGet('/song-list/:source', songListSchema, async(request) => {
|
||||
const { sortId, tagId } = request.query
|
||||
return songListHandler(request.params.source, Number(request.params.page) || 1, sortId, tagId)
|
||||
})
|
||||
|
||||
// ---------- 歌手 & 专辑 ----------
|
||||
@@ -402,50 +409,58 @@ export const musicRoutes = async(fastify: any) => {
|
||||
.getInfo(id).catch(err => { throw upstream(err.message) })
|
||||
})
|
||||
|
||||
fastify.get('/singer/:source/:id/songs', {
|
||||
schema: {
|
||||
const singerSongsSchema = (withPage: boolean) => ({
|
||||
summary: '获取歌手歌曲列表',
|
||||
description: '支持 kg/tx/wy。',
|
||||
tags: ['歌手专辑'],
|
||||
params: params({ source: pSource('singer'), id: { type: 'string', description: '平台歌手 id' } }),
|
||||
querystring: qs({ page: pPage, limit: pLimit }),
|
||||
params: params({
|
||||
source: pSource('singer'),
|
||||
id: { type: 'string', description: '平台歌手 id' },
|
||||
page: pPage,
|
||||
}, withPage ? undefined : ['source', 'id']),
|
||||
querystring: qs({ limit: pLimit }),
|
||||
response: responses('SingerSongListResult'),
|
||||
},
|
||||
}, async(request) => {
|
||||
})
|
||||
pagedGet('/singer/:source/:id/songs', singerSongsSchema, async(request) => {
|
||||
const { source, id } = request.params
|
||||
const { page, limit } = request.query
|
||||
return getSource(musicSdk, source, 'singer').singer
|
||||
.getSongList(id, page, limit).catch(err => { throw upstream(err.message) })
|
||||
.getSongList(id, Number(request.params.page) || 1, request.query.limit).catch(err => { throw upstream(err.message) })
|
||||
})
|
||||
|
||||
fastify.get('/singer/:source/:id/albums', {
|
||||
schema: {
|
||||
const singerAlbumsSchema = (withPage: boolean) => ({
|
||||
summary: '获取歌手专辑列表',
|
||||
description: '支持 kg/tx/wy。',
|
||||
tags: ['歌手专辑'],
|
||||
params: params({ source: pSource('singer'), id: { type: 'string', description: '平台歌手 id' } }),
|
||||
querystring: qs({ page: pPage, limit: pLimit }),
|
||||
params: params({
|
||||
source: pSource('singer'),
|
||||
id: { type: 'string', description: '平台歌手 id' },
|
||||
page: pPage,
|
||||
}, withPage ? undefined : ['source', 'id']),
|
||||
querystring: qs({ limit: pLimit }),
|
||||
response: responses('SingerAlbumListResult'),
|
||||
},
|
||||
}, async(request) => {
|
||||
})
|
||||
pagedGet('/singer/:source/:id/albums', singerAlbumsSchema, async(request) => {
|
||||
const { source, id } = request.params
|
||||
const { page, limit } = request.query
|
||||
return getSource(musicSdk, source, 'singer').singer
|
||||
.getAlbumList(id, page, limit).catch(err => { throw upstream(err.message) })
|
||||
.getAlbumList(id, Number(request.params.page) || 1, request.query.limit).catch(err => { throw upstream(err.message) })
|
||||
})
|
||||
|
||||
fastify.get('/album/:source/:id', {
|
||||
schema: {
|
||||
const albumSchema = (withPage: boolean) => ({
|
||||
summary: '获取专辑详情与曲目列表',
|
||||
description: '支持 kg/kw/tx/xm/me(见 /sources 的 album 能力位)。kw 单页固定 1000 条、xm/me 固定 30 条、limit 不生效。',
|
||||
tags: ['歌手专辑'],
|
||||
params: params({ source: pSource('album'), id: { type: 'string', description: '平台专辑 id(搜索结果中的 albumId)' } }),
|
||||
querystring: qs({ page: pPage, limit: pLimit }),
|
||||
params: params({
|
||||
source: pSource('album'),
|
||||
id: { type: 'string', description: '平台专辑 id(搜索结果中的 albumId)' },
|
||||
page: pPage,
|
||||
}, withPage ? undefined : ['source', 'id']),
|
||||
querystring: qs({ limit: pLimit }),
|
||||
response: responses('AlbumDetailResult'),
|
||||
},
|
||||
}, async(request) => {
|
||||
})
|
||||
pagedGet('/album/:source/:id', albumSchema, async(request) => {
|
||||
const { source, id } = request.params
|
||||
const { page, limit } = request.query
|
||||
const { limit } = request.query
|
||||
const page = Number(request.params.page) || 1
|
||||
const album = getSource(musicSdk, source, 'album').album
|
||||
// 各平台适配器签名不同:kg 为 getAlbumDetail(id, page, limit),
|
||||
// kw 为 getAlbumListDetail(id, page)——第三参数是 retryNum,不能透传 limit
|
||||
|
||||
+12
-5
@@ -355,12 +355,19 @@ await test('平台列表 /sources', async() => {
|
||||
|
||||
await test('榜单详情 路径风格 /boards/:source/:boardId', async() => {
|
||||
// 用列表返回的带前缀 id(回归:详情接口应自动归一化为裸 bangid)
|
||||
const r = await get('/boards/kw/kw__93?page=1')
|
||||
const r = await get('/boards/kw/kw__93')
|
||||
if (r.code != 0) throw new Error(r.msg)
|
||||
if (!r.data?.list?.length) throw new Error('空列表')
|
||||
return `${r.data.list.length} 首`
|
||||
})
|
||||
|
||||
// 列表接口分页 path 段(pagedGet 风格:第 1 页省略段,下一页 /2)
|
||||
await test('榜单分页 /boards/:source/:boardId/:page', async() => {
|
||||
const r = await get('/boards/kw/kw__93/2')
|
||||
if (r.code != 0) throw new Error(r.msg)
|
||||
return `${r.data?.list?.length} 首(第 2 页)`
|
||||
})
|
||||
|
||||
await test('跨平台匹配 /find', async() => {
|
||||
const r = await get(`/find/all/${encodeURIComponent('稻香')}?singer=${encodeURIComponent('周杰伦')}`)
|
||||
if (r.code != 0) throw new Error(r.msg)
|
||||
@@ -369,14 +376,14 @@ await test('跨平台匹配 /find', async() => {
|
||||
})
|
||||
|
||||
await test('歌单 路径风格 /song-list/:source', async() => {
|
||||
const r = await get('/song-list/kg?page=1')
|
||||
const r = await get('/song-list/kg')
|
||||
if (r.code != 0) throw new Error(r.msg)
|
||||
if (!r.data?.list?.length) throw new Error('空列表')
|
||||
return `${r.data.list.length} 个歌单`
|
||||
})
|
||||
|
||||
await test('歌单 默认排序 /song-list/kw', async() => {
|
||||
const r = await get('/song-list/kw?page=1')
|
||||
const r = await get('/song-list/kw')
|
||||
if (r.code != 0) throw new Error(r.msg)
|
||||
if (!r.data?.list?.length) throw new Error('空列表(sortId 默认值未适配平台)')
|
||||
return `${r.data.list.length} 个歌单`
|
||||
@@ -406,14 +413,14 @@ await test('歌手信息 /singer/tx', async() => {
|
||||
})
|
||||
|
||||
await test('歌手歌曲 /singer/tx/:id/songs', async() => {
|
||||
const r = await get('/singer/tx/0025NhlN2yWrP4/songs?page=1&limit=3')
|
||||
const r = await get('/singer/tx/0025NhlN2yWrP4/songs?limit=3')
|
||||
if (r.code != 0) throw new Error(r.msg)
|
||||
if (!r.data?.list?.length) throw new Error('空列表')
|
||||
return `${r.data.list.length} 首 / 共 ${r.data.total}`
|
||||
})
|
||||
|
||||
await test('歌手专辑 /singer/kg/:id/albums', async() => {
|
||||
const r = await get('/singer/kg/3062/albums?page=1&limit=3')
|
||||
const r = await get('/singer/kg/3062/albums?limit=3')
|
||||
if (r.code != 0) throw new Error(r.msg)
|
||||
if (!r.data?.list?.length) throw new Error('空列表')
|
||||
return `${r.data.list.length} 张`
|
||||
|
||||
Reference in new issue
Block a user