From ddc44a276dfac13e4cbab4daac4accab1bd27ca8 Mon Sep 17 00:00:00 2001 From: snowy-yang <102860110+snowy-yang@users.noreply.github.com> Date: Thu, 1 Oct 2026 22:43:29 +0800 Subject: [PATCH] =?UTF-8?q?fix(kg):=20/v5/url=20=E6=88=90=E5=8A=9F?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E6=8C=89=E9=A1=B6=E5=B1=82=20url/backupUrl?= =?UTF-8?q?=20=E6=95=B0=E7=BB=84=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 网关成功(status:1)时播放地址在顶层 url: string[] 与 backupUrl: string[], 并非旧 data:[{url}] 结构,导致 VIP 登录后所有取流仍报"获取失败"; 旧结构保留为兜底。album_audio_id/album_id 加 Number.isFinite 守卫—— /url 路由把 hash 传给 songmid 时 Number(hash)=NaN 会被网关拒答。 实测珊瑚海四档(VIP)全通,320k/flac/hi-res 与曲库大小逐字节吻合。 --- sdk/apis/kg.ts | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/sdk/apis/kg.ts b/sdk/apis/kg.ts index 977ffb5..a84ead2 100644 --- a/sdk/apis/kg.ts +++ b/sdk/apis/kg.ts @@ -2,6 +2,8 @@ // 接口: https://gateway.kugou.com/v5/url(x-router: trackercdn.kugou.com,android 签名) // 登录后自动携带 token/userid(见 /login/kg);匿名仅能获取部分免费资源, // VIP/受限资源会返回 status:2。quality: 128k→128, 320k→320, flac→flac, flac24bit→high +// 成功响应(status:1)播放地址在顶层 url: string[] 与 backupUrl: string[](2026-10 实测; +// 旧 data:[{url}] 结构仅作兼容兜底)。album_audio_id 传 NaN 会被网关拒答,必须归零。 // 统一接口约定:apis('kg').getMusicUrl(songInfo, type) → { promise, cancelHttp } // promise resolve → { type, url } @@ -15,6 +17,8 @@ const SALT_KEY = '57ae12eb6890223e355ccfcb74edf70d' const APPID = 1005 const CLIENTVER = 11430 +const num = (v: any) => { const n = Number(v); return Number.isFinite(n) ? n : 0 } + const qualityMap = { '128k': '128', '320k': '320', flac: 'flac', flac24bit: 'high' } // 官方直连接口支持的音质(sdk/index.ts 汇总为 supportQuality) @@ -38,14 +42,14 @@ export const getMusicUrl = (songInfo, type) => { const params: Record = { dfid: dev.dfid, mid: dev.mid, uuid: '-', appid: APPID, clientver: CLIENTVER, clienttime: Math.floor(Date.now() / 1000), - album_id: Number(songInfo.albumId ?? 0), + album_id: num(songInfo.albumId), area_code: 1, hash, ssa_flag: 'is_fromtrack', version: CLIENTVER, page_id: 151369488, quality: qualityMap[type] ?? '128', - album_audio_id: Number(songInfo.songmid ?? 0), + album_audio_id: num(songInfo.songmid), behavior: 'play', pid: 2, cmd: 26, @@ -75,12 +79,18 @@ export const getMusicUrl = (songInfo, type) => { }).promise const body = r.body && typeof r.body === 'object' ? r.body : {} - if (body.status !== 1 || !Array.isArray(body.data)) { - throw new Error(body.error || (auth ? '获取失败' : '获取失败(该资源需要酷狗登录)')) + if (body.status !== 1) { + throw new Error(body.error || (auth ? `获取失败(status ${body.status ?? '未知'})` : '获取失败(该资源需要酷狗登录)')) } - const item = body.data.find(d => d.url) ?? body.data[0] - const url = item?.url || item?.fallback - if (!url) throw new Error('获取失败') + let url = '' + if (Array.isArray(body.url)) url = body.url[0] || '' + else if (Array.isArray(body.backupUrl)) url = body.backupUrl[0] || '' + else if (Array.isArray(body.data)) { + // 旧版 data:[{url, fallback}] 结构兜底 + const item = body.data.find(d => d.url) ?? body.data[0] + url = item?.url || item?.fallback || '' + } + if (!url) throw new Error('获取失败(网关未返回播放地址)') return { type, url } })() return requestObj