From fcbc74dbc070aa426abea17337f3d41cf5dfc22c Mon Sep 17 00:00:00 2001 From: lyswhut Date: Sat, 2 Mar 2024 15:33:16 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dmg=E6=AD=8C=E5=8D=95=E6=90=9C?= =?UTF-8?q?=E7=B4=A2=E3=80=81=E4=B8=8D=E5=86=8D=E4=B8=A2=E5=BC=83kg?= =?UTF-8?q?=E6=BA=90=E9=80=90=E8=A1=8C=E6=AD=8C=E8=AF=8D=EF=BC=88@helloplh?= =?UTF-8?q?m-qwq,=20@Folltoshe=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- publish/changeLog.md | 6 + src/utils/musicSdk/kg/lyric.js | 27 +++-- src/utils/musicSdk/kg/songList.js | 4 +- src/utils/musicSdk/kg/temp/songList-new.js | 10 +- src/utils/musicSdk/kg/util.js | 6 +- src/utils/musicSdk/kw/leaderboard.js | 131 +++++++++++++-------- src/utils/musicSdk/kw/util.js | 44 +++++++ src/utils/musicSdk/mg/songList.js | 2 +- 8 files changed, 160 insertions(+), 70 deletions(-) diff --git a/publish/changeLog.md b/publish/changeLog.md index 9528733..427f18e 100644 --- a/publish/changeLog.md +++ b/publish/changeLog.md @@ -2,9 +2,15 @@ - 新增棕色主题“泥牛入海” +### 优化 + +- 不再丢弃kg源逐行歌词(@helloplhm-qwq) +- 支持kw源排行榜显示大小(revert @Folltoshe #1460) + ### 修复 - 修复mg歌词在某些情况下获取失败的问题 +- 修复mg歌单搜索(@helloplhm-qwq) - 修复kg最新评论无法获取的问题(@helloplhm-qwq) ### 其他 diff --git a/src/utils/musicSdk/kg/lyric.js b/src/utils/musicSdk/kg/lyric.js index ab6d341..c1a7b64 100644 --- a/src/utils/musicSdk/kg/lyric.js +++ b/src/utils/musicSdk/kg/lyric.js @@ -89,7 +89,7 @@ export default { // 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}`, { + let requestObj = httpFetch(`http://lyrics.kugou.com/search?ver=1&man=yes&client=pc&keyword=${encodeURIComponent(name)}&hash=${hash}&timelength=${time}&lrctxt=1`, { headers: { 'KG-RC': 1, 'KG-THash': 'expand_search_manager.cpp:852736169:451', @@ -105,14 +105,14 @@ export default { } if (body.candidates.length) { let info = body.candidates[0] - return { id: info.id, accessKey: info.accesskey } + return { id: info.id, accessKey: info.accesskey, fmt: (info.krctype == 1 && info.contenttype != 1) ? 'krc' : 'lrc' } } return null }) return requestObj }, - getLyricDownload(id, accessKey, tryNum = 0) { - let requestObj = httpFetch(`http://lyrics.kugou.com/download?ver=1&client=pc&id=${id}&accesskey=${accessKey}&fmt=krc&charset=utf8`, { + getLyricDownload(id, accessKey, fmt, tryNum = 0) { + let requestObj = httpFetch(`http://lyrics.kugou.com/download?ver=1&client=pc&id=${id}&accesskey=${accessKey}&fmt=${fmt}&charset=utf8`, { headers: { 'KG-RC': 1, 'KG-THash': 'expand_search_manager.cpp:852736169:451', @@ -122,13 +122,26 @@ export default { requestObj.promise = requestObj.promise.then(({ body, statusCode }) => { if (statusCode !== 200) { if (tryNum > 5) return Promise.reject(new Error('歌词获取失败')) - let tryRequestObj = this.getLyric(id, accessKey, ++tryNum) + let tryRequestObj = this.getLyric(id, accessKey, fmt, ++tryNum) requestObj.cancelHttp = tryRequestObj.cancelHttp.bind(tryRequestObj) return tryRequestObj.promise } - return decodeLyric(body.content).then(result => parseLyric(result)) + switch (body.fmt) { + case 'krc': + return decodeLyric(body.content).then(result => parseLyric(result)) + case 'lrc': + return { + lyric: Buffer.from(body.content, 'base64').toString('utf-8'), + tlyric: '', + rlyric: '', + lxlyric: '', + } + default: + return Promise.reject(new Error(`未知歌词格式: ${body.fmt}`)) + } }) + return requestObj }, getLyric(songInfo, tryNum = 0) { @@ -137,7 +150,7 @@ export default { requestObj.promise = requestObj.promise.then(result => { if (!result) return Promise.reject(new Error('Get lyric failed')) - let requestObj2 = this.getLyricDownload(result.id, result.accessKey) + let requestObj2 = this.getLyricDownload(result.id, result.accessKey, result.fmt) requestObj.cancelHttp = requestObj2.cancelHttp.bind(requestObj2) diff --git a/src/utils/musicSdk/kg/songList.js b/src/utils/musicSdk/kg/songList.js index d3725f8..8e18ed7 100644 --- a/src/utils/musicSdk/kg/songList.js +++ b/src/utils/musicSdk/kg/songList.js @@ -462,7 +462,7 @@ export default { total -= limit page += 1 const params = 'appid=1058&global_specialid=' + id + '&specialid=0&plat=0&version=8000&page=' + page + '&pagesize=' + limit + '&srcappid=2919&clientver=20000&clienttime=1586163263991&mid=1586163263991&uuid=1586163263991&dfid=-' - tasks.push(this.createHttp(`https://mobiles.kugou.com/api/v5/special/song_v2?${params}&signature=${signatureParams(params, 5)}`, { + tasks.push(this.createHttp(`https://mobiles.kugou.com/api/v5/special/song_v2?${params}&signature=${signatureParams(params, 'web')}`, { headers: { mid: '1586163263991', Referer: 'https://m3ws.kugou.com/share/index.php', @@ -478,7 +478,7 @@ export default { let id = global_collection_id if (id.length > 1000) throw new Error('get list error') const params = 'appid=1058&specialid=0&global_specialid=' + id + '&format=jsonp&srcappid=2919&clientver=20000&clienttime=1586163242519&mid=1586163242519&uuid=1586163242519&dfid=-' - let info = await this.createHttp(`https://mobiles.kugou.com/api/v5/special/info_v2?${params}&signature=${signatureParams(params, 5)}`, { + let info = await this.createHttp(`https://mobiles.kugou.com/api/v5/special/info_v2?${params}&signature=${signatureParams(params, 'web')}`, { headers: { mid: '1586163242519', Referer: 'https://m3ws.kugou.com/share/index.php', diff --git a/src/utils/musicSdk/kg/temp/songList-new.js b/src/utils/musicSdk/kg/temp/songList-new.js index 389e93c..2ed7586 100644 --- a/src/utils/musicSdk/kg/temp/songList-new.js +++ b/src/utils/musicSdk/kg/temp/songList-new.js @@ -254,7 +254,7 @@ export default { if (this.collectionIdListInfoCache.has(id)) return this.collectionIdListInfoCache.get(id) const params = `appid=1058&specialid=0&global_specialid=${id}&format=jsonp&srcappid=2919&clientver=20000&clienttime=1586163242519&mid=1586163242519&uuid=1586163242519&dfid=-` - return createHttpFetch(`https://mobiles.kugou.com/api/v5/special/info_v2?${params}&signature=${signatureParams(params, 5)}`, { + return createHttpFetch(`https://mobiles.kugou.com/api/v5/special/info_v2?${params}&signature=${signatureParams(params, 'web')}`, { headers: { mid: '1586163242519', Referer: 'https://m3ws.kugou.com/share/index.php', @@ -321,7 +321,7 @@ export default { const listInfo = await this.getUserListInfoByCollectionId(id) const params = `need_sort=1&module=CloudMusic&clientver=11589&pagesize=${limit}&global_collection_id=${id}&userid=0&page=${page}&type=0&area_code=1&appid=1005` - return createHttpFetch(`http://pubsongs.kugou.com/v2/get_other_list_file?${params}&signature=${signatureParams(params, 2)}`, { + return createHttpFetch(`http://pubsongs.kugou.com/v2/get_other_list_file?${params}&signature=${signatureParams(params, 'android')}`, { headers: { 'User-Agent': 'Android10-AndroidPhone-11589-201-0-playlist-wifi', }, @@ -539,7 +539,7 @@ export default { total -= limit page += 1 const params = 'appid=1058&global_specialid=' + id + '&specialid=0&plat=0&version=8000&page=' + page + '&pagesize=' + limit + '&srcappid=2919&clientver=20000&clienttime=1586163263991&mid=1586163263991&uuid=1586163263991&dfid=-' - tasks.push(createHttpFetch(`https://mobiles.kugou.com/api/v5/special/song_v2?${params}&signature=${signatureParams(params, 5)}`, { + tasks.push(createHttpFetch(`https://mobiles.kugou.com/api/v5/special/song_v2?${params}&signature=${signatureParams(params, 'web')}`, { headers: { mid: '1586163263991', Referer: 'https://m3ws.kugou.com/share/index.php', @@ -555,7 +555,7 @@ export default { let id = global_collection_id if (id.length > 1000) throw new Error('get list error') const params = 'appid=1058&specialid=0&global_specialid=' + id + '&format=jsonp&srcappid=2919&clientver=20000&clienttime=1586163242519&mid=1586163242519&uuid=1586163242519&dfid=-' - let info = await createHttpFetch(`https://mobiles.kugou.com/api/v5/special/info_v2?${params}&signature=${signatureParams(params, 5)}`, { + let info = await createHttpFetch(`https://mobiles.kugou.com/api/v5/special/info_v2?${params}&signature=${signatureParams(params, 'web')}`, { headers: { mid: '1586163242519', Referer: 'https://m3ws.kugou.com/share/index.php', @@ -760,7 +760,7 @@ export default { search(text, page, limit = 20) { const params = `userid=1384394652&req_custom=1&appid=1005&req_multi=1&version=11589&page=${page}&filter=0&pagesize=${limit}&order=0&clienttime=1681779443&iscorrection=1&searchsong=0&keyword=${text}&mid=288799920684148686226285199951543865551&dfid=3eSBsO1u97EY1zeIZd40hH4p&clientver=11589&platform=AndroidFilter` - const url = encodeURI(`http://complexsearchretry.kugou.com/v1/search/special?${params}&signature=${signatureParams(params, 1)}`) + const url = encodeURI(`http://complexsearchretry.kugou.com/v1/search/special?${params}&signature=${signatureParams(params, 'android')}`) return createHttpFetch(url).then(body => { // console.log(body) return { diff --git a/src/utils/musicSdk/kg/util.js b/src/utils/musicSdk/kg/util.js index e315d58..dc006e7 100644 --- a/src/utils/musicSdk/kg/util.js +++ b/src/utils/musicSdk/kg/util.js @@ -28,12 +28,12 @@ export const decodeLyric = str => new Promise((resolve, reject) => { * @param {*} params * @param {*} apiver */ -export const signatureParams = (params, apiver = 9) => { +export const signatureParams = (params, platform = 'android', body = '') => { let keyparam = 'OIlwieks28dk2k092lksi2UIkp' - if (apiver === 5) keyparam = 'NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt' + if (platform === 'web') keyparam = 'NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt' let param_list = params.split('&') param_list.sort() - let sign_params = `${keyparam}${param_list.join('')}${keyparam}` + let sign_params = `${keyparam}${param_list.join('')}${body}${keyparam}` return toMD5(sign_params) } diff --git a/src/utils/musicSdk/kw/leaderboard.js b/src/utils/musicSdk/kw/leaderboard.js index 5756ea7..6d5e5d1 100644 --- a/src/utils/musicSdk/kw/leaderboard.js +++ b/src/utils/musicSdk/kw/leaderboard.js @@ -1,9 +1,35 @@ import { httpFetch } from '../../request' import { formatPlayTime, decodeName } from '../../index' -import { formatSinger } from './util' +import { formatSinger, wbdCrypto } from './util' + const boardList = [{ id: 'kw__93', name: '飙升榜', bangid: '93' }, { id: 'kw__17', name: '新歌榜', bangid: '17' }, { id: 'kw__16', name: '热歌榜', bangid: '16' }, { id: 'kw__158', name: '抖音热歌榜', bangid: '158' }, { id: 'kw__292', name: '铃声榜', bangid: '292' }, { id: 'kw__284', name: '热评榜', bangid: '284' }, { id: 'kw__290', name: 'ACG新歌榜', bangid: '290' }, { id: 'kw__286', name: '台湾KKBOX榜', bangid: '286' }, { id: 'kw__279', name: '冬日暖心榜', bangid: '279' }, { id: 'kw__281', name: '巴士随身听榜', bangid: '281' }, { id: 'kw__255', name: 'KTV点唱榜', bangid: '255' }, { id: 'kw__280', name: '家务进行曲榜', bangid: '280' }, { id: 'kw__282', name: '熬夜修仙榜', bangid: '282' }, { id: 'kw__283', name: '枕边轻音乐榜', bangid: '283' }, { id: 'kw__278', name: '古风音乐榜', bangid: '278' }, { id: 'kw__264', name: 'Vlog音乐榜', bangid: '264' }, { id: 'kw__242', name: '电音榜', bangid: '242' }, { id: 'kw__187', name: '流行趋势榜', bangid: '187' }, { id: 'kw__204', name: '现场音乐榜', bangid: '204' }, { id: 'kw__186', name: 'ACG神曲榜', bangid: '186' }, { id: 'kw__185', name: '最强翻唱榜', bangid: '185' }, { id: 'kw__26', name: '经典怀旧榜', bangid: '26' }, { id: 'kw__104', name: '华语榜', bangid: '104' }, { id: 'kw__182', name: '粤语榜', bangid: '182' }, { id: 'kw__22', name: '欧美榜', bangid: '22' }, { id: 'kw__184', name: '韩语榜', bangid: '184' }, { id: 'kw__183', name: '日语榜', bangid: '183' }, { id: 'kw__145', name: '会员畅听榜', bangid: '145' }, { id: 'kw__153', name: '网红新歌榜', bangid: '153' }, { id: 'kw__64', name: '影视金曲榜', bangid: '64' }, { id: 'kw__176', name: 'DJ嗨歌榜', bangid: '176' }, { id: 'kw__106', name: '真声音', bangid: '106' }, { id: 'kw__12', name: 'Billboard榜', bangid: '12' }, { id: 'kw__49', name: 'iTunes音乐榜', bangid: '49' }, { id: 'kw__180', name: 'beatport电音榜', bangid: '180' }, { id: 'kw__13', name: '英国UK榜', bangid: '13' }, { id: 'kw__164', name: '百大DJ榜', bangid: '164' }, { id: 'kw__246', name: 'YouTube音乐排行榜', bangid: '246' }, { id: 'kw__265', name: '韩国Genie榜', bangid: '265' }, { id: 'kw__14', name: '韩国M-net榜', bangid: '14' }, { id: 'kw__8', name: '香港电台榜', bangid: '8' }, { id: 'kw__15', name: '日本公信榜', bangid: '15' }, { id: 'kw__151', name: '腾讯音乐人原创榜', bangid: '151' }] +const sortQualityArray = array => { + const qualityMap = { + flac24bit: 4, + flac: 3, + '320k': 2, + '128k': 1, + } + const rawQualityArray = [] + const newQualityArray = [] + + array.forEach((item, index) => { + const type = qualityMap[item.type] + if (!type) return + rawQualityArray.push({ type, index }) + }) + + rawQualityArray.sort((a, b) => a.type - b.type) + + rawQualityArray.forEach(item => { + newQualityArray.push(array[item.index]) + }) + + return newQualityArray +} + export default { list: [ { @@ -62,9 +88,9 @@ export default { bangid: 183, }, ], - getUrl: (p, l, id) => `http://kbangserver.kuwo.cn/ksong.s?from=pc&fmt=json&pn=${p - 1}&rn=${l}&type=bang&data=content&id=${id}&show_copyright_off=0&pcmp4=1&isbang=1`, + // getUrl: (p, l, id) => `http://kbangserver.kuwo.cn/ksong.s?from=pc&fmt=json&pn=${p - 1}&rn=${l}&type=bang&data=content&id=${id}&show_copyright_off=0&pcmp4=1&isbang=1`, regExps: { - + mInfo: /level:(\w+),bitrate:(\d+),format:(\w+),size:([\w.]+)/, }, limit: 100, _requestBoardsObj: null, @@ -79,57 +105,50 @@ export default { return requestDataObj.promise }, filterData(rawList) { - // console.log(rawList) - // console.log(rawList.length, rawList2.length) - return rawList.map((item, inedx) => { - let formats = item.formats.split('|') + return rawList.map(item => { let types = [] - let _types = {} - if (formats.includes('MP3128')) { - types.push({ type: '128k', size: null }) - _types['128k'] = { - size: null, + const _types = {} + const qualitys = new Set() + + item.n_minfo.split(';').forEach(i => { + const info = i.match(this.regExps.mInfo) + if (!info) return + + const quality = info[2] + const size = info[4].toLocaleUpperCase() + + if (qualitys.has(quality)) return + qualitys.add(quality) + + switch (quality) { + case '4000': + types.push({ type: 'flac24bit', size }) + _types.flac24bit = { size } + break + case '2000': + types.push({ type: 'flac', size }) + _types.flac = { size } + break + case '320': + types.push({ type: '320k', size }) + _types['320k'] = { size } + break + case '128': + types.push({ type: '128k', size }) + _types['128k'] = { size } + break } - } - // if (formats.includes('MP3192')) { - // types.push({ type: '192k', size: null }) - // _types['192k'] = { - // size: null, - // } - // } - if (formats.includes('MP3H')) { - types.push({ type: '320k', size: null }) - _types['320k'] = { - size: null, - } - } - // if (formats.includes('AL')) { - // types.push({ type: 'ape', size: null }) - // _types.ape = { - // size: null, - // } - // } - if (formats.includes('ALFLAC')) { - types.push({ type: 'flac', size: null }) - _types.flac = { - size: null, - } - } - if (formats.includes('HIRFLAC')) { - types.push({ type: 'flac24bit', size: null }) - _types.flac24bit = { - size: null, - } - } - // types.reverse() + }) + types = sortQualityArray(types) + return { singer: formatSinger(decodeName(item.artist)), name: decodeName(item.name), albumName: decodeName(item.album), - albumId: item.albumid, + albumId: item.albumId, songmid: item.id, source: 'kw', - interval: formatPlayTime(parseInt(item.song_duration)), + interval: formatPlayTime(parseInt(item.duration)), img: item.pic, lrc: null, otherSource: null, @@ -180,12 +199,20 @@ export default { getList(id, page, retryNum = 0) { if (++retryNum > 3) return Promise.reject(new Error('try max num')) - return this.getData(this.getUrl(page, this.limit, id)).then(({ statusCode, body }) => { - // console.log(body) - if (statusCode !== 200 || !body.musiclist) return this.getList(id, page, retryNum) - // console.log(data1.musiclist, data2.data) - let total = parseInt(body.num) - let list = this.filterData(body.musiclist) + + const requestBody = { uid: '', devId: '', sFrom: 'kuwo_sdk', user_type: 'AP', carSource: 'kwplayercar_ar_6.0.1.0_apk_keluze.apk', id, pn: page - 1, rn: this.limit } + const requestUrl = `https://wbd.kuwo.cn/api/bd/bang/bang_info?${wbdCrypto.buildParam(requestBody)}` + const request = httpFetch(requestUrl, { cache: 'default' }).promise + + 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) + + const total = parseInt(data.total) + const list = this.filterData(data.musiclist) + return { total, list, diff --git a/src/utils/musicSdk/kw/util.js b/src/utils/musicSdk/kw/util.js index 91df160..eb7c20a 100644 --- a/src/utils/musicSdk/kw/util.js +++ b/src/utils/musicSdk/kw/util.js @@ -1,5 +1,7 @@ // import BackgroundTimer from 'react-native-background-timer' // import { httpGet, httpFetch } from '../../request' +import { toMD5 } from '../utils' +import { aesEncryptSync, aesDecryptSync, AES_MODE } from '@/utils/nativeModules/crypto' export { default as decodeLyric } from './decodeLyric' // const kw_token = { @@ -177,3 +179,45 @@ export const lrcTools = { return lrcs }, } + + +// const createAesEncrypt = (buffer, mode, key, iv) => { +// const cipher = createCipheriv(mode, key, iv) +// return Buffer.concat([cipher.update(buffer), cipher.final()]) +// } + +// const createAesDecrypt = (buffer, mode, key, iv) => { +// const cipher = createDecipheriv(mode, key, iv) +// return Buffer.concat([cipher.update(buffer), cipher.final()]) +// } + +export const wbdCrypto = { + aesMode: 'aes-128-ecb', + // aesKey: Buffer.from([112, 87, 39, 61, 199, 250, 41, 191, 57, 68, 45, 114, 221, 94, 140, 228], 'binary'), + aesKey: 'cFcnPcf6Kb85RC1y3V6M5A==', + aesIv: '', + appId: 'y67sprxhhpws', + decodeData(base64Result) { + // const data = Buffer.from(decodeURIComponent(base64Result), 'base64') + // return JSON.parse(createAesDecrypt(data, this.aesMode, this.aesKey, this.aesIv).toString()) + const data = decodeURIComponent(base64Result) + return JSON.parse(aesDecryptSync(data, this.aesKey, this.aesIv, AES_MODE.ECB_128_NoPadding)) + }, + createSign(data, time) { + const str = `${this.appId}${data}${time}` + return toMD5(str).toUpperCase() + }, + buildParam(jsonData) { + // const data = Buffer.from(JSON.stringify(jsonData)) + // const time = Date.now() + + // const encodeData = createAesEncrypt(data, this.aesMode, this.aesKey, this.aesIv).toString('base64') + const data = Buffer.from(JSON.stringify(jsonData)).toString('base64') + const time = Date.now() + + const encodeData = aesEncryptSync(data, this.aesKey, this.aesIv, AES_MODE.ECB_128_NoPadding) + const sign = this.createSign(encodeData, time) + + return `data=${encodeURIComponent(encodeData)}&time=${time}&appId=${this.appId}&sign=${sign}` + }, +} diff --git a/src/utils/musicSdk/mg/songList.js b/src/utils/musicSdk/mg/songList.js index 8f11bad..f4d1ef8 100644 --- a/src/utils/musicSdk/mg/songList.js +++ b/src/utils/musicSdk/mg/songList.js @@ -310,7 +310,7 @@ export default { search(text, page, limit = 20) { const timeStr = Date.now().toString() const signResult = createSignature(timeStr, text) - return createHttpFetch(`https://jadeite.migu.cn/music_search/v3/search/searchAll?isCorrect=1&isCopyright=1&searchSwitch=%7B%22song%22%3A0%2C%22album%22%3A0%2C%22singer%22%3A0%2C%22tagSong%22%3A0%2C%22mvSong%22%3A0%2C%22bestShow%22%3A0%2C%22songlist%22%3A1%2C%22lyricSong%22%3A0%7D&pageSize=${limit}&text=${encodeURIComponent(text)}&pageNo=${page}&sort=0`, { + return createHttpFetch(`https://jadeite.migu.cn/music_search/v3/search/searchAll?isCorrect=1&isCopyright=1&searchSwitch=%7B%22song%22%3A0%2C%22album%22%3A0%2C%22singer%22%3A0%2C%22tagSong%22%3A0%2C%22mvSong%22%3A0%2C%22bestShow%22%3A0%2C%22songlist%22%3A1%2C%22lyricSong%22%3A0%7D&pageSize=${limit}&text=${encodeURIComponent(text)}&pageNo=${page}&sort=0&sid=USS`, { headers: { uiVersion: 'A_music_3.6.1', deviceId: signResult.deviceId,