From 8c02fb5c15cc337e715ccc5b16803084b41b07f9 Mon Sep 17 00:00:00 2001 From: snowy-yang <102860110+snowy-yang@users.noreply.github.com> Date: Sat, 3 Oct 2026 20:48:54 +0800 Subject: [PATCH] =?UTF-8?q?refactor(sdk):=20=E5=AE=A1=E8=AE=A1=20P2=20?= =?UTF-8?q?=E5=8D=AB=E7=94=9F=E9=A1=B9=E6=B8=85=E7=90=86=E2=80=94=E2=80=94?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E5=B1=82=E6=94=B6=E6=95=9B=E4=B8=8E=E6=AD=BB?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=B8=85=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除旧 sdk/request.ts,全部 import 收敛到 sdk/common/request.ts(85 文件) - 注释死代码 630+ 行、裸 console.log 吞错 6 处、未使用符号 26 处清零 - bili 状态校验去重;utils DNS 预解析失败日志改 warn 带上下文 - CODE-AUDIT.md:第四节 P2 清理记录 + 第八节线索逐条复核结论(kw/kg/tx/wy parse 骨架相似实质各异,不抽公共层) --- CODE-AUDIT.md | 4 +- sdk/5sing/util.ts | 2 +- sdk/apis/joox.ts | 2 +- sdk/apis/lr.ts | 2 +- sdk/apis/me.ts | 2 +- sdk/apis/migu.ts | 13 +--- sdk/apple/util.ts | 2 +- sdk/auth/kg.ts | 1 - sdk/bili/util.ts | 28 ++++---- sdk/common/utils.ts | 2 +- sdk/index.ts | 4 -- sdk/joox/album.ts | 2 +- sdk/joox/lyric.ts | 2 +- sdk/joox/musicInfo.ts | 2 +- sdk/joox/musicSearch.ts | 4 +- sdk/joox/parse.ts | 4 +- sdk/joox/playlist.ts | 2 +- sdk/joox/util.ts | 2 +- sdk/kg/album.ts | 2 +- sdk/kg/comment.ts | 6 +- sdk/kg/hotSearch.ts | 3 +- sdk/kg/leaderboard.ts | 25 +------ sdk/kg/lyric.ts | 26 +------ sdk/kg/musicInfo.ts | 1 - sdk/kg/musicSearch.ts | 2 +- sdk/kg/parse.ts | 2 +- sdk/kg/pic.ts | 2 +- sdk/kg/playlist.ts | 2 +- sdk/kg/songList.ts | 147 +------------------------------------- sdk/kg/util.ts | 6 +- sdk/kw/album.ts | 34 +-------- sdk/kw/comment.ts | 4 +- sdk/kw/hotSearch.ts | 3 +- sdk/kw/index.ts | 22 +----- sdk/kw/leaderboard.ts | 26 +------ sdk/kw/lyric.ts | 152 +--------------------------------------- sdk/kw/musicSearch.ts | 12 +--- sdk/kw/parse.ts | 2 +- sdk/kw/pic.ts | 2 +- sdk/kw/songList.ts | 10 +-- sdk/kw/util.ts | 67 ------------------ sdk/lr/appApi.ts | 2 +- sdk/lr/auth.ts | 2 +- sdk/lr/index.ts | 4 +- sdk/lr/menu.ts | 2 +- sdk/me/album.ts | 2 +- sdk/me/musicSearch.ts | 2 +- sdk/me/sign.ts | 2 +- sdk/migu/lyric.ts | 4 +- sdk/migu/util.ts | 3 +- sdk/qian/lyric.ts | 2 +- sdk/qian/util.ts | 2 +- sdk/qs/musicInfo.ts | 2 +- sdk/qt/http.ts | 2 +- sdk/request.ts | 5 -- sdk/tx/album.ts | 2 +- sdk/tx/comment.ts | 4 +- sdk/tx/hotSearch.ts | 4 +- sdk/tx/leaderboard.ts | 26 +------ sdk/tx/lyric.ts | 36 +--------- sdk/tx/musicInfo.ts | 5 +- sdk/tx/musicSearch.ts | 14 ---- sdk/tx/parse.ts | 2 +- sdk/tx/playlist.ts | 2 +- sdk/tx/songList.ts | 8 +-- sdk/tx/userPlaylist.ts | 2 +- sdk/tx/utils/index.ts | 8 +-- sdk/utils.ts | 2 +- sdk/wy/album.ts | 2 +- sdk/wy/comment.ts | 3 +- sdk/wy/leaderboard.ts | 27 +------ sdk/wy/lyric.ts | 77 +------------------- sdk/wy/musicDetail.ts | 5 +- sdk/wy/musicInfo.ts | 3 +- sdk/wy/musicSearch.ts | 5 +- sdk/wy/parse.ts | 2 +- sdk/wy/playlist.ts | 2 +- sdk/wy/songList.ts | 14 +--- sdk/wy/userPlaylist.ts | 2 +- sdk/wy/utils/index.ts | 10 +-- sdk/xm/album.ts | 2 +- sdk/xm/musicInfo.ts | 2 +- sdk/xm/musicSearch.ts | 2 +- sdk/xm/sign.ts | 2 +- src/routes-login.ts | 2 +- 85 files changed, 112 insertions(+), 839 deletions(-) delete mode 100644 sdk/request.ts diff --git a/CODE-AUDIT.md b/CODE-AUDIT.md index 1bbbe10..e90a177 100644 --- a/CODE-AUDIT.md +++ b/CODE-AUDIT.md @@ -2,7 +2,9 @@ **检查时间**:2026-10-03 **修复状态**(复查后更新):P0-1 ~ P0-3、P1-4 ~ P1-16 **全部已修复**(含测试隔离与 isolated-vm 原生构建); -第五节「文档与代码不一致」已按 `/sources` 与路由实现逐条校准;第八节列出的未复核线索与第四节 P2 项**未动**,留待后续。 +第四节 P2 卫生项已于 2026-10-03 清理完毕(注释死代码 630+ 行、裸 `console.log` 吞错 6 处、未使用符号 26 处清零、bili 状态校验去重); +第八节线索逐条复核:qian 导出名、migu 异常消息、Quality `preview`、bili 重试重复均已过时(早前重写时已解决),kw/kg/tx/wy parse/playlist 仅有骨架相似、实质各异,评估后不抽公共层。 +第五节「文档与代码不一致」已按 `/sources` 与路由实现逐条校准。 各条的修复要点见下文对应条目。 **检查范围**:`src/`(15 文件 / 3,103 行)、`sdk/`(173 文件 / 21,919 行)、`test/`(2 文件 / 1,081 行),共约 26,100 行 TypeScript diff --git a/sdk/5sing/util.ts b/sdk/5sing/util.ts index 2fa4e0b..830c57e 100644 --- a/sdk/5sing/util.ts +++ b/sdk/5sing/util.ts @@ -4,7 +4,7 @@ // 上游 New(cookie) 的 cookie 实际参与请求(搜索/getSongUrl/newget/歌单页), // 这里按约定从 sdk/auth/store.ts 的 getCredentials('5s') 读取(无则匿名)。 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { getCredentials } from '../auth/store.ts' export const UserAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36' diff --git a/sdk/apis/joox.ts b/sdk/apis/joox.ts index 00e8e34..4d09a25 100644 --- a/sdk/apis/joox.ts +++ b/sdk/apis/joox.ts @@ -10,7 +10,7 @@ // 统一接口约定:apis('jx').getMusicUrl(songInfo, type) → { promise, cancelHttp } // promise resolve → { type, url }(type 为实际命中档位,可能低于请求值) -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { jooxHeaders, normalizeJooxID } from '../joox/util.ts' import { buildTrackUrl } from '../joox/musicInfo.ts' diff --git a/sdk/apis/lr.ts b/sdk/apis/lr.ts index d1836c4..4b7f2c0 100644 --- a/sdk/apis/lr.ts +++ b/sdk/apis/lr.ts @@ -3,7 +3,7 @@ // 实测(2026-10-02):免费章节匿名也返回 status=2 "收费章节未购买"——必须携带 /login/lr 登录会话; // 成功响应 list[0].path 为音频直链。 // songmid 为复合 id ":
"(/album/lr 章节列表产出);纯 bookId 视为第一章 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { getLrCookie } from '../lr/auth.ts' const UA_MI = 'Mozilla/5.0 (Linux; U; Android 4.1.1; zh-cn; MI2 Build/JRO03L) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0' diff --git a/sdk/apis/me.ts b/sdk/apis/me.ts index af0c09c..9b3754a 100644 --- a/sdk/apis/me.ts +++ b/sdk/apis/me.ts @@ -32,7 +32,7 @@ const pickUrl = (info: any, type: string) => { /** 剧条目 "d:" → 首个免费集的 sound_id(getdrama episodes.episode[]) */ const resolveDramaFirstFree = async(dramaId: string): Promise => { - const { httpFetch } = await import('../request.ts') + const { httpFetch } = await import('../common/request.ts') const { statusCode, body } = await httpFetch(`https://www.missevan.com/dramaapi/getdrama?drama_id=${dramaId}`, { headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36', diff --git a/sdk/apis/migu.ts b/sdk/apis/migu.ts index eb4441e..50718a3 100644 --- a/sdk/apis/migu.ts +++ b/sdk/apis/migu.ts @@ -2,9 +2,9 @@ // 命中可访问的最高档位;匿名仅 PQ(128k) 可用,HQ/SQ/ZQ 各档需登录 Cookie。 // 上游对应:music-lib/migu/download.go(GetDownloadInfo / buildMiguDownloadCandidates / // selectHighestValidDownload / rewriteMiguToneURL / embeddedDownloadInfoFromResponse) -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { - AndroidChannel, AndroidUA, AndroidVersion, buildUrl, decryptZ3D, firstNonEmpty, + AndroidChannel, AndroidUA, AndroidVersion, decryptZ3D, firstNonEmpty, getMiguCookie, isMiguAudioMagic, miguFormatExt, TONE_QUALITY, type MiguSongItem, } from '../migu/util.ts' @@ -112,15 +112,6 @@ const normalizeDownloadURL = (rawURL?: string | null): string => { return url } -const isEncryptedDirectURL = (rawURL: string): boolean => { - try { - const decodedPath = decodeURIComponent(new URL(rawURL).pathname) - return decodedPath.includes('wav_3d/') && !decodedPath.includes('wav_3d_60s/') - } catch { - return false - } -} - interface DownloadInfo { url: string format: string diff --git a/sdk/apple/util.ts b/sdk/apple/util.ts index 3fd157d..feeb8ea 100644 --- a/sdk/apple/util.ts +++ b/sdk/apple/util.ts @@ -7,7 +7,7 @@ // - ampGet/ampHeaders:amp-api 请求(httpFetch 不自动跟 302,首页跳转用 fetchFollow 手动跟) // - 模型转换:appleSongFromCatalog / appleAlbumToPlaylist / applePlaylistToPlaylist(字段映射同上游) // - ID 提取:extractAppleID / extractAppleIDFromPath / isAppleRawID(apple_test.go 的断言全部逐条保留) -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { formatPlayTime } from '../common/utils.ts' import { getCredentials } from '../auth/store.ts' diff --git a/sdk/auth/kg.ts b/sdk/auth/kg.ts index a62896e..911ee39 100644 --- a/sdk/auth/kg.ts +++ b/sdk/auth/kg.ts @@ -11,7 +11,6 @@ import { generateSimulate } from './kgSimulate.ts' import type { KgCredentials } from './store.ts' const md5 = s => crypto.createHash('md5').update(s).digest('hex') -const SALT_KEY = '57ae12eb6890223e355ccfcb74edf70d' const SALT_SIGN = 'OIlwieks28dk2k092lksi2UIkp' const APPID = 1005 const CLIENTVER = 11430 diff --git a/sdk/bili/util.ts b/sdk/bili/util.ts index aa46060..3587fb6 100644 --- a/sdk/bili/util.ts +++ b/sdk/bili/util.ts @@ -157,24 +157,28 @@ export const makeSong = ({ bvid, cid, name, artist, album, duration, cover, page // ---- 视频/分P/合集接口(上游 bilibili.go 各 fetch* 的对应实现) ---- +/** B 站 API 统一校验:HTTP 200 且业务码 code=0,否则抛带上下文的错误 */ +const assertApiOk = (what: string, statusCode: number, body: any): void => { + if (statusCode !== 200 || !body || body.code !== 0) { + throw new Error(`B站${what}获取失败(${body?.code ?? `HTTP ${statusCode}`}${body?.message ? `: ${body.message}` : ''})`) + } +} + /** 视频详情(x/web-interface/view);bvid 或 aid 均可,返回 data 节点 */ export const fetchView = async(id: string): Promise => { const raw = String(id || '').trim() if (!raw) throw new Error('B站视频 id 为空') const query = /^BV/i.test(raw) ? `bvid=${encodeURIComponent(raw)}` : `aid=${encodeURIComponent(raw.replace(/^av/i, ''))}` const { statusCode, body } = await apiGet(`https://api.bilibili.com/x/web-interface/view?${query}`) - if (statusCode !== 200 || !body || body.code !== 0 || !body.data) { - throw new Error(`B站视频信息获取失败(${body?.code ?? `HTTP ${statusCode}`}${body?.message ? `: ${body.message}` : ''})`) - } + assertApiOk('视频信息', statusCode, body) + if (!body.data) throw new Error('B站视频信息获取失败(data 为空)') return body.data } /** 分P列表(x/player/pagelist),返回 data 数组 */ export const fetchPageList = async(bvid: string): Promise => { const { statusCode, body } = await apiGet(`https://api.bilibili.com/x/player/pagelist?bvid=${encodeURIComponent(bvid)}`) - if (statusCode !== 200 || !body || body.code !== 0) { - throw new Error(`B站分P列表获取失败(${body?.code ?? `HTTP ${statusCode}`}${body?.message ? `: ${body.message}` : ''})`) - } + assertApiOk('分P列表', statusCode, body) return body.data ?? [] } @@ -188,10 +192,8 @@ export const fetchSeasonArchiveIndex = async(mid: string | number, seasonId: str let pageNum = 1 const pageSize = 30 for (;;) { - const { body } = await apiGet(`https://api.bilibili.com/x/space/ugc/season?mid=${mid}&season_id=${seasonId}&page_num=${pageNum}&page_size=${pageSize}`) - if (!body || body.code !== 0) { - throw new Error(`B站合集信息获取失败(${body?.code ?? '非 JSON 响应'}${body?.message ? `: ${body.message}` : ''})`) - } + const { statusCode, body } = await apiGet(`https://api.bilibili.com/x/space/ugc/season?mid=${mid}&season_id=${seasonId}&page_num=${pageNum}&page_size=${pageSize}`) + assertApiOk('合集信息', statusCode, body) if (!seasonTitle) seasonTitle = body.data?.season?.title || '' if (!seasonCover) seasonCover = body.data?.season?.cover || '' const archives = body.data?.archives ?? [] @@ -276,10 +278,8 @@ export const fetchSeasonSongs = async(mid: string | number, seasonId: string | n let pageNum = 1 const pageSize = 30 for (;;) { - const { body } = await apiGet(`https://api.bilibili.com/x/space/ugc/season?mid=${mid}&season_id=${seasonId}&page_num=${pageNum}&page_size=${pageSize}`) - if (!body || body.code !== 0) { - throw new Error(`B站合集列表获取失败(${body?.code ?? '非 JSON 响应'}${body?.message ? `: ${body.message}` : ''})`) - } + const { statusCode, body } = await apiGet(`https://api.bilibili.com/x/space/ugc/season?mid=${mid}&season_id=${seasonId}&page_num=${pageNum}&page_size=${pageSize}`) + assertApiOk('合集列表', statusCode, body) if (!seasonTitle) seasonTitle = body.data?.season?.title || '' if (!seasonCover) seasonCover = body.data?.season?.cover || '' const archives = body.data?.archives ?? [] diff --git a/sdk/common/utils.ts b/sdk/common/utils.ts index 2ae0699..3c3986b 100644 --- a/sdk/common/utils.ts +++ b/sdk/common/utils.ts @@ -97,5 +97,5 @@ export const decodeName = (str = '') => { .replace(/'/g, "'") .replace(/'/g, "'") .replace(/ /g, ' ') - .replace(/&#(\d+);/g, (match, num) => String.fromCharCode(parseInt(num))) + .replace(/&#(\d+);/g, (_, num) => String.fromCharCode(parseInt(num))) } diff --git a/sdk/index.ts b/sdk/index.ts index 2fa1a8e..02650e3 100644 --- a/sdk/index.ts +++ b/sdk/index.ts @@ -176,10 +176,6 @@ export const findMusic = async ( const isEqualsInterval = (intv: number) => Math.abs((fInterval || intv) - (intv || fInterval)) < 5 - const isIncludesName = (n: string) => fMusicName.includes(n) || n.includes(fMusicName) - const isIncludesSinger = (sng: string) => - fSinger ? fSinger.includes(sng) || sng.includes(fSinger) : true - const isEqualsAlbum = (alb: string) => (fAlbumName ? fAlbumName === alb : true) let candidates: MatchCandidate[] = [] for (const source of lists) { diff --git a/sdk/joox/album.ts b/sdk/joox/album.ts index 1ee5de2..ad73c65 100644 --- a/sdk/joox/album.ts +++ b/sdk/joox/album.ts @@ -5,7 +5,7 @@ // 兜底:www.joox.com//album/ SSR __NEXT_DATA__.props.pageProps.albumData(上游做法,需 X-Forwarded-For) // 链接解析:ParseAlbum 的正则与裸 ID 规则同上游。 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { jooxHeaders, jooxSign, diff --git a/sdk/joox/lyric.ts b/sdk/joox/lyric.ts index bb85cc5..d6c8344 100644 --- a/sdk/joox/lyric.ts +++ b/sdk/joox/lyric.ts @@ -6,7 +6,7 @@ // 解码:base64 → UTF-8 → HTML 实体(& 等)→ { lyric, tlyric: '' } // 统一接口约定:{ promise, cancelHttp };promise resolve → { lyric, tlyric } -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { jooxHeaders, decodeJooxLyric, normalizeJooxID, firstNonEmpty } from './util.ts' import { buildTrackUrl } from './musicInfo.ts' diff --git a/sdk/joox/musicInfo.ts b/sdk/joox/musicInfo.ts index 64fd1e3..01c3b75 100644 --- a/sdk/joox/musicInfo.ts +++ b/sdk/joox/musicInfo.ts @@ -9,7 +9,7 @@ // 返回体含 play_url_list / refrain_url / lrc_content(base64) / qrc_content(base64) / // has_hq / has_hifi / vip_flag / node_is_preview 等。 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { jooxHeaders, jooxSign, diff --git a/sdk/joox/musicSearch.ts b/sdk/joox/musicSearch.ts index be708f0..50cd00f 100644 --- a/sdk/joox/musicSearch.ts +++ b/sdk/joox/musicSearch.ts @@ -4,13 +4,13 @@ // 该接口无分页参数(上游也未分页),page 参数仅为统一契约保留;allPage 恒为 1。 // 实测(2026-10-02):英文/中文关键词均 HTTP 200。 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { jooxHeaders } from './util.ts' import { jooxSongFromSearch } from './song.ts' const SEARCH_URL = 'https://cache.api.joox.com/openjoox/v3/search' -export const search = async(keyword: string, page = 1, limit = 20) => { +export const search = async(keyword: string, _page = 1, limit = 20) => { const url = `${SEARCH_URL}?country=sg&lang=zh_cn&keyword=${encodeURIComponent(String(keyword ?? ''))}` const { statusCode, body } = await httpFetch(url, { headers: jooxHeaders(), timeout: 20000 }).promise as any if (statusCode != 200 || !body?.section_list) { diff --git a/sdk/joox/parse.ts b/sdk/joox/parse.ts index b5c925f..6122c8f 100644 --- a/sdk/joox/parse.ts +++ b/sdk/joox/parse.ts @@ -6,8 +6,8 @@ import { normalizeJooxID } from './util.ts' import { getTrackDetail, pickTrackUrl } from './musicInfo.ts' import { jooxSongFromDetail } from './song.ts' -import { getAlbumDetail, parseAlbum } from './album.ts' -import { getPlaylistDetail, parsePlaylist } from './playlist.ts' +import { parseAlbum } from './album.ts' +import { parsePlaylist } from './playlist.ts' /** 歌曲链接 → Song(上游 Parse 的正则与裸 ID 规则) */ export const parseSong = async(link: string) => { diff --git a/sdk/joox/playlist.ts b/sdk/joox/playlist.ts index 1edafdc..bf75d48 100644 --- a/sdk/joox/playlist.ts +++ b/sdk/joox/playlist.ts @@ -7,7 +7,7 @@ // 分类:www.joox.com/sg/playlist(302 → / 首页)__NEXT_DATA__.props.pageProps.mlList // 链接解析:joox.com/{region}/playlist/、playlistid/id 查询参数、裸 ID -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { jooxHeaders, jooxSign, diff --git a/sdk/joox/util.ts b/sdk/joox/util.ts index 70b3b36..b25ed56 100644 --- a/sdk/joox/util.ts +++ b/sdk/joox/util.ts @@ -11,7 +11,7 @@ // 在签名参数里作为 uid/usk 参与(可拿到完整曲目/更高档位)。 import crypto from 'node:crypto' -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { getCredentials } from '../auth/store.ts' export const JOOX_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36' diff --git a/sdk/kg/album.ts b/sdk/kg/album.ts index cc0886c..c35426d 100644 --- a/sdk/kg/album.ts +++ b/sdk/kg/album.ts @@ -1,6 +1,6 @@ import { getMusicInfosByList } from './musicInfo.ts' import { createHttpFetch } from './util.ts' -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' const albumCover = (url: any): string => String(url ?? '').replace('{size}', '240') diff --git a/sdk/kg/comment.ts b/sdk/kg/comment.ts index 15297c4..7b18609 100644 --- a/sdk/kg/comment.ts +++ b/sdk/kg/comment.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { decodeName, dateFormat2 } from '../index.ts' import { signatureParams } from './util.ts' // import { getMusicInfoRaw } from './musicInfo.ts' @@ -22,13 +22,11 @@ export default { }, }) const { body, statusCode } = await _requestObj.promise - // console.log(body) if (statusCode != 200 || body.err_code !== 0) throw new Error('获取评论失败') const total = body.count ?? 0 return { source: 'kg', comments: this.filterComment(body.list || []), total, page, limit, maxPage: Math.ceil(total / limit) || 1 } }, async getHotComment({ hash }, page = 1, limit = 20) { - // console.log(songmid) if (this._requestObj2) this._requestObj2.cancelHttp() let timestamp = Date.now() const params = `dfid=0&mid=16249512204336365674023395779019&clienttime=${timestamp}&uuid=0&extdata=${hash}&appid=1005&code=fc4be23b4e972707f36b8a828a93ba8a&schash=${hash}&clientver=11409&p=${page}&clienttoken=&pagesize=${limit}&ver=10&kugouid=0` @@ -39,7 +37,6 @@ export default { }, }) const { body, statusCode } = await _requestObj2.promise - // console.log(body) if (statusCode != 200 || body.err_code !== 0) throw new Error('获取热门评论失败') const total = body.count ?? 0 return { source: 'kg', comments: this.filterComment(body.list || []), total, page, limit, maxPage: Math.ceil(total / limit) || 1 } @@ -57,7 +54,6 @@ export default { }, }) const { body, statusCode } = await _requestObj2.promise - // console.log(body) if (statusCode != 200 || body.err_code !== 0) throw new Error('获取回复评论失败') return { source: 'kg', comments: this.filterComment(body.list || []) } }, diff --git a/sdk/kg/hotSearch.ts b/sdk/kg/hotSearch.ts index 46f54b3..167f79b 100644 --- a/sdk/kg/hotSearch.ts +++ b/sdk/kg/hotSearch.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { decodeName } from '../index.ts' import type { HttpRequestObject } from '../types.ts' @@ -21,7 +21,6 @@ export default { }) const { body, statusCode } = await _requestObj.promise if (statusCode != 200 || body.errcode !== 0) throw new Error('获取热搜词失败') - // console.log(body, statusCode) return { source: 'kg', list: this.filterList(body.data.list) } }, filterList(rawList) { diff --git a/sdk/kg/leaderboard.ts b/sdk/kg/leaderboard.ts index 84162b6..a5c5e63 100644 --- a/sdk/kg/leaderboard.ts +++ b/sdk/kg/leaderboard.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { decodeName, formatPlayTime, sizeFormate } from '../index.ts' import { formatSingerName } from '../utils.ts' import type { HttpRequestObject, SongType, QualityInfo } from '../types.ts' @@ -91,7 +91,6 @@ export default { return arr.join('、') }, filterData(rawList) { - // console.log(rawList) return rawList.map(item => { const types: Array = [] const _types: Record = {} @@ -147,7 +146,6 @@ export default { }, filterBoardsData(rawList) { - // console.log(rawList) let list: Array<{ id: string; name: string; bangid: string }> = [] for (const board of rawList) { if (board.isvol != 1) continue @@ -159,24 +157,7 @@ export default { } return list }, - async getBoards(retryNum = 0) { - // if (++retryNum > 3) return Promise.reject(new Error('try max num')) - // let response - // try { - // response = await this.getBoardsData() - // } catch (error) { - // return this.getBoards(retryNum) - // } - // // console.log(response.body) - // if (response.statusCode !== 200 || response.body.errcode !== 0) return this.getBoards(retryNum) - // const list = this.filterBoardsData(response.body.data.info) - // console.log(list) - // // console.log(JSON.stringify(list)) - // this.list = list - // return { - // list, - // source: 'kg', - // } + async getBoards() { this.list = boardList return { list: boardList, @@ -189,11 +170,9 @@ export default { if (body.errcode != 0) return this.getList(bangid, page, retryNum) - // console.log(body) let total = body.data.total let limit = 100 let listData = this.filterData(body.data.info) - // console.log(listData) return { total, list: listData, diff --git a/sdk/kg/lyric.ts b/sdk/kg/lyric.ts index 12781e3..eac0d54 100644 --- a/sdk/kg/lyric.ts +++ b/sdk/kg/lyric.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { decodeKrc } from './krcDecode.ts' export default { @@ -13,28 +13,6 @@ export default { } return parseInt(intv as unknown as string) }, - // getLyric(songInfo, tryNum = 0) { - // let requestObj = httpFetch(`http://m.kugou.com/app/i/krc.php?cmd=100&keyword=${encodeURIComponent(songInfo.name)}&hash=${songInfo.hash}&timelength=${songInfo._interval || this.getIntv(songInfo.interval)}&d=0.38664927426725626`, { - // headers: { - // 'KG-RC': 1, - // 'KG-THash': 'expand_search_manager.cpp:852736169:451', - // 'User-Agent': 'KuGou2012-9020-ExpandSearchManager', - // }, - // }) - // requestObj.promise = requestObj.promise.then(({ body, statusCode }) => { - // if (statusCode !== 200) { - // if (tryNum > 5) return Promise.reject(new Error('歌词获取失败')) - // let tryRequestObj = this.getLyric(songInfo, ++tryNum) - // requestObj.cancelHttp = tryRequestObj.cancelHttp.bind(tryRequestObj) - // return tryRequestObj.promise - // } - // return { - // lyric: body, - // tlyric: '', - // } - // }) - // return requestObj - // }, searchLyric(name, hash, time, tryNum = 0) { let requestObj = httpFetch(`http://lyrics.kugou.com/search?ver=1&man=yes&client=pc&keyword=${encodeURIComponent(name)}&hash=${hash}&timelength=${time}&lrctxt=1`, { headers: { @@ -92,7 +70,7 @@ export default { return requestObj }, - getLyric(songInfo, tryNum = 0) { + getLyric(songInfo) { let requestObj = this.searchLyric(songInfo.name, songInfo.hash, songInfo._interval || this.getIntv(songInfo.interval)) requestObj.promise = requestObj.promise.then(result => { diff --git a/sdk/kg/musicInfo.ts b/sdk/kg/musicInfo.ts index 649b6a7..6ed1aa0 100644 --- a/sdk/kg/musicInfo.ts +++ b/sdk/kg/musicInfo.ts @@ -39,7 +39,6 @@ const createGetMusicInfosTask = (hashs: Array<{ hash: string }>): Array { - // console.log(rawList) let ids = new Set() let list: SongInfo[] = [] rawList.forEach(item => { diff --git a/sdk/kg/musicSearch.ts b/sdk/kg/musicSearch.ts index 2cfa291..1ea0eb4 100644 --- a/sdk/kg/musicSearch.ts +++ b/sdk/kg/musicSearch.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { decodeName, formatPlayTime, sizeFormate } from '../index.ts' import { formatSingerName } from '../utils.ts' import type { SongType, QualityInfo } from '../types.ts' diff --git a/sdk/kg/parse.ts b/sdk/kg/parse.ts index b733241..6967251 100644 --- a/sdk/kg/parse.ts +++ b/sdk/kg/parse.ts @@ -3,7 +3,7 @@ // 上游对应:music-lib/kugou/song.go Parse / kugou.go fetchSongInfo // 元数据 m.kugou.com/app/i/getSongInfo.php(songName/author_name/timeLength/album_img/bitRate) // 另尽力合并 musicInfo.getMusicInfo 的专辑/多档 hash,直链取流失败不影响返回(上游为必得 URL)。 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { formatPlayTime, decodeName } from '../index.ts' import kgApi from '../apis/kg.ts' import { getMusicInfo } from './musicInfo.ts' diff --git a/sdk/kg/pic.ts b/sdk/kg/pic.ts index 1b48eeb..7904075 100644 --- a/sdk/kg/pic.ts +++ b/sdk/kg/pic.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' export default { getPic(songInfo) { diff --git a/sdk/kg/playlist.ts b/sdk/kg/playlist.ts index c837f04..c467889 100644 --- a/sdk/kg/playlist.ts +++ b/sdk/kg/playlist.ts @@ -3,7 +3,7 @@ // 链接解析优先复用既有 sdk/kg/songList.ts 的 getUserListDetail / getListDetailBySpecialId / // getListInfoByChain / decodeGcid 等能力(覆盖 special/single、songlist/gcid、share chain、 // zlist、global_collection_id 等形态),本模块只做统一形状归一。 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import songList from './songList.ts' const UA = 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1' diff --git a/sdk/kg/songList.ts b/sdk/kg/songList.ts index b0d1390..024a40b 100644 --- a/sdk/kg/songList.ts +++ b/sdk/kg/songList.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { decodeName, formatPlayTime, sizeFormate, dateFormat, formatPlayCount } from '../index.ts' import { toMD5 } from '../utils.ts' import { signatureParams } from './util.ts' @@ -66,51 +66,6 @@ export default { // https://www.kugou.com/yy/special/single/1067062.html listDetailLink: /^.+\/(\d+)\.html(?:\?.*|&.*$|#.*$|$)/, }, - // async getGlobalSpecialId(specialId) { - // return httpFetch(`http://mobilecdnbj.kugou.com/api/v5/special/info?specialid=${specialId}`, { - // headers: { - // 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; HLK-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Mobile Safari/537.36 EdgA/104.0.1293.70', - // }, - // }).promise.then(({ body }) => { - // // console.log(body) - // if (!body.data.global_specialid) Promise.reject(new Error('Failed to get global collection id.')) - // return body.data.global_specialid - // }) - // }, - // async getListInfoBySpecialId(special_id, retry = 0) { - // if (++retry > 2) throw new Error('failed') - // return httpFetch(`https://m.kugou.com/plist/list/${special_id}/?json=true`, { - // headers: { - // 'User-Agent': 'Mozilla/5.0 (Linux; Android 10; HLK-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Mobile Safari/537.36 EdgA/104.0.1293.70', - // }, - // follow_max: 2, - // }).promise.then(({ body }) => { - // // console.log(body) - // if (!body.info.list) return this.getListInfoBySpecialId(special_id, retry) - // let listinfo = body.info.list - // return { - // listInfo: { - // name: listinfo.specialname, - // image: listinfo.imgurl.replace('{size}', '150'), - // intro: listinfo.intro, - // author: listinfo.nickname, - // playcount: listinfo.playcount, - // total: listinfo.songcount, - // }, - // globalSpecialId: listinfo.global_specialid, - // } - // }) - // }, - // async getSongListDetailByGlobalSpecialId(id, page, limit = 100, retry = 0) { - // if (++retry > 2) throw new Error('failed') - // console.log(id) - // const params = `specialid=0&need_sort=1&module=CloudMusic&clientver=11409&pagesize=${limit}&global_collection_id=${id}&userid=0&page=${page}&type=1&area_code=1&appid=1005` - // return httpFetch(`http://pubsongscdn.tx.kugou.com/v2/get_other_list_file?${params}&signature=${signatureParams(params)}`).promise.then(({ body }) => { - // // console.log(body) - // if (body.data?.info == null) return this.getSongListDetailByGlobalSpecialId(id, page, limit, retry) - // return body.data.info - // }) - // }, parseHtmlDesc(html) { const prefix = '
' let index = html.indexOf(prefix) @@ -148,30 +103,9 @@ export default { name, img: pic, desc, - // author: body.result.info.userinfo.username, - // play_count: formatPlayCount(body.result.listen_num), }, } - // const globalSpecialId = await this.getGlobalSpecialId(id) - // const limit = 100 - // const listData = await this.getSongListDetailByGlobalSpecialId(globalSpecialId, page, limit) - // if (!Array.isArray(listData)) - // return this.getUserListDetail2(globalSpecialId) - // return { - // list: this.filterDatav9(listData), - // page, - // limit, - // total: listInfo.total, - // source: 'kg', - // info: { - // name: listInfo.name, - // img: listInfo.image, - // desc: listInfo.intro, - // author: listInfo.author, - // play_count: formatPlayCount(listInfo.playcount), - // }, - // } }, getInfoUrl(tagId?) { return tagId @@ -276,10 +210,9 @@ export default { try { result = await httpFetch(url, options).promise } catch (err) { - console.log(err) + console.warn(`[kg] 歌单请求失败将重试(${retryNum + 1}/3) ${url}: ${(err as Error).message}`) return this.createHttp(url, options, ++retryNum) } - // console.log(result.statusCode, result.body) if (result.statusCode !== 200 || ( (result.body.error_code !== undefined @@ -349,7 +282,6 @@ export default { }, body: { appid: 1001, clientver: 9020, mid: '21511157a05844bd085308bc76ef3343', clienttime: 640612895, key: '36164c4015e704673c588ee202b9ecb8', data: id }, }) - // console.log(songInfo) // type 1单曲,2歌单,3电台,4酷狗码,5别人的播放队列 let songList let info = songInfo.info @@ -372,7 +304,6 @@ export default { }, body: { appid: 1001, clientver: 9020, mid: '21511157a05844bd085308bc76ef3343', clienttime: 640612895, key: '36164c4015e704673c588ee202b9ecb8', data: { id: info.id, type: 3, userid: info.userid, collect_type: 0, page: 1, pagesize: info.count } }, }) - // console.log(songList) } let list = await this.getMusicInfos(songList || songInfo.list) return { @@ -402,7 +333,6 @@ export default { else return this.getUserListDetail4(songInfo, chain, page).catch(() => this.getUserListDetail5(chain)) } let list = await this.getMusicInfos(songInfo.list) - // console.log(info, songInfo) return { list, page: 1, @@ -468,7 +398,6 @@ export default { } let result = await Promise.all(tasks).then(([...datas]) => datas.flat()) result = await this.getMusicInfos(result) - // console.log(result) return { list: result, page, @@ -519,7 +448,6 @@ export default { }) const songInfo = await this.createGetListDetail2Task(id, info.songcount) let list = await this.getMusicInfos(songInfo) - // console.log(info, songInfo, list) return { list, page: 1, @@ -561,7 +489,6 @@ export default { if (result) result = JSON.parse(result[1]) this.cache.set(chain, result) result = await this.getMusicInfos(result) - // console.log(info, songInfo) return result }, @@ -618,9 +545,7 @@ export default { }, }) - // console.log(info) let result = await this.getMusicInfos(info.info) - // console.log(info, songInfo) return result }, @@ -655,10 +580,8 @@ export default { }) const { headers: { location }, statusCode, body } = await requestObj_listDetailLink.promise const loc = location as string | undefined - // console.log(body, location) if (statusCode > 400) return this.getUserListDetail(link, page, ++retryNum) if (loc) { - // console.log(location) if (loc.includes('global_collection_id')) return this.getUserListDetail2(loc.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1')) if (loc.includes('gcid_')) { let gcid = link.match(/gcid_\w+/)?.[0] @@ -679,7 +602,6 @@ export default { return this.getUserListDetail(link, page, ++retryNum) } else return this.getUserListDetail3(loc.replace(/.+\/(\w+).html(?:\?.*|&.*$|#.*$|$)/, '$1'), page) } - // console.log('location', location) return this.getUserListDetail(loc, page, ++retryNum) } if (typeof body == 'string') { @@ -713,7 +635,6 @@ export default { return this.getListDetailBySpecialId(id, page) }, filterData(rawList) { - // console.log(rawList) return rawList.map(item => { const types: Array<{ type: string; size: string; hash?: string }> = [] const _types: Record = {} @@ -766,72 +687,9 @@ export default { } }) }, - // getSinger(singers) { - // let arr = [] - // singers?.forEach(singer => { - // arr.push(singer.name) - // }) - // return arr.join('、') - // }, - // v9 API - // filterDatav9(rawList) { - // console.log(rawList) - // return rawList.map(item => { - // const types = [] - // const _types = {} - // item.relate_goods.forEach(qualityObj => { - // if (qualityObj.level === 2) { - // let size = sizeFormate(qualityObj.size) - // types.push({ type: '128k', size, hash: qualityObj.hash }) - // _types['128k'] = { - // size, - // hash: qualityObj.hash, - // } - // } else if (qualityObj.level === 4) { - // let size = sizeFormate(qualityObj.size) - // types.push({ type: '320k', size, hash: qualityObj.hash }) - // _types['320k'] = { - // size, - // hash: qualityObj.hash, - // } - // } else if (qualityObj.level === 5) { - // let size = sizeFormate(qualityObj.size) - // types.push({ type: 'flac', size, hash: qualityObj.hash }) - // _types.flac = { - // size, - // hash: qualityObj.hash, - // } - // } else if (qualityObj.level === 6) { - // let size = sizeFormate(qualityObj.size) - // types.push({ type: 'flac24bit', size, hash: qualityObj.hash }) - // _types.flac24bit = { - // size, - // hash: qualityObj.hash, - // } - // } - // }) - // const nameInfo = item.name.split(' - ') - // return { - // singer: this.getSinger(item.singerinfo), - // name: decodeName((nameInfo[1] ?? nameInfo[0]).trim()), - // albumName: decodeName(item.albuminfo.name), - // albumId: item.albuminfo.id, - // songmid: item.audio_id, - // source: 'kg', - // interval: formatPlayTime(item.timelen / 1000), - // img: null, - // lrc: null, - // hash: item.hash, - // types, - // _types, - // typeUrl: {}, - // } - // }) - // }, // hash list filter filterData2(rawList) { - // console.log(rawList) let ids = new Set() let list: SongInfo[] = [] rawList.forEach(item => { @@ -959,7 +817,6 @@ export default { return httpFetch(`http://msearchretry.kugou.com/api/v3/search/special?keyword=${encodeURIComponent(text)}&page=${page}&pagesize=${limit}&showtype=10&filter=0&version=7910&sver=2`) .promise.then(({ body }) => { if (body.errcode != 0) throw new Error('filed') - // console.log(body.data.info) return { list: body.data.info.map(item => { return { diff --git a/sdk/kg/util.ts b/sdk/kg/util.ts index 54360ed..7833e68 100644 --- a/sdk/kg/util.ts +++ b/sdk/kg/util.ts @@ -1,9 +1,8 @@ import { toMD5 } from '../utils.ts' -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import type { HttpOptions } from '../types.ts' // s.content[0].lyricContent.forEach(([str]) => { -// console.log(str) // }) /** @@ -32,10 +31,9 @@ export const createHttpFetch = async(url: string, options?: HttpOptions, retryNu try { result = await httpFetch(url, options).promise } catch (err) { - console.log(err) + console.warn(`[kg] 请求失败将重试(${retryNum + 1}/3) ${url}: ${(err as Error).message}`) return createHttpFetch(url, options, ++retryNum) } - // console.log(result.statusCode, result.body) if (result.statusCode !== 200 || ( result.body.error_code ?? diff --git a/sdk/kw/album.ts b/sdk/kw/album.ts index c11647b..f6174f4 100644 --- a/sdk/kw/album.ts +++ b/sdk/kw/album.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { decodeName } from '../index.ts' import { formatSinger, objStr2JSON } from './util.ts' import type { Quality } from '../types.ts' @@ -17,9 +17,7 @@ export default { limit_list: 36, limit_song: 1000, filterListDetail(rawList, albumName, albumId) { - // console.log(rawList) - // console.log(rawList.length, rawList2.length) - return rawList.map((item, inedx) => { + return rawList.map(item => { let formats = item.formats.split('|') let types: Array<{ type: Quality; size: string | null }> = [] let _types: Partial> = {} @@ -92,7 +90,6 @@ export default { return requestObj_listDetail.promise.then(({ statusCode, body }) => { if (statusCode !== 200) return this.getAlbumListDetail(id, page, ++retryNum) body = objStr2JSON(body) - // console.log(body) if (!body.musiclist) return this.getAlbumListDetail(id, page, ++retryNum) body.name = decodeName(body.name) return { @@ -235,31 +232,4 @@ export default { } throw new Error('无效的酷我专辑链接') }, - // getAlbumListDetail(id, page, retryNum = 0) { - // if (retryNum > 2) return Promise.reject(new Error('try max num')) - // return tokenRequest(`http://www.kuwo.cn/api/www/album/albumInfo?albumId=${id}&pn=${page}&rn=${this.limit_song}&httpsStatus=1`).then((resp) => { - // return resp.promise.then(({ statusCode, body }) => { - // console.log(body) - // return Promise.reject(new Error('failed')) - // // if (statusCode !== 200) return this.getAlbumListDetail(id, page, ++retryNum) - // // const data = body.data - // // console.log(data) - // // if (!data.musicList) return this.getAlbumListDetail(id, page, ++retryNum) - // // return { - // // list: this.filterListDetail(data.musiclist), - // // page, - // // limit: this.limit_song, - // // total: data.total, - // // source: 'kw', - // // info: { - // // name: data.album, - // // img: data.pic, - // // desc: data.albuminfo, - // // author: data.artist, - // // play_count: this.formatPlayCount(data.playCnt), - // // }, - // // } - // }) - // }) - // }, } diff --git a/sdk/kw/comment.ts b/sdk/kw/comment.ts index 5e29cb2..afb258e 100644 --- a/sdk/kw/comment.ts +++ b/sdk/kw/comment.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { dateFormat2 } from '../index.ts' import type { HttpRequestObject } from '../types.ts' @@ -15,7 +15,6 @@ export default { }) const { body, statusCode } = await _requestObj.promise if (statusCode != 200 || body.code != '200') throw new Error('获取评论失败') - // console.log(body) const total = body.comments_counts return { @@ -37,7 +36,6 @@ export default { }) const { body, statusCode } = await _requestObj2.promise if (statusCode != 200 || body.code != '200') throw new Error('获取热门评论失败') - // console.log(body) const total = body.hot_comments_counts return { diff --git a/sdk/kw/hotSearch.ts b/sdk/kw/hotSearch.ts index a7de583..2974790 100644 --- a/sdk/kw/hotSearch.ts +++ b/sdk/kw/hotSearch.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import type { HttpRequestObject } from '../types.ts' export default { @@ -14,7 +14,6 @@ export default { }) const { body, statusCode } = await _requestObj.promise if (statusCode != 200 || body.status !== 'ok') throw new Error('获取热搜词失败') - // console.log(body, statusCode) return { source: 'kw', list: this.filterList(body.tagvalue) } }, filterList(rawList) { diff --git a/sdk/kw/index.ts b/sdk/kw/index.ts index ed486db..3910fc0 100644 --- a/sdk/kw/index.ts +++ b/sdk/kw/index.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import musicSearch from './musicSearch.ts' import { formatSinger } from './util.ts' import leaderboard from './leaderboard.ts' @@ -21,22 +21,6 @@ const kw = { album, playlist, parse, - // context: null, - - - // init(context) { - // if (this.isInited) return - // this.isInited = true - // this.context = context - - // // this.musicSearch.search('我又想你了').then(res => { - // // console.log(res) - // // }) - - // // this.getMusicUrl('62355680', '320k').then(url => { - // // console.log(url) - // // }) - // }, musicSearch, leaderboard, @@ -49,7 +33,6 @@ const kw = { }, handleMusicInfo(songInfo) { return this.getMusicInfo(songInfo).then(info => { - // console.log(JSON.stringify(info)) songInfo.name = info.name songInfo.singer = formatSinger(info.artist) songInfo.img = info.pic @@ -99,9 +82,6 @@ const kw = { return `http://www.kuwo.cn/play_detail/${songInfo.songmid}` }, - // init() { - // return getToken() - // }, } export default kw diff --git a/sdk/kw/leaderboard.ts b/sdk/kw/leaderboard.ts index 698c8c8..2f13019 100644 --- a/sdk/kw/leaderboard.ts +++ b/sdk/kw/leaderboard.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { formatPlayTime, decodeName } from '../index.ts' import { formatSinger, wbdCrypto } from './util.ts' import type { HttpRequestObject, Quality, QualityInfo, SongType } from '../types.ts' @@ -167,7 +167,6 @@ export default { }, filterBoardsData(rawList) { - // console.log(rawList) let list: any[] = [] for (const board of rawList) { if (board.source != '1') continue @@ -179,24 +178,7 @@ export default { } return list }, - async getBoards(retryNum = 0) { - // if (++retryNum > 3) return Promise.reject(new Error('try max num')) - // let response - // try { - // response = await this.getBoardsData() - // } catch (error) { - // return this.getBoards(retryNum) - // } - // console.log(response.body) - // if (response.statusCode !== 200 || !response.body.child) return this.getBoards(retryNum) - // const list = this.filterBoardsData(response.body.child) - // // console.log(list) - // console.log(JSON.stringify(list)) - // this.list = list - // return { - // list, - // source: 'kw', - // } + async getBoards() { this.list = boardList return { list: boardList, @@ -213,7 +195,6 @@ export default { return request.then(({ statusCode, body }) => { const rawData = wbdCrypto.decodeData(body) - // console.log(rawData) const data = rawData.data if (statusCode !== 200 || rawData.code != 200 || !data.musiclist) return this.getList(id, page, retryNum) @@ -230,7 +211,4 @@ export default { }) }, - // getDetailPageUrl(id) { - // return `http://www.kuwo.cn/rankList/${id}` - // }, } diff --git a/sdk/kw/lyric.ts b/sdk/kw/lyric.ts index 99278fa..13bcc37 100644 --- a/sdk/kw/lyric.ts +++ b/sdk/kw/lyric.ts @@ -1,71 +1,7 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { decodeLyric, lrcTools } from './util.ts' import { decodeName } from '../index.ts' -/* -export default { - formatTime(time) { - let m = parseInt(time / 60) - let s = (time % 60).toFixed(2) - return (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s) - }, - sortLrcArr(arr) { - const lrcSet = new Set() - let lrc = [] - let lrcT = [] - - for (const item of arr) { - if (lrcSet.has(item.time)) { - const tItem = lrc.pop() - tItem.time = lrc[lrc.length - 1].time - lrcT.push(tItem) - lrc.push(item) - } else { - lrc.push(item) - lrcSet.add(item.time) - } - } - - if (lrcT.length && lrc.length > lrcT.length) { - const tItem = lrc.pop() - tItem.time = lrc[lrc.length - 1].time - lrcT.push(tItem) - } - - return { - lrc, - lrcT, - } - }, - transformLrc(songinfo, lrclist) { - return `[ti:${songinfo.songName}]\n[ar:${songinfo.artist}]\n[al:${songinfo.album}]\n[by:]\n[offset:0]\n${lrclist ? lrclist.map(l => `[${this.formatTime(l.time)}]${l.lineLyric}\n`).join('') : '暂无歌词'}` - }, - getLyric(songId) { - const requestObj = httpFetch(`http://m.kuwo.cn/newh5/singles/songinfoandlrc?musicId=${songId}`) - requestObj.promise = requestObj.promise.then(({ body }) => { - // console.log(body) - if (!body.data?.lrclist?.length) return Promise.reject(new Error('Get lyric failed')) - let lrcInfo - try { - lrcInfo = this.sortLrcArr(body.data.lrclist) - } catch { - return Promise.reject(new Error('Get lyric failed')) - } - // console.log(body.data.lrclist) - // console.log(lrcInfo.lrc, lrcInfo.lrcT) - // console.log({ - // lyric: decodeName(this.transformLrc(body.data.songinfo, lrc)), - // tlyric: decodeName(this.transformLrc(body.data.songinfo, lrcT)), - // }) - return { - lyric: decodeName(this.transformLrc(body.data.songinfo, lrcInfo.lrc)), - tlyric: lrcInfo.lrcT.length ? decodeName(this.transformLrc(body.data.songinfo, lrcInfo.lrcT)) : '', - } - }) - return requestObj - }, -} - */ const buf_key = Buffer.from('yeelion') const buf_key_len = buf_key.length @@ -87,65 +23,11 @@ const buildParams = (id: string, isGetLyricx: boolean): string => { return Buffer.from(output).toString('base64') } -// console.log(buildParams('207527604', false)) -// console.log(buildParams('207527604', true)) const timeExp = /^\[([\d:.]*)\]{1}/g const existTimeExp = /\[\d{1,2}:.*\d{1,4}\]/ const lyricxTag = /^<-?\d+,-?\d+>/ export default { - /* sortLrcArr(arr) { - const lrcSet = new Set() - let lrc = [] - let lrcT = [] - let markIndex = [] - for (const item of arr) { - if (lrcSet.has(item.time)) { - if (lrc.length < 2) continue - const index = lrc.findIndex(l => l.time == item.time) - markIndex.push(index) - if (index == lrc.length - 1) { - lrcT.push({ ...lrc[index], time: item.time }) - lrc.push(item) - } else { - lrcT.push({ ...lrc[index], time: lrc[index + 1].time }) - if (item.text) { - // const lastIndex = lrc.length - 1 - // markIndex.push(lastIndex) - // lrcT.push({ ...lrc[lastIndex], time: lrc[lastIndex - 1].time }) - lrc.push(item) - } - } - } else { - lrc.push(item) - lrcSet.add(item.time) - } - } - - // console.log(markIndex) - markIndex = Array.from(new Set(markIndex)) - for (let index = markIndex.length - 1; index >= 0; index--) { - lrc.splice(markIndex[index], 1) - } - - // if (lrcT.length) { - // if (lrc.length * 0.4 < lrcT.length) { // 翻译数量需大于歌词数量的0.4倍,否则认为没有翻译 - // const tItem = lrc.pop() - // tItem.time = lrc[lrc.length - 1].time - // lrcT.push(tItem) - // } else { - // lrc = arr - // lrcT = [] - // } - // } - - console.log(lrc, lrcT) - - return { - lrc, - lrcT, - } - }, */ sortLrcArr(arr) { const lrcSet = new Set() let lrc: any[] = [] @@ -211,48 +93,17 @@ export default { tlyric: lrcInfo.lrcT.length ? decodeName(this.transformLrc(tags, lrcInfo.lrcT)) : '', } }, - // getLyric2(musicInfo, isGetLyricx = true) { - // const requestObj = httpFetch(`http://newlyric.kuwo.cn/newlyric.lrc?${buildParams(musicInfo.songmid, isGetLyricx)}`) - // requestObj.promise = requestObj.promise.then(({ statusCode, body, raw }) => { - // if (statusCode != 200) return Promise.reject(new Error(JSON.stringify(body))) - // return decodeLyric({ lrcBase64: raw.toString('base64'), isGetLyricx }).then(base64Data => { - // let lrcInfo - // console.log(Buffer.from(base64Data, 'base64').toString()) - // try { - // lrcInfo = this.parseLrc(Buffer.from(base64Data, 'base64').toString()) - // } catch { - // return Promise.reject(new Error('Get lyric failed')) - // } - // if (lrcInfo.tlyric) lrcInfo.tlyric = lrcInfo.tlyric.replace(lrcTools.rxps.wordTimeAll, '') - // lrcInfo.yrc = lrcTools.parse(lrcInfo.lyric) - // // console.log(lrcInfo.lyric) - // // console.log(lrcInfo.tlyric) - // // console.log(lrcInfo.yrc) - // // console.log(JSON.stringify(lrcInfo)) - // }) - // }) - // return requestObj - // }, getLyric(musicInfo, isGetLyricx = true) { - // this.getLyric2(musicInfo) const requestObj = httpFetch(`http://newlyric.kuwo.cn/newlyric.lrc?${buildParams(musicInfo.songmid, isGetLyricx)}`) requestObj.promise = requestObj.promise.then(({ statusCode, body, raw }) => { if (statusCode != 200) return Promise.reject(new Error(JSON.stringify(body))) return decodeLyric({ lrcBase64: raw!.toString('base64'), isGetLyricx }).then(base64Data => { - // let lrcInfo - // try { - // lrcInfo = this.parseLrc(Buffer.from(base64Data, 'base64').toString()) - // } catch { - // return Promise.reject(new Error('Get lyric failed')) - // } let lrcInfo - // console.log(Buffer.from(base64Data, 'base64').toString()) try { lrcInfo = this.parseLrc(Buffer.from(base64Data, 'base64').toString()) } catch (err) { return Promise.reject(new Error('Get lyric failed')) } - // console.log(lrcInfo) if (lrcInfo.tlyric) lrcInfo.tlyric = lrcInfo.tlyric.replace(lrcTools.rxps.wordTimeAll, '') try { lrcInfo.yrc = lrcTools.parse(lrcInfo.lyric) @@ -261,7 +112,6 @@ export default { } lrcInfo.lyric = lrcInfo.lyric.replace(lrcTools.rxps.wordTimeAll, '') if (!existTimeExp.test(lrcInfo.lyric)) return Promise.reject(new Error('Get lyric failed')) - // console.log(lrcInfo) return lrcInfo }) }) diff --git a/sdk/kw/musicSearch.ts b/sdk/kw/musicSearch.ts index ee938e8..aab9138 100644 --- a/sdk/kw/musicSearch.ts +++ b/sdk/kw/musicSearch.ts @@ -1,6 +1,6 @@ // import '../../polyfill/array.find.js' -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { formatPlayTime, decodeName } from '../index.ts' // import { debug } from '../../utils/env.ts' import { formatSinger } from './util.ts' @@ -14,21 +14,13 @@ export default { total: 0, page: 0, allPage: 1, - // cancelFn: null, musicSearch(str: string, page: number, limit: number) { const musicSearchRequestObj = httpFetch(`http://search.kuwo.cn/r.s?client=kt&all=${encodeURIComponent(str)}&pn=${page - 1}&rn=${limit}&uid=794762570&ver=kwplayer_ar_9.2.2.1&vipver=1&show_copyright_off=1&newver=1&ft=music&cluster=0&strategy=2012&encoding=utf8&rformat=json&vermerge=1&mobi=1&issubtitle=1`) return musicSearchRequestObj.promise }, - // getImg(songId) { - // return httpGet(`http://player.kuwo.cn/webmusic/sj/dtflagdate?flag=6&rid=MUSIC_${songId}`) - // }, - // getLrc(songId) { - // return httpGet(`http://mobile.kuwo.cn/mpage/html5/songinfoandlrc?mid=${songId}&flag=0`) - // }, handleResult(rawData: any) { const result: SongInfo[] = [] if (!rawData) return result - // console.log(rawData) for (let i = 0; i < rawData.length; i++) { const info = rawData[i] let songId = info.MUSICRID.replace('MUSIC_', '') @@ -97,7 +89,6 @@ export default { typeUrl: {}, }) } - // console.log(result) return result }, search(str: string, page = 1, limit?: number, retryNum = 0) { @@ -105,7 +96,6 @@ export default { if (limit == null) limit = this.limit // http://newlyric.kuwo.cn/newlyric.lrc?62355680 return this.musicSearch(str, page, limit).then(({ body: result }) => { - // console.log(result) if (!result || (result.TOTAL !== '0' && result.SHOW === '0')) return this.search(str, page, limit, ++retryNum) let list = this.handleResult(result.abslist) diff --git a/sdk/kw/parse.ts b/sdk/kw/parse.ts index 49e6c19..d26d59a 100644 --- a/sdk/kw/parse.ts +++ b/sdk/kw/parse.ts @@ -2,7 +2,7 @@ // 歌曲:https://www.kuwo.cn/play_detail/(含 ?/# 尾串)、m.kuwo.cn 的 musicId=、裸 rid // 上游对应:music-lib/kuwo/song.go Parse / kuwo.go fetchFullSongInfo(元数据 m.kuwo.cn + 尽力附直链) // 专辑 / 歌单分别复用 album.parseAlbumLink、playlist.parsePlaylistLink。 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { formatPlayTime } from '../index.ts' import kwApi from '../apis/kw.ts' import album from './album.ts' diff --git a/sdk/kw/pic.ts b/sdk/kw/pic.ts index 770a27e..c42e43c 100644 --- a/sdk/kw/pic.ts +++ b/sdk/kw/pic.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import type { SongInfo } from '../types.ts' export default { diff --git a/sdk/kw/songList.ts b/sdk/kw/songList.ts index 53e05d0..bf01c15 100644 --- a/sdk/kw/songList.ts +++ b/sdk/kw/songList.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { formatPlayTime, decodeName } from '../index.ts' import { formatSinger, objStr2JSON } from './util.ts' import album from './album.ts' @@ -147,7 +147,6 @@ export default { })) }, filterList2(rawData) { - // console.log(rawData) const list: any[] = [] rawData.forEach(item => { if (!item.label) return @@ -196,7 +195,6 @@ export default { // 本方法须返回 detailId(调用方据此再查曲目),失败时应重试自身; // 原先误调 getListDetail(返回歌单详情对象、且把 tryNum 当 page)导致返回类型错位 if (statusCode != 200 || !body.child) return this.getListDetailDigest5Info(id, ++tryNum) - // console.log(body) return body.child.length ? body.child[0].sourceid : null }) }, @@ -204,7 +202,6 @@ export default { if (tryNum > 2) return Promise.reject(new Error('try max num')) const requestObj = httpFetch(`http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=${id}&pn=${page - 1}&rn=${this.limit_song}&encode=utf-8&keyset=pl2012&identity=kuwo&pcmp4=1`) return requestObj.promise.then(({ body }) => { - // console.log(body) if (body.result !== 'ok') return this.getListDetail(id, page, ++tryNum) return { list: this.filterListDetail(body.musiclist), @@ -314,7 +311,6 @@ export default { if (infoData.code != 200) return null - // console.log(infoData) return { name: infoData.data.userInfo.nickname + '喜欢的音乐', img: infoData.data.userInfo.headImg, @@ -367,13 +363,11 @@ export default { author: '', play_count: '', } - // console.log(listData) return listData }, // 获取歌曲列表内的音乐 getListDetail(id, page, retryNum = 0) { - // console.log(id) // https://h5app.kuwo.cn/m/bodian/collection.html?uid=000&playlistId=000&source=5&ownerId=000 // https://h5app.kuwo.cn/m/bodian/collection.html?uid=000&playlistId=000&source=4&ownerId= if (/\/bodian\//.test(id)) return this.getListDetailMusicListByBD(id, page) @@ -393,7 +387,6 @@ export default { return this.getListDetailDigest8(id, page, retryNum) }, filterListDetail(rawData) { - // console.log(rawData) return rawData.map(item => { let infoArr = item.N_MINFO.split(';') let types: SongType[] = [] @@ -464,7 +457,6 @@ export default { return httpFetch(`http://search.kuwo.cn/r.s?all=${encodeURIComponent(text)}&pn=${page - 1}&rn=${limit}&rformat=json&encoding=utf8&ver=mbox&vipver=MUSIC_8.7.7.0_BCS37&plat=pc&devid=28156413&ft=playlist&pay=0&needliveshow=0`) .promise.then(({ body }) => { body = objStr2JSON(body) - // console.log(body) return { list: body.abslist.map(item => { return { diff --git a/sdk/kw/util.ts b/sdk/kw/util.ts index 53111d7..a18a441 100644 --- a/sdk/kw/util.ts +++ b/sdk/kw/util.ts @@ -1,33 +1,7 @@ -// import { httpGet, httpFetch } from '../request.ts' import { handleKwDecodeLyric } from './lyricDecode.ts' import { createCipheriv, createDecipheriv } from 'crypto' import { toMD5 } from '../utils.ts' -// const kw_token = { -// token: null, -// isGetingToken: false, -// } - -// const translationMap = { -// "{'": '{"', -// "'}\n": '"}', -// "'}": '"}', -// "':'": '":"', -// "','": '","', -// "':{'": '":{"', -// "':['": '":["', -// "'}],'": '"}],"', -// "':[{'": '":[{"', -// "'},'": '"},"', -// "'},{'": '"},{"', -// "':[],'": '":[],"', -// "':{},'": '":{},"', -// "'}]}": '"}]}', -// } - -// export const objStr2JSON = str => { -// return JSON.parse(str.replace(/(^{'|'}\n$|'}$|':'|','|':\[{'|'}\],'|':{'|'},'|'},{'|':\['|':\[\],'|':{},'|'}]})/g, s => translationMap[s])) -// } export const objStr2JSON = (str: string): any => { return JSON.parse(str.replace(/('(?=(,\s*')))|('(?=:))|((?<=([:,]\s*))')|((?<={)')|('(?=}))/g, '"')) @@ -44,46 +18,9 @@ export const matchToken = (headers: Record): string | null => { } } -// const wait = time => new Promise(resolve => setTimeout(() => resolve(), time)) - - -// export const getToken = (retryNum = 0) => new Promise((resolve, reject) => { -// if (retryNum > 2) return Promise.reject(new Error('try max num')) - -// if (kw_token.isGetingToken) return wait(1000).then(() => getToken(retryNum).then(token => resolve(token))) -// if (kw_token.token) return resolve(kw_token.token) -// kw_token.isGetingToken = true -// httpGet('http://www.kuwo.cn/', (err, resp) => { -// kw_token.isGetingToken = false -// if (err) return getToken(++retryNum) -// if (resp.statusCode != 200) return reject(new Error('获取失败')) -// const token = kw_token.token = matchToken(resp.headers) -// resolve(token) -// }) -// }) export const decodeLyric = handleKwDecodeLyric -// export const tokenRequest = async(url, options = {}) => { -// let token = kw_token.token -// if (!token) token = await getToken() -// if (!options.headers) { -// options.headers = { -// Referer: 'http://www.kuwo.cn/', -// csrf: token, -// cookie: 'kw_token=' + token, -// } -// } -// const requestObj = httpFetch(url, options) -// requestObj.promise = requestObj.promise.then(resp => { -// // console.log(resp) -// if (resp.statusCode == 200) { -// kw_token.token = matchToken(resp.headers) -// } -// return resp -// }) -// return requestObj -// } interface LrcWordInfo { startTime: number @@ -117,7 +54,6 @@ export const lrcTools = { } prevWord.newTimeStr = `<${prevWord.startTime},${prevWord.endTime - prevWord.startTime}>` - // console.log(prevWord) } } return { @@ -137,7 +73,6 @@ export const lrcTools = { } const wordTimes = words.match(this.rxps.wordTimeAll) if (!wordTimes) return - // console.log(wordTimes) let preTimeInfo for (const timeStr of wordTimes) { const result = this.rxps.wordTime.exec(timeStr) @@ -167,7 +102,6 @@ export const lrcTools = { } }, parse(lrc: string): string { - // console.log(lrc) const lines = lrc.split(/\r\n|\r|\n/) const tools = Object.create(this) tools.isOK = true @@ -183,7 +117,6 @@ export const lrcTools = { if (!tools.lines.length) return '' let lrcs = tools.lines.join('\n') if (tools.tags.length) lrcs = `${tools.tags.join('\n')}\n${lrcs}` - // console.log(lrcs) return lrcs }, } diff --git a/sdk/lr/appApi.ts b/sdk/lr/appApi.ts index 5d658a0..5d7bdda 100644 --- a/sdk/lr/appApi.ts +++ b/sdk/lr/appApi.ts @@ -5,7 +5,7 @@ // 端点:/yyting/search/searchBatch.action(q=2150) // 注意:章节/取流 App 端点(q=1930/2224)游客 token 已失效(482 请登录),取流走 web 通道(见 apis/lr.ts) import crypto from 'node:crypto' -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' const DOMAIN = 'http://dapis.mting.info' const SECRET = 'iJ0DgxmdC83#I&j@iwg' diff --git a/sdk/lr/auth.ts b/sdk/lr/auth.ts index d8ae0ab..84f4c4d 100644 --- a/sdk/lr/auth.ts +++ b/sdk/lr/auth.ts @@ -2,7 +2,7 @@ // 参考社区下载器(yoval/lrts 等):POST form {account, pwd: base64(password)}, // 成功响应 json.phone 非空,Set-Cookie 种下会话;取流接口必须携带该会话 // (免费章节匿名也返回"收费章节未购买",2026-10-02 实测)。 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { getCredentials, setCredentials } from '../auth/store.ts' const UA_MI = 'Mozilla/5.0 (Linux; U; Android 4.1.1; zh-cn; MI2 Build/JRO03L) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0' diff --git a/sdk/lr/index.ts b/sdk/lr/index.ts index c1a6bb3..aac034d 100644 --- a/sdk/lr/index.ts +++ b/sdk/lr/index.ts @@ -5,15 +5,13 @@ import lrApi from '../apis/lr.ts' import musicSearch from './musicSearch.ts' import { getBookMenu } from './menu.ts' -import { getLrCookie } from './auth.ts' const lr = { musicSearch, getMusicUrl(songInfo, type) { return lrApi.getMusicUrl(songInfo, type) }, - getPic(songInfo) { - const bookId = String(songInfo.songmid ?? '').split(':')[0] + getPic() { // 书籍封面无独立免签接口;搜索结果的 img 字段已带封面(这里返回空由调用方回退) return Promise.resolve(null) }, diff --git a/sdk/lr/menu.ts b/sdk/lr/menu.ts index b692d8c..740f1cf 100644 --- a/sdk/lr/menu.ts +++ b/sdk/lr/menu.ts @@ -2,7 +2,7 @@ // 接口: https://m.lrts.me/ajax/getBookMenu?bookId=&pageNum=&pageSize=&sortType=0 // 实测(2026-10-02)匿名可用;章节条目 {section, name, listenPrice, state} // 注意:专辑类内容用 getAlbumAudios(entityType=2),本实现仅收书(entityType=3) -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' const UA_MI = 'Mozilla/5.0 (Linux; U; Android 4.1.1; zh-cn; MI2 Build/JRO03L) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30 XiaoMi/MiuiBrowser/1.0' const MENU_URL = 'https://m.lrts.me/ajax/getBookMenu' diff --git a/sdk/me/album.ts b/sdk/me/album.ts index 585c6bb..e680a5d 100644 --- a/sdk/me/album.ts +++ b/sdk/me/album.ts @@ -2,7 +2,7 @@ // 接口: https://www.missevan.com/dramaapi/getdramaepisodes?drama_id=&season=&page=&order=0&pageSize= // 结果在 info.episodes.episode[](name/sound_id/pay_type/vip);剧名在 info.drama.name // 注意:getdrama(不带 type=2 时)的 info.episodes.episode 同样可用(MusicFree 插件用法),本接口支持翻页故用之 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { formatPlayTime } from '../index.ts' const EPISODES_URL = 'https://www.missevan.com/dramaapi/getdramaepisodes' diff --git a/sdk/me/musicSearch.ts b/sdk/me/musicSearch.ts index 024b265..33d2d43 100644 --- a/sdk/me/musicSearch.ts +++ b/sdk/me/musicSearch.ts @@ -3,7 +3,7 @@ // ——网页版搜索排前面的正剧来自这里;getsearch 的 type 参数只有 1UP主/2音单/3声音/4声优,没有剧集类型 // 声音(补足): https://www.missevan.com/sound/getsearch?s=&p=&type=3&page_size=&sort=2 → info.Datas[] // 剧条目 songmid 用 "d:" 前缀(取流时自动取首个免费集,见 apis/me.ts);声音条目为裸 sound_id -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { formatPlayTime } from '../index.ts' const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36' diff --git a/sdk/me/sign.ts b/sdk/me/sign.ts index a2c09e5..3174b11 100644 --- a/sdk/me/sign.ts +++ b/sdk/me/sign.ts @@ -7,7 +7,7 @@ // 该通道返回的是免签名 CDN 明文直链(sound-ali*-cdn-cn.maoercdn.com,m4a 原文件/-128k 变体); // 网页版 hls.m3u8 为 Widevine 加密,与此无关。 import crypto from 'node:crypto' -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { getCredentials } from '../auth/store.ts' const APP_SECRET = 'f8Yw1M3u0e5MV7z34PcbY9wgP56YwJ' diff --git a/sdk/migu/lyric.ts b/sdk/migu/lyric.ts index fb0336b..5e24488 100644 --- a/sdk/migu/lyric.ts +++ b/sdk/migu/lyric.ts @@ -1,7 +1,7 @@ // 咪咕歌词 —— resourceinfo.do 取 lrcUrl/lyricUrl 再下载文本 // 上游对应:music-lib/migu/lyric.go -import { buildUrl, fetchSongDetail, miguGet, UserAgent } from './util.ts' -import { httpFetch } from '../request.ts' +import { buildUrl, fetchSongDetail, miguGet } from './util.ts' +import { httpFetch } from '../common/request.ts' const LRC_REFERER = 'https://y.migu.cn/' const LRC_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36' diff --git a/sdk/migu/util.ts b/sdk/migu/util.ts index 4947393..2326c18 100644 --- a/sdk/migu/util.ts +++ b/sdk/migu/util.ts @@ -2,7 +2,7 @@ // 上游对应:music-lib/migu/migu.go(convertItemToSong*、collectMiguFormats、pickMiguImage 等) // 说明:匿名态 listen-url 仅放行 PQ(128k mp3);HQ/SQ/ZQ 各档需携带登录 Cookie(对话框「登录后免费试听」)。 import crypto from 'node:crypto' -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { getCredentials } from '../auth/store.ts' import type { SongType } from '../types.ts' @@ -328,7 +328,6 @@ export const convertItemToSong = (item: MiguSongItem, allowPaid = true): MiguSon const best = candidates[0]! const bestFormat = rateFormats[best.index]! - const bitrate = duration > 0 && best.size > 0 ? Math.floor(best.size * 8 / 1000 / duration) : 0 const coverURL = normalizeMiguImageURL(firstNonEmpty( pickMiguImage(item.imgItems), pickMiguImage(item.albumImgs), item.img1, item.img2, item.img3, )) diff --git a/sdk/qian/lyric.ts b/sdk/qian/lyric.ts index 28b9373..7ee83e4 100644 --- a/sdk/qian/lyric.ts +++ b/sdk/qian/lyric.ts @@ -1,7 +1,7 @@ // 千千音乐歌词 // 链路:/v1/song/info → data[0].lyric 为歌词文本 URL(static-qianqian.taihe.com/*.txt)→ 直接下载文本。 // 返回 { lyric, tlyric: '' }(千千只有原文歌词,无翻译)。 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { getSongInfo } from './musicInfo.ts' import { requestHeaders } from './util.ts' diff --git a/sdk/qian/util.ts b/sdk/qian/util.ts index b200ff5..7c57715 100644 --- a/sdk/qian/util.ts +++ b/sdk/qian/util.ts @@ -4,7 +4,7 @@ // 该平台匿名即可搜索 / 查专辑 / 查歌单 / 拿免费曲目直链;cookie 仅影响 VIP、收藏等登录态资源, // MusicServer 从 sdk/auth/store.ts 的 getCredentials('bd') 读取(可选,未登录留空)。 import crypto from 'node:crypto' -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { getCredentials } from '../auth/store.ts' export const APP_ID = '16073360' diff --git a/sdk/qs/musicInfo.ts b/sdk/qs/musicInfo.ts index 107ebec..618c2ad 100644 --- a/sdk/qs/musicInfo.ts +++ b/sdk/qs/musicInfo.ts @@ -4,7 +4,7 @@ // 逐字歌词(lyric.content)与试听播放信息(track_player.url_player_info / video_model) // 注意:seo_track 属分享页/SEO 数据面,track_player 里只有 30 秒试听资源; // 完整音频需真机凭证走 /luna/pc/track_v2,且音频经 CENC 加密,见 apis/qs.ts 头注释 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import type { RequestObj } from '../types.ts' export default (trackId: string): RequestObj => { diff --git a/sdk/qt/http.ts b/sdk/qt/http.ts index 3601cba..cc91ee9 100644 --- a/sdk/qt/http.ts +++ b/sdk/qt/http.ts @@ -1,6 +1,6 @@ // 蜻蜓FM SSR 请求助手 —— 域名迁移(www.qingting.fm → www.qtfm.cn)伴随华为 WAF 会话, // 302 时需带上 Set-Cookie 的 HWWAFSESID/HWWAFSESTIME 再请求 Location,否则可能被 WAF 拦 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36' diff --git a/sdk/request.ts b/sdk/request.ts deleted file mode 100644 index 469c397..0000000 --- a/sdk/request.ts +++ /dev/null @@ -1,5 +0,0 @@ -// SDK 根请求模块 —— 唯一实现在 common/request.ts,此处仅转发 -// sdk 内 `import { ... } from '../request.ts'` 的解析目标 - -export { httpFetch } from './common/request.ts' -export type { HttpOptions, HttpRequestObject, HttpFetchResponse } from './common/request.ts' diff --git a/sdk/tx/album.ts b/sdk/tx/album.ts index 9fe8ae2..ece4b61 100644 --- a/sdk/tx/album.ts +++ b/sdk/tx/album.ts @@ -3,7 +3,7 @@ // 曲目:music.musichallAlbum.AlbumSongList GetAlbumSongList 按 100 一批翻页(上游 fetchAlbumDetail 的曲目段) // 详情:GetAlbumInfo 详情接口已停用:专辑名取自曲目自带的 album 信息,作者由曲目歌手去重合成,封面走平台固定 URL 规则 // 链接解析:albumDetail/、album/、albummid=(上游 ParseAlbum) -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { filterMusicInfoItem } from './singer.ts' import { createMusicuFetch } from './utils/index.ts' diff --git a/sdk/tx/comment.ts b/sdk/tx/comment.ts index 9061839..116c2f1 100644 --- a/sdk/tx/comment.ts +++ b/sdk/tx/comment.ts @@ -1,5 +1,5 @@ import type { HttpRequestObject } from '../types.ts' -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { dateFormat2 } from '../index.ts' import getMusicInfo from './musicInfo.ts' @@ -114,7 +114,6 @@ export default { }) const { body, statusCode } = await _requestObj.promise if (statusCode != 200 || body.code !== 0) throw new Error('获取评论失败') - // console.log(body, statusCode) const comment = body.comment return { source: 'tx', @@ -183,7 +182,6 @@ export default { }, }) const { body, statusCode } = await _requestObj2.promise - // console.log('body', body) if (statusCode != 200 || body.code !== 0 || body.req.code !== 0) throw new Error('获取热门评论失败') const comment = body.req.data.CommentList return { diff --git a/sdk/tx/hotSearch.ts b/sdk/tx/hotSearch.ts index 4377cf4..f7a9758 100644 --- a/sdk/tx/hotSearch.ts +++ b/sdk/tx/hotSearch.ts @@ -1,5 +1,5 @@ import type { HttpRequestObject } from '../types.ts' -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' export default { _requestObj: null as HttpRequestObject | null, @@ -44,9 +44,7 @@ export default { }, }) const { body, statusCode } = await _requestObj.promise - // console.log(body) if (statusCode != 200 || body.code !== 0) throw new Error('获取热搜词失败') - // console.log(body) return { source: 'tx', list: this.filterList(body.hotkey.data.vec_hotkey) } }, filterList(rawList) { diff --git a/sdk/tx/leaderboard.ts b/sdk/tx/leaderboard.ts index d8cb2c5..1ce5906 100644 --- a/sdk/tx/leaderboard.ts +++ b/sdk/tx/leaderboard.ts @@ -1,5 +1,5 @@ -import type { HttpRequestObject, SongInfo, SongType, Quality, QualityInfo } from '../types.ts' -import { httpFetch } from '../request.ts' +import type { HttpRequestObject, SongType, Quality, QualityInfo } from '../types.ts' +import { httpFetch } from '../common/request.ts' import { formatPlayTime, sizeFormate } from '../index.ts' import { formatSingerName } from '../utils.ts' @@ -65,7 +65,6 @@ export default { }, ], listDetailRequest(id, period, limit) { - // console.log(id, period, limit) return httpFetch('https://u.y.qq.com/cgi-bin/musicu.fcg', { method: 'post', headers: { @@ -107,7 +106,6 @@ export default { return requestDataObj.promise }, filterData(rawList) { - // console.log(rawList) return rawList.map(item => { let types: SongType[] = [] let _types: Partial> = {} @@ -180,7 +178,6 @@ export default { }) }, filterBoardsData(rawList) { - // console.log(rawList) let list: any[] = [] for (const board of rawList) { // 排除 MV榜 @@ -198,24 +195,7 @@ export default { } return list }, - async getBoards(retryNum = 0) { - // if (++retryNum > 3) return Promise.reject(new Error('try max num')) - // let response - // try { - // response = await this.getBoardsData() - // } catch (error) { - // return this.getBoards(retryNum) - // } - // // console.log(response.body) - // if (response.statusCode !== 200 || response.body.code !== 0) return this.getBoards(retryNum) - // const list = this.filterBoardsData(response.body.data.topList) - // console.log(list) - // console.log(JSON.stringify(list)) - // this.list = list - // return { - // list, - // source: 'tx', - // } + async getBoards() { this.list = boardList return { list: boardList, diff --git a/sdk/tx/lyric.ts b/sdk/tx/lyric.ts index fdc11bd..6efbd6e 100644 --- a/sdk/tx/lyric.ts +++ b/sdk/tx/lyric.ts @@ -1,5 +1,4 @@ -import type { HttpRequestObject } from '../types.ts' -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import getMusicInfo from './musicInfo.ts' import { decodeQrc } from './qrcDecode.ts' @@ -111,8 +110,6 @@ const parseTools = { return parseInt(m) * 3600000 + parseInt(s) * 1000 + parseInt(ms) }, fixRlrcTimeTag(rlrc, lrc) { - // console.log(lrc) - // console.log(rlrc) const rlrcLines = rlrc.split('\n') let lrcLines = lrc.split('\n') // let temp: string[] = [] @@ -141,8 +138,6 @@ const parseTools = { return newLrc.join('\n') }, fixTlrcTimeTag(tlrc, lrc) { - // console.log(lrc) - // console.log(tlrc) const tlrcLines = tlrc.split('\n') let lrcLines = lrc.split('\n') // let temp: string[] = [] @@ -185,14 +180,9 @@ const parseTools = { let { lyric, yrc } = this.parseLyric(this.removeTag(lrc)) info.lyric = lyric info.yrc = yrc - // console.log(lyric) - // console.log(yrc) } if (rlrc) info.rlyric = this.fixRlrcTimeTag(this.parseRlyric(this.removeTag(rlrc)), info.lyric) if (tlrc) info.tlyric = this.fixTlrcTimeTag(tlrc, info.lyric) - // console.log(info.lyric) - // console.log(info.tlyric) - // console.log(info.rlyric) return info }, @@ -218,9 +208,6 @@ export default { // return { // } - // console.log(lyric) - // console.log(tlyric) - // console.log(rlyric) return parseTools.parse(lyric, tlyric, rlyric) }, getLyric(mInfo, retryNum = 0) { @@ -266,7 +253,6 @@ export default { }, }) return requestObj.promise.then(({ body }) => { - // console.log(body) if (body.code != this.successCode || body.req.code != this.successCode) return this.getLyric(songId, ++retryNum) const data = body.req.data return this.parseLyric(data.lyric, data.trans, data.roma) @@ -276,23 +262,3 @@ export default { }, } -// export default { -// regexps: { -// matchLrc: /.+"lyric":"([\w=+/]*)".+/, -// }, -// getLyric(songmid) { -// const requestObj = httpFetch(`https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg?songmid=${songmid}&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8&platform=yqq`, { -// headers: { -// Referer: 'https://y.qq.com/portal/player.html', -// }, -// }) -// requestObj.promise = requestObj.promise.then(({ body }) => { -// if (body.code != 0 || !body.lyric) return Promise.reject(new Error('Get lyric failed')) -// return { -// lyric: decodeName(b64DecodeUnicode(body.lyric)), -// tlyric: decodeName(b64DecodeUnicode(body.trans)), -// } -// }) -// return requestObj -// }, -// } diff --git a/sdk/tx/musicInfo.ts b/sdk/tx/musicInfo.ts index 0664664..21c4e51 100644 --- a/sdk/tx/musicInfo.ts +++ b/sdk/tx/musicInfo.ts @@ -1,5 +1,5 @@ -import type { HttpRequestObject, SongType, Quality, QualityInfo } from '../types.ts' -import { httpFetch } from '../request.ts' +import type { SongType, Quality, QualityInfo } from '../types.ts' +import { httpFetch } from '../common/request.ts' import { formatPlayTime, sizeFormate } from '../index.ts' const getSinger = (singers) => { @@ -33,7 +33,6 @@ export default (songmid) => { }, }) return requestObj.promise.then(({ body }) => { - // console.log(body) if (body.code != 0 || body.req.code != 0) return Promise.reject(new Error('获取歌曲信息失败')) const item = body.req.data.track_info if (!item.file?.media_mid) return null diff --git a/sdk/tx/musicSearch.ts b/sdk/tx/musicSearch.ts index 3fd7943..8357435 100644 --- a/sdk/tx/musicSearch.ts +++ b/sdk/tx/musicSearch.ts @@ -61,26 +61,13 @@ export default { }, }) return searchRequest.then(({ body }) => { - // console.log(body) if (!body || !body.req || body.code != this.successCode || body.req.code != this.successCode) { return this.musicSearch(str, page, limit, ++retryNum) } return body.req.data }) }, - // randomInt(min, max) { - // return Math.floor(Math.random() * (max - min + 1)) + min - // }, - // getSearchId() { - // const e = BigInt(this.randomInt(1, 20)) - // const t = e * 18014398509481984n - // const n = BigInt(this.randomInt(0, 4194304)) * 4294967296n - // const a = BigInt(Date.now()) - // const r = (a * 1000n) % (24n * 60n * 60n * 1000n) - // return String(t + n + r) - // }, handleResult(rawList) { - // console.log(rawList) if (!rawList || !Array.isArray(rawList)) return [] const list: SongInfo[] = [] rawList.forEach(item => { @@ -144,7 +131,6 @@ export default { typeUrl: {}, }) }) - // console.log(list) return list }, search(str, page = 1, limit) { diff --git a/sdk/tx/parse.ts b/sdk/tx/parse.ts index f8f144e..e3e7b5c 100644 --- a/sdk/tx/parse.ts +++ b/sdk/tx/parse.ts @@ -5,7 +5,7 @@ // https://i.y.qq.com/v8/playsong.html?songid=<数字 id>(先反查 songmid) // ...?songmid= // 返回 Song(含 songmid);直链 url/type 为尽力附带,失败不影响元数据返回(与上游一致)。 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { formatPlayTime, sizeFormate } from '../index.ts' import { formatSingerName } from '../utils.ts' import txApi from '../apis/tx.ts' diff --git a/sdk/tx/playlist.ts b/sdk/tx/playlist.ts index 1a2a788..2a34b24 100644 --- a/sdk/tx/playlist.ts +++ b/sdk/tx/playlist.ts @@ -2,7 +2,7 @@ // 搜索/分类复用现有 sdk/tx/songList.ts(handleParseId / getListId / getListDetail / getTag / getList) // 推荐:musicu.fcg playlist.HotRecommendServer/get_hot_recommend(上游 GetRecommendedPlaylists) // 链接解析:extractPlaylistId 为上游 extractQQPlaylistID 的 1:1 移植(含单测用例断言) -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { formatPlayCount } from '../index.ts' import songList from './songList.ts' diff --git a/sdk/tx/songList.ts b/sdk/tx/songList.ts index 6a07aa9..cef59a8 100644 --- a/sdk/tx/songList.ts +++ b/sdk/tx/songList.ts @@ -1,5 +1,5 @@ import type { HttpRequestObject, SongType, Quality, QualityInfo } from '../types.ts' -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { decodeName, formatPlayTime, sizeFormate, dateFormat, formatPlayCount } from '../index.ts' import { formatSingerName } from '../utils.ts' @@ -120,7 +120,6 @@ export default { this._requestObj_list = httpFetch( this.getListUrl(sortId, tagId, page), ) - // console.log(this.getListUrl(sortId, tagId, page)) return this._requestObj_list!.promise.then(({ body }) => { if (body.code !== this.successCode) return this.getList(sortId, tagId, page, ++tryNum) return tagId ? this.filterList2(body.playlist.data, page) : this.filterList(body.playlist.data, page) @@ -148,7 +147,6 @@ export default { } }, filterList2({ content }, page) { - // console.log(content.v_item) return { list: content.v_item.map(({ basic }) => ({ play_count: formatPlayCount(basic.play_cnt), @@ -173,7 +171,6 @@ export default { const requestObj_listDetailLink = httpFetch(link) const { headers: { location }, statusCode } = await requestObj_listDetailLink.promise - // console.log(headers) if (statusCode > 400) return this.handleParseId(link, ++retryNum) return location == null ? link : location }, @@ -189,7 +186,6 @@ export default { if (!result) throw new Error('failed') } id = result[1] - // console.log(id) } return id }, @@ -225,7 +221,6 @@ export default { } }, filterListDetail(rawList) { - // console.log(rawList) return rawList.map(item => { let types: SongType[] = [] let _types: Partial> = {} @@ -300,7 +295,6 @@ export default { }) .promise.then(({ body }) => { if (body.code != 0) return this.search(text, page, limit, ++retryNum) - // console.log(body.data.list) return { list: body.data.list.map(item => { return { diff --git a/sdk/tx/userPlaylist.ts b/sdk/tx/userPlaylist.ts index 1cd9f17..62b7d62 100644 --- a/sdk/tx/userPlaylist.ts +++ b/sdk/tx/userPlaylist.ts @@ -6,7 +6,7 @@ // 2) fcg_get_profile_order_asset reqtype=3 → 收藏歌单 // 3) fcg_get_profile_order_asset reqtype=1 → 「我喜欢的歌曲」虚拟歌单摘要(有歌才附上) // 说明:虚拟条目的 id 为 profile:favorites(与上游一致),歌曲需凭 cookie 走同一接口拉取 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { formatPlayCount } from '../index.ts' import { getCredentials } from '../auth/store.ts' import type { TxCredentials } from '../auth/store.ts' diff --git a/sdk/tx/utils/index.ts b/sdk/tx/utils/index.ts index f2b3753..1976c76 100644 --- a/sdk/tx/utils/index.ts +++ b/sdk/tx/utils/index.ts @@ -1,12 +1,8 @@ -import type { HttpRequestObject } from '../../types.ts' - -import { httpFetch } from '../../request.ts' +import { httpFetch } from '../../common/request.ts' import { zzcSign } from './crypto.ts' export const signRequest = async(data) => { - // console.log(data) const sign = await zzcSign(JSON.stringify(data)) - // console.log('sign', sign) return httpFetch(`https://u.y.qq.com/cgi-bin/musics.fcg?sign=${sign}`, { method: 'post', headers: { @@ -36,7 +32,7 @@ export const createMusicuFetch = async(data, retryNum = 0) => { }, }).promise } catch (err) { - console.log(err) + console.warn(`[tx] musicu 请求失败将重试(${retryNum + 1}/3): ${(err as Error).message}`) return createMusicuFetch(data, ++retryNum) } if (result.statusCode !== 200 || result.body.code != 0) return createMusicuFetch(data, ++retryNum) diff --git a/sdk/utils.ts b/sdk/utils.ts index 4e8744c..4184328 100644 --- a/sdk/utils.ts +++ b/sdk/utils.ts @@ -20,7 +20,7 @@ export const getHostIp = (hostname: string): CachedIp | undefined => { // family: 4, all: false, }, (err, address, family) => { - if (err) return console.log(err) + if (err) return console.warn(`[utils] DNS 预解析 ${hostname} 失败: ${err.message}`) ipMap.set(hostname, { address, family }) }) } diff --git a/sdk/wy/album.ts b/sdk/wy/album.ts index 43d22a1..628058a 100644 --- a/sdk/wy/album.ts +++ b/sdk/wy/album.ts @@ -2,7 +2,7 @@ // 搜索:cloudsearch pc type=10(eapi 通道,与现有 songList.search 同一通路) // 详情/曲目:weapi/v1/album/(匿名可用;登录 cookie 可选) // 链接解析:#/album?id= / /album?id= / /album/(上游 parseNeteaseLink) -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { weapi } from './utils/crypto.ts' import { formatPlayTime, sizeFormate } from '../index.ts' import { formatSingerName } from '../utils.ts' diff --git a/sdk/wy/comment.ts b/sdk/wy/comment.ts index b63b7e9..a6998f3 100644 --- a/sdk/wy/comment.ts +++ b/sdk/wy/comment.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { weapi } from './utils/crypto.ts' import { dateFormat2 } from '../index.ts' import type { HttpRequestObject } from '../types.ts' @@ -149,7 +149,6 @@ export default { }), }) const { body, statusCode } = await _requestObj.promise - // console.log(body) if (statusCode != 200 || body.code !== 200) throw new Error('获取评论失败') cursorTools.setCursor(songmid, body.data.cursor, cursorInfo.orderType, cursorInfo.offset, page) return { source: 'wy', comments: this.filterComment(body.data.comments), total: body.data.totalCount, page, limit, maxPage: Math.ceil(body.data.totalCount / limit) || 1 } diff --git a/sdk/wy/leaderboard.ts b/sdk/wy/leaderboard.ts index f04cb26..ed570a1 100644 --- a/sdk/wy/leaderboard.ts +++ b/sdk/wy/leaderboard.ts @@ -1,5 +1,5 @@ import { weapi } from './utils/crypto.ts' -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import musicDetailApi from './musicDetail.ts' import type { HttpRequestObject } from '../types.ts' @@ -129,7 +129,6 @@ export default { }, filterBoardsData(rawList) { - // console.log(rawList) let list: any[] = [] for (const board of rawList) { // 排除 MV榜 @@ -142,24 +141,7 @@ export default { } return list }, - async getBoards(retryNum = 0) { - // if (++retryNum > 3) return Promise.reject(new Error('try max num')) - // let response - // try { - // response = await this.getBoardsData() - // } catch (error) { - // return this.getBoards(retryNum) - // } - // console.log(response.body) - // if (response.statusCode !== 200 || response.body.code !== 200) return this.getBoards(retryNum) - // const list = this.filterBoardsData(response.body.list) - // console.log(list) - // console.log(JSON.stringify(list)) - // this.list = list - // return { - // list, - // source: 'wy', - // } + async getBoards() { this.list = topList return { list: topList, @@ -168,7 +150,6 @@ export default { }, async getList(bangid, page, retryNum = 0) { if (++retryNum > 6) return Promise.reject(new Error('try max num')) - // console.log(bangid) let resp try { resp = await this.getData(bangid) @@ -180,19 +161,17 @@ export default { } } if (resp.statusCode !== 200 || resp.body.code !== 200) return this.getList(bangid, page, retryNum) - // console.log(resp.body) let musicDetail try { musicDetail = await (musicDetailApi as any).getList(resp.body.playlist.trackIds.map(trackId => trackId.id)) } catch (err: any) { - console.log(err) + console.warn(`[wy] 榜单歌曲详情获取失败将重试(${retryNum + 1}): ${err.message}`) if (err.message == 'try max num') { throw err } else { return this.getList(bangid, page, retryNum) } } - // console.log(musicDetail) return { total: musicDetail.list.length, list: musicDetail.list, diff --git a/sdk/wy/lyric.ts b/sdk/wy/lyric.ts index 1007a6f..b7eb195 100644 --- a/sdk/wy/lyric.ts +++ b/sdk/wy/lyric.ts @@ -1,39 +1,6 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { eapi } from './utils/crypto.ts' -import type { LyricInfo, HttpRequestObject } from '../types.ts' -// import { decodeName } from '../...ts' - -// const parseLyric = (str, lrc) => { -// if (!str) return '' - -// str = str.replace(/\r/g, '') - -// let yrc = str.replace(/\[((\d+),\d+)\].*/g, str => { -// let result = str.match(/\[((\d+),\d+)\].*/) -// let time = parseInt(result[2]) -// let ms = time % 1000 -// time /= 1000 -// let m = parseInt(time / 60).toString().padStart(2, '0') -// time %= 60 -// let s = parseInt(time).toString().padStart(2, '0') -// time = `${m}:${s}.${ms}` -// str = str.replace(result[1], time) - -// let startTime = 0 -// str = str.replace(/\(0,1\) /g, ' ').replace(/\(\d+,\d+\)/g, time => { -// const [start, end] = time.replace(/^\((\d+,\d+)\)$/, '$1').split(',') - -// time = `<${parseInt(startTime + parseInt(start))},${end}>` -// startTime = parseInt(startTime + parseInt(end)) -// return time -// }) - -// return str -// }) - -// yrc = decodeName(yrc) -// return yrc.trim() -// } +import type { HttpRequestObject } from '../types.ts' const eapiRequest = (url: string, data: object) => { return httpFetch('https://interface3.music.163.com/eapi/song/lyric/v1', { @@ -41,18 +8,9 @@ const eapiRequest = (url: string, data: object) => { headers: { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36', origin: 'https://music.163.com', - // cookie: 'os=pc; deviceId=A9C064BB4584D038B1565B58CB05F95290998EE8B025AA2D07AE; osver=Microsoft-Windows-10-Home-China-build-19043-64bit; appver=2.5.2.197409; channel=netease; MUSIC_A=37a11f2eb9de9930cad479b2ad495b0e4c982367fb6f909d9a3f18f876c6b49faddb3081250c4980dd7e19d4bd9bf384e004602712cf2b2b8efaafaab164268a00b47359f85f22705cc95cb6180f3aee40f5be1ebf3148d888aa2d90636647d0c3061cd18d77b7a0; __csrf=05b50d54082694f945d7de75c210ef94; mode=Z7M-KP5(7)GZ; NMTID=00OZLp2VVgq9QdwokUgq3XNfOddQyIAAAF_6i8eJg; ntes_kaola_ad=1', }, form: eapi(url, data), }) - // requestObj.promise = requestObj.promise.then(({ body }) => { - // // console.log(raw) - // console.log(body) - // // console.log(eapiDecrypt(raw)) - // // return eapiDecrypt(raw) - // return body - // }) - // return requestObj } const parseTools = { @@ -218,35 +176,6 @@ const parseTools = { } -// https://github.com/Binaryify/NeteaseCloudMusicApi/pull/1523/files -// export default songmid => { -// const requestObj = httpFetch('https://music.163.com/api/linux/forward', { -// method: 'post', -// 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36', -// form: linuxapi({ -// method: 'POST', -// url: 'https://music.163.com/api/song/lyric?_nmclfl=1', -// params: { -// id: songmid, -// tv: -1, -// lv: -1, -// rv: -1, -// kv: -1, -// }, -// }), -// }) -// requestObj.promise = requestObj.promise.then(({ body }) => { -// if (body.code !== 200 || !body?.lrc?.lyric) return Promise.reject(new Error('Get lyric failed')) -// // console.log(body) -// return { -// lyric: body.lrc.lyric, -// tlyric: body.tlyric?.lyric ?? '', -// rlyric: body.romalrc?.lyric ?? '', -// // yrc: parseLyric(body.klyric.lyric), -// } -// }) -// return requestObj -// } // 参考社区通用的歌词时间标签修正思路 const fixTimeLabel = (lrc: string, tlrc?: string, romalrc?: string) => { @@ -277,11 +206,9 @@ export default (songmid: string): HttpRequestObject => { yrv: 0, }) requestObj.promise = requestObj.promise.then(({ body }) => { - // console.log(body) if (body.code !== 200 || !body?.lrc?.lyric) return Promise.reject(new Error('Get lyric failed')) const fixTimeLabelLrc = fixTimeLabel(body.lrc.lyric, body.tlyric?.lyric, body.romalrc?.lyric) const info = parseTools.parse(body.yrc?.lyric, body.ytlrc?.lyric, body.yromalrc?.lyric, fixTimeLabelLrc.lrc, fixTimeLabelLrc.tlrc, fixTimeLabelLrc.romalrc) - // console.log(info) if (!info.lyric) return Promise.reject(new Error('Get lyric failed')) return info }) as any diff --git a/sdk/wy/musicDetail.ts b/sdk/wy/musicDetail.ts index 84cd6e8..e068157 100644 --- a/sdk/wy/musicDetail.ts +++ b/sdk/wy/musicDetail.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { weapi } from './utils/crypto.ts' import { formatPlayTime, sizeFormate } from '../index.ts' // https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/song_detail.js @@ -12,7 +12,6 @@ export default { return arr.join('、') }, filterList({ songs, privileges }) { - // console.log(songs, privileges) const list: any[] = [] songs.forEach((item, index) => { const types: Array<{ type: string, size: string | null }> = [] @@ -87,7 +86,6 @@ export default { }) } }) - // console.log(list) return list }, async getList(ids = [], retryNum = 0) { @@ -106,7 +104,6 @@ export default { }) const { body, statusCode } = await requestObj.promise if (statusCode != 200 || body.code !== 200) throw new Error('获取歌曲详情失败') - // console.log(body) return { source: 'wy', list: this.filterList(body) } }, } diff --git a/sdk/wy/musicInfo.ts b/sdk/wy/musicInfo.ts index 3c54bb0..4521733 100644 --- a/sdk/wy/musicInfo.ts +++ b/sdk/wy/musicInfo.ts @@ -1,5 +1,5 @@ // https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/song_detail.js -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { weapi } from './utils/crypto.ts' import type { RequestObj } from '../types.ts' @@ -17,7 +17,6 @@ export default (songmid: string): RequestObj => { }), }) requestObj.promise = requestObj.promise.then(({ body }) => { - // console.log(body) if (body.code !== 200 || !body.songs.length) return Promise.reject(new Error('获取歌曲信息失败')) return body.songs[0] }) diff --git a/sdk/wy/musicSearch.ts b/sdk/wy/musicSearch.ts index 7664d5a..3d340c5 100644 --- a/sdk/wy/musicSearch.ts +++ b/sdk/wy/musicSearch.ts @@ -1,4 +1,4 @@ -// import { httpFetch } from '../request.ts' +// import { httpFetch } from '../common/request.ts' // import { weapi } from './utils/crypto.ts' import { sizeFormate, formatPlayTime } from '../index.ts' // import musicDetailApi from './musicDetail.ts' @@ -36,7 +36,6 @@ export default { return arr.join('、') }, handleResult(rawList) { - // console.log(rawList) if (!rawList) return [] return rawList.map(item => { item = item.baseInfo.simpleSongData @@ -95,10 +94,8 @@ export default { if (++retryNum > 3) return Promise.reject(new Error('try max num')) if (limit == null) limit = this.limit return this.musicSearch(str, page, limit).then(result => { - // console.log(result) if (!result || result.code !== 200) return this.search(str, page, limit, retryNum) let list = this.handleResult(result.data.resources || []) - // console.log(list) if (list == null) return this.search(str, page, limit, retryNum) diff --git a/sdk/wy/parse.ts b/sdk/wy/parse.ts index 6276d37..b8602b4 100644 --- a/sdk/wy/parse.ts +++ b/sdk/wy/parse.ts @@ -6,7 +6,7 @@ // 裸数字 id 也接受(补充便利;上游仅接受链接) // 直链 url/type 为尽力附带,失败不影响元数据返回(与上游一致); // 歌单/专辑链接抛清晰错误,提示使用对应 parsePlaylist/parseAlbum。 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { weapi } from './utils/crypto.ts' import { getWyCookie } from '../auth/store.ts' import wyApi from '../apis/wy.ts' diff --git a/sdk/wy/playlist.ts b/sdk/wy/playlist.ts index 0116688..ca0c3dc 100644 --- a/sdk/wy/playlist.ts +++ b/sdk/wy/playlist.ts @@ -3,7 +3,7 @@ // 推荐:weapi/personalized/playlist(上游 GetRecommendedPlaylists,匿名可用) // 详情/曲目:复用 songList.getListDetail(linuxapi forward),按 page/limit 切片 // 链接解析:#/playlist?id= / /playlist?id= / /playlist///... / 裸数字 id(上游 parseNeteaseLink) -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { weapi } from './utils/crypto.ts' import { formatPlayCount } from '../index.ts' import { getWyCookie } from '../auth/store.ts' diff --git a/sdk/wy/songList.ts b/sdk/wy/songList.ts index 43858d9..58170e9 100644 --- a/sdk/wy/songList.ts +++ b/sdk/wy/songList.ts @@ -4,7 +4,7 @@ // https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/playlist_detail.js import { weapi, linuxapi } from './utils/crypto.ts' -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { formatPlayTime, sizeFormate, dateFormat, formatPlayCount } from '../index.ts' import musicDetailApi from './musicDetail.ts' import { eapiRequest } from './utils/index.ts' @@ -39,7 +39,6 @@ export default { const requestObj_listDetailLink = httpFetch(link) const { headers: { location }, statusCode } = await requestObj_listDetailLink.promise - // console.log(headers) if (statusCode > 400) return this.handleParseId(link, ++retryNum) const url = location == null ? link : location return this.regExps.listDetailLink.test(url) @@ -62,7 +61,6 @@ export default { } else { id = await this.handleParseId(id) } - // console.log(id) } return { id, cookie } }, @@ -92,7 +90,6 @@ export default { if (statusCode !== 200 || body.code !== this.successCode) return this.getListDetail(id, page, ++tryNum) let limit = 1000 let rangeStart = (page - 1) * limit - // console.log(body) let list if (body.playlist.trackIds.length == body.privileges.length) { list = this.filterListDetail(body) @@ -100,7 +97,7 @@ export default { try { list = (await (musicDetailApi as any).getList(body.playlist.trackIds.slice(rangeStart, limit * page).map(trackId => trackId.id))).list } catch (err: any) { - console.log(err) + console.warn(`[wy] 歌单歌曲详情获取失败将重试(${tryNum + 1}): ${err.message}`) if (err.message == 'try max num') { throw err } else { @@ -108,7 +105,6 @@ export default { } } } - // console.log(list) return { list, page, @@ -125,7 +121,6 @@ export default { } }, filterListDetail({ playlist: { tracks }, privileges }) { - // console.log(tracks, privileges) const list: any[] = [] tracks.forEach((item, index) => { const types: Array<{ type: string, size: string | null }> = [] @@ -218,7 +213,6 @@ export default { }), }) return this._requestObj_list!.promise.then(({ body }) => { - // console.log(body) if (body.code !== this.successCode) return this.getList(sortId, tagId, page, ++tryNum) return { list: this.filterList(body.playlists), @@ -230,7 +224,6 @@ export default { }) }, filterList(rawData) { - // console.log(rawData) return rawData.map(item => ({ play_count: formatPlayCount(item.playCount), id: String(item.id), @@ -254,7 +247,6 @@ export default { form: weapi({}), }) return this._requestObj_tags!.promise.then(({ body }) => { - // console.log(JSON.stringify(body)) if (body.code !== this.successCode) return this.getTag(++tryNum) return this.filterTagInfo(body) }) @@ -292,7 +284,6 @@ export default { form: weapi({}), }) return this._requestObj_hotTags!.promise.then(({ body }) => { - // console.log(JSON.stringify(body)) if (body.code !== this.successCode) return this.getTag(++tryNum) return this.filterHotTagInfo(body.tags) }) @@ -324,7 +315,6 @@ export default { }) .promise.then(({ body }) => { if (body.code != this.successCode) throw new Error('filed') - // console.log(body) return { list: this.filterList(body.result.playlists), limit, diff --git a/sdk/wy/userPlaylist.ts b/sdk/wy/userPlaylist.ts index 9c9332b..145977c 100644 --- a/sdk/wy/userPlaylist.ts +++ b/sdk/wy/userPlaylist.ts @@ -3,7 +3,7 @@ // 未登录抛出清晰错误,不返回空列表 // 1) weapi/nuser/account/get → 当前用户 userId // 2) weapi/user/playlist → 用户歌单列表(分页 limit/offset) -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { weapi } from './utils/crypto.ts' import { formatPlayCount } from '../index.ts' import { getCredentials, getWyCookie } from '../auth/store.ts' diff --git a/sdk/wy/utils/index.ts b/sdk/wy/utils/index.ts index 30b0f32..36981a7 100644 --- a/sdk/wy/utils/index.ts +++ b/sdk/wy/utils/index.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../../request.ts' +import { httpFetch } from '../../common/request.ts' import { eapi } from './crypto.ts' import { getWyCookie } from '../../auth/store.ts' import type { HttpRequestObject } from '../../types.ts' @@ -15,12 +15,4 @@ export const eapiRequest = (url: string, data: object): HttpRequestObject => { }, form: eapi(url, data), }) - // requestObj.promise = requestObj.promise.then(({ body }) => { - // // console.log(raw) - // console.log(body) - // // console.log(eapiDecrypt(raw)) - // // return eapiDecrypt(raw) - // return body - // }) - // return requestObj } diff --git a/sdk/xm/album.ts b/sdk/xm/album.ts index 1399076..6f9fa94 100644 --- a/sdk/xm/album.ts +++ b/sdk/xm/album.ts @@ -2,7 +2,7 @@ // 接口: https://www.ximalaya.com/revision/album/getTracksList?albumId=&pageNum=&sort=0 // 实测(2026-10-02)匿名可翻全部页(固定每页 30 条);仅曲目元信息(trackId/title/isPaid), // 播放地址需另走 baseInfo。注意 v1 版接口(/revision/album/v1/getTracksList)需要 webtk 签名且有风控。 -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { XM_UA } from './sign.ts' const TRACKS_URL = 'https://www.ximalaya.com/revision/album/getTracksList' diff --git a/sdk/xm/musicInfo.ts b/sdk/xm/musicInfo.ts index ab3805a..13091ff 100644 --- a/sdk/xm/musicInfo.ts +++ b/sdk/xm/musicInfo.ts @@ -7,7 +7,7 @@ // 响应 trackInfo 顶层挂载(playUrlList/title/cover*/duration/isPaid/isAuthorized/isXimiUhqTrack), // playUrlList[].url 为 AES-ECB 加密地址(key 取自官方客户端 4.0.14 asar),见 decoder.ts import crypto from 'node:crypto' -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { makeXmSign, XM_UA } from './sign.ts' import { getCredentials } from '../auth/store.ts' diff --git a/sdk/xm/musicSearch.ts b/sdk/xm/musicSearch.ts index 65507b8..2de4cd5 100644 --- a/sdk/xm/musicSearch.ts +++ b/sdk/xm/musicSearch.ts @@ -4,7 +4,7 @@ // risk invalid 风控,本端点 + condition=relation&device=web 不受影响) // 返回 data.result.response.docs[],字段 id/title/duration(秒)/nickname/album_id/album_title/ // album_cover_path/is_paid/is_trailer -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { formatPlayTime } from '../index.ts' import { XM_UA } from './sign.ts' diff --git a/sdk/xm/sign.ts b/sdk/xm/sign.ts index 37bb956..8bbfdea 100644 --- a/sdk/xm/sign.ts +++ b/sdk/xm/sign.ts @@ -7,7 +7,7 @@ import zlib from 'node:zlib' import crypto from 'node:crypto' -import { httpFetch } from '../request.ts' +import { httpFetch } from '../common/request.ts' import { DEVICE_INFO } from './deviceInfo.ts' const SIGN_KEY = 'm9ZtRrz:qujT8@da' diff --git a/src/routes-login.ts b/src/routes-login.ts index 5b5eba9..3c3e3d4 100644 --- a/src/routes-login.ts +++ b/src/routes-login.ts @@ -431,7 +431,7 @@ export const loginRoutes = async(fastify) => { description: '用 B站 App 扫码后轮询 /login/bl/qr/check 完成登录。返回 key 需原样回传,qrimg 为 data URL 可直接展示。', tags: ['登录'], }, - }, async(request, reply) => { + }, async(_request, reply) => { try { return await biliAuth.createQRLogin() } catch (err) {