From 1dfb7a59ca4929712e71d607d85f26b701775e9a Mon Sep 17 00:00:00 2001 From: snowy-yang <102860110+snowy-yang@users.noreply.github.com> Date: Sat, 29 Aug 2026 00:23:50 +0800 Subject: [PATCH] =?UTF-8?q?refactor(sdk):=20musicSdk=20=E5=85=A8=E9=87=8F?= =?UTF-8?q?=E8=BF=81=E7=A7=BB=E8=87=B3=20TypeScript?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 7 + musicSdk/api-source-info.js | 40 ----- musicSdk/api-source-info.ts | 30 ++-- musicSdk/{api-source.js => api-source.ts} | 36 ++--- musicSdk/bd/{hotSearch.js => hotSearch.ts} | 5 +- musicSdk/bd/{index.js => index.ts} | 16 +- .../bd/{leaderboard.js => leaderboard.ts} | 6 +- musicSdk/bd/{musicInfo.js => musicInfo.ts} | 2 +- .../bd/{musicSearch.js => musicSearch.ts} | 10 +- musicSdk/bd/{songList.js => songList.ts} | 29 ++-- musicSdk/{index.js => index.ts} | 118 +++++++------- musicSdk/kg/{album.js => album.ts} | 4 +- musicSdk/kg/{comment.js => comment.ts} | 11 +- musicSdk/kg/{hotSearch.js => hotSearch.ts} | 13 +- musicSdk/kg/{index.js => index.ts} | 18 +-- .../kg/{leaderboard.js => leaderboard.ts} | 19 +-- musicSdk/kg/{lyric.js => lyric.ts} | 18 +-- musicSdk/kg/{musicInfo.js => musicInfo.ts} | 25 +-- .../kg/{musicSearch.js => musicSearch.ts} | 13 +- musicSdk/kg/{pic.js => pic.ts} | 4 +- musicSdk/kg/{singer.js => singer.ts} | 4 +- musicSdk/kg/{songList.js => songList.ts} | 68 ++++---- musicSdk/kg/{tipSearch.js => tipSearch.ts} | 4 +- musicSdk/kg/{util.js => util.ts} | 9 +- musicSdk/kw/{album.js => album.ts} | 17 +- musicSdk/kw/{comment.js => comment.ts} | 9 +- musicSdk/kw/{hotSearch.js => hotSearch.ts} | 5 +- musicSdk/kw/{index.js => index.ts} | 33 ++-- .../kw/{leaderboard.js => leaderboard.ts} | 33 ++-- musicSdk/kw/{lyric.js => lyric.ts} | 20 +-- .../kw/{musicSearch.js => musicSearch.ts} | 19 +-- musicSdk/kw/{pic.js => pic.ts} | 5 +- musicSdk/kw/{songList.js => songList.ts} | 58 +++---- musicSdk/kw/{tipSearch.js => tipSearch.ts} | 21 +-- musicSdk/kw/{util.js => util.ts} | 44 +++--- musicSdk/{message.js => message.ts} | 0 musicSdk/mg/{comment.js => comment.ts} | 13 +- musicSdk/mg/{hotSearch.js => hotSearch.ts} | 5 +- musicSdk/mg/{index.js => index.ts} | 20 +-- .../mg/{leaderboard.js => leaderboard.ts} | 21 ++- musicSdk/mg/{lyric.js => lyric.ts} | 18 +-- musicSdk/mg/{musicInfo.js => musicInfo.ts} | 29 ++-- .../mg/{musicSearch.js => musicSearch.ts} | 15 +- musicSdk/mg/{pic.js => pic.ts} | 6 +- musicSdk/mg/{songId.js => songId.ts} | 7 +- musicSdk/mg/{songList.js => songList.ts} | 23 +-- musicSdk/mg/{tipSearch.js => tipSearch.ts} | 4 +- musicSdk/mg/utils/{index.js => index.ts} | 5 +- musicSdk/mg/utils/{mrc.js => mrc.ts} | 28 ++-- musicSdk/{options.js => options.ts} | 4 +- musicSdk/request.js | 4 - musicSdk/request.ts | 8 + musicSdk/tx/{comment.js => comment.ts} | 14 +- musicSdk/tx/{hotSearch.js => hotSearch.ts} | 5 +- musicSdk/tx/{index.js => index.ts} | 18 +-- .../tx/{leaderboard.js => leaderboard.ts} | 37 ++--- musicSdk/tx/{lyric.js => lyric.ts} | 32 ++-- musicSdk/tx/{musicInfo.js => musicInfo.ts} | 11 +- .../tx/{musicSearch.js => musicSearch.ts} | 13 +- musicSdk/tx/{singer.js => singer.ts} | 13 +- musicSdk/tx/{songList.js => songList.ts} | 25 +-- musicSdk/tx/{tipSearch.js => tipSearch.ts} | 5 +- musicSdk/tx/utils/{crypto.js => crypto.ts} | 0 musicSdk/tx/utils/{index.js => index.ts} | 5 +- musicSdk/types.ts | 146 ++++++++++++++++++ musicSdk/{utils.js => utils.ts} | 36 +++-- musicSdk/wy/{comment.js => comment.ts} | 21 ++- musicSdk/wy/{hotSearch.js => hotSearch.ts} | 5 +- musicSdk/wy/{index.js => index.ts} | 18 +-- .../wy/{leaderboard.js => leaderboard.ts} | 19 +-- musicSdk/wy/{lyric.js => lyric.ts} | 29 ++-- .../wy/{musicDetail.js => musicDetail.ts} | 14 +- musicSdk/wy/{musicInfo.js => musicInfo.ts} | 8 +- .../wy/{musicSearch.js => musicSearch.ts} | 10 +- musicSdk/wy/{singer.js => singer.ts} | 24 +-- musicSdk/wy/{songList.js => songList.ts} | 37 ++--- musicSdk/wy/{tipSearch.js => tipSearch.ts} | 11 +- musicSdk/wy/utils/{crypto.js => crypto.ts} | 16 +- musicSdk/wy/utils/{index.js => index.ts} | 7 +- musicSdk/xm.js | 55 ------- musicSdk/xm.ts | 30 ++++ src/apis/wy.js | 2 +- tsconfig.json | 7 +- 83 files changed, 924 insertions(+), 732 deletions(-) delete mode 100644 musicSdk/api-source-info.js rename musicSdk/{api-source.js => api-source.ts} (53%) rename musicSdk/bd/{hotSearch.js => hotSearch.ts} (84%) rename musicSdk/bd/{index.js => index.ts} (71%) rename musicSdk/bd/{leaderboard.js => leaderboard.ts} (97%) rename musicSdk/bd/{musicInfo.js => musicInfo.ts} (94%) rename musicSdk/bd/{musicSearch.js => musicSearch.ts} (92%) rename musicSdk/bd/{songList.js => songList.ts} (89%) rename musicSdk/{index.js => index.ts} (54%) rename musicSdk/kg/{album.js => album.ts} (95%) rename musicSdk/kg/{comment.js => comment.ts} (94%) rename musicSdk/kg/{hotSearch.js => hotSearch.ts} (79%) rename musicSdk/kg/{index.js => index.ts} (63%) rename musicSdk/kg/{leaderboard.js => leaderboard.ts} (94%) rename musicSdk/kg/{lyric.js => lyric.ts} (87%) rename musicSdk/kg/{musicInfo.js => musicInfo.ts} (79%) rename musicSdk/kg/{musicSearch.js => musicSearch.ts} (91%) rename musicSdk/kg/{pic.js => pic.ts} (95%) rename musicSdk/kg/{singer.js => singer.ts} (95%) rename musicSdk/kg/{songList.js => songList.ts} (94%) rename musicSdk/kg/{tipSearch.js => tipSearch.ts} (90%) rename musicSdk/kg/{util.js => util.ts} (77%) rename musicSdk/kw/{album.js => album.ts} (88%) rename musicSdk/kw/{comment.js => comment.ts} (91%) rename musicSdk/kw/{hotSearch.js => hotSearch.ts} (85%) rename musicSdk/kw/{index.js => index.ts} (74%) rename musicSdk/kw/{leaderboard.js => leaderboard.ts} (91%) rename musicSdk/kw/{lyric.js => lyric.ts} (94%) rename musicSdk/kw/{musicSearch.js => musicSearch.ts} (88%) rename musicSdk/kw/{pic.js => pic.ts} (70%) rename musicSdk/kw/{songList.js => songList.ts} (90%) rename musicSdk/kw/{tipSearch.js => tipSearch.ts} (64%) rename musicSdk/kw/{util.js => util.ts} (82%) rename musicSdk/{message.js => message.ts} (100%) rename musicSdk/mg/{comment.js => comment.ts} (93%) rename musicSdk/mg/{hotSearch.js => hotSearch.ts} (82%) rename musicSdk/mg/{index.js => index.ts} (50%) rename musicSdk/mg/{leaderboard.js => leaderboard.ts} (93%) rename musicSdk/mg/{lyric.js => lyric.ts} (85%) rename musicSdk/mg/{musicInfo.js => musicInfo.ts} (81%) rename musicSdk/mg/{musicSearch.js => musicSearch.ts} (95%) rename musicSdk/mg/{pic.js => pic.ts} (85%) rename musicSdk/mg/{songId.js => songId.ts} (84%) rename musicSdk/mg/{songList.js => songList.ts} (97%) rename musicSdk/mg/{tipSearch.js => tipSearch.ts} (89%) rename musicSdk/mg/utils/{index.js => index.ts} (77%) rename musicSdk/mg/utils/{mrc.js => mrc.ts} (69%) rename musicSdk/{options.js => options.ts} (57%) delete mode 100644 musicSdk/request.js create mode 100644 musicSdk/request.ts rename musicSdk/tx/{comment.js => comment.ts} (95%) rename musicSdk/tx/{hotSearch.js => hotSearch.ts} (91%) rename musicSdk/tx/{index.js => index.ts} (60%) rename musicSdk/tx/{leaderboard.js => leaderboard.ts} (92%) rename musicSdk/tx/{lyric.js => lyric.ts} (92%) rename musicSdk/tx/{musicInfo.js => musicInfo.ts} (88%) rename musicSdk/tx/{musicSearch.js => musicSearch.ts} (92%) rename musicSdk/tx/{singer.js => singer.ts} (93%) rename musicSdk/tx/{songList.js => songList.ts} (93%) rename musicSdk/tx/{tipSearch.js => tipSearch.ts} (87%) rename musicSdk/tx/utils/{crypto.js => crypto.ts} (100%) rename musicSdk/tx/utils/{index.js => index.ts} (71%) create mode 100644 musicSdk/types.ts rename musicSdk/{utils.js => utils.ts} (50%) rename musicSdk/wy/{comment.js => comment.ts} (92%) rename musicSdk/wy/{hotSearch.js => hotSearch.ts} (79%) rename musicSdk/wy/{index.js => index.ts} (58%) rename musicSdk/wy/{leaderboard.js => leaderboard.ts} (93%) rename musicSdk/wy/{lyric.js => lyric.ts} (92%) rename musicSdk/wy/{musicDetail.js => musicDetail.ts} (90%) rename musicSdk/wy/{musicInfo.js => musicInfo.ts} (80%) rename musicSdk/wy/{musicSearch.js => musicSearch.ts} (92%) rename musicSdk/wy/{singer.js => singer.ts} (84%) rename musicSdk/wy/{songList.js => songList.ts} (90%) rename musicSdk/wy/{tipSearch.js => tipSearch.ts} (73%) rename musicSdk/wy/utils/{crypto.js => crypto.ts} (74%) rename musicSdk/wy/utils/{index.js => index.ts} (83%) delete mode 100644 musicSdk/xm.js create mode 100644 musicSdk/xm.ts diff --git a/.gitignore b/.gitignore index 32d4445..9e09d50 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,10 @@ Thumbs.db dist/ coverage/ .nyc_output/ + +# TypeScript in-place emit (musicSdk source is .ts) +musicSdk/**/*.js +!musicSdk/**/api-test.js +!musicSdk/**/api-temp.js +!musicSdk/**/temp/*.js +!musicSdk/**/vendors/*.js diff --git a/musicSdk/api-source-info.js b/musicSdk/api-source-info.js deleted file mode 100644 index 97a2568..0000000 --- a/musicSdk/api-source-info.js +++ /dev/null @@ -1,40 +0,0 @@ -// Support qualitys: 128k 320k flac wav - -const sources = [ - // { - // id: 'test', - // name: '测试接口', - // disabled: false, - // supportQualitys: { - // kw: ['128k'], - // kg: ['128k'], - // tx: ['128k'], - // wy: ['128k'], - // mg: ['128k'], - // // bd: ['128k'], - // }, - // }, - // { - // id: 'temp', - // name: '临时接口', - // disabled: false, - // supportQualitys: { - // kw: ['128k'], - // }, - // }, - { - id: 'v5', - name: 'lx-music-source-v5 聚合源', - disabled: false, - supportQualitys: { - kw: ['128k', '320k', 'flac'], - kg: ['128k', '320k', 'flac'], - tx: ['128k', '320k', 'flac'], - wy: ['128k', '320k', 'flac'], - mg: ['128k', '320k', 'flac'], - // bd: ['128k', '320k', 'flac'], - }, - }, -] - -export default sources diff --git a/musicSdk/api-source-info.ts b/musicSdk/api-source-info.ts index 65cf20e..ffd6433 100644 --- a/musicSdk/api-source-info.ts +++ b/musicSdk/api-source-info.ts @@ -1,11 +1,14 @@ +// 接口源声明:id 与 api-source.ts 中 allApi 的 `_` 键对应 // Support qualitys: 128k 320k flac wav -const sources: Array<{ +interface ApiSourceInfo { id: string name: string disabled: boolean - supportQualitys: Partial> -}> = [ + supportQualitys: Partial> +} + +const sources: ApiSourceInfo[] = [ // { // id: 'test', // name: '测试接口', @@ -19,14 +22,19 @@ const sources: Array<{ // // bd: ['128k'], // }, // }, - // { - // id: 'temp', - // name: '临时接口', - // disabled: false, - // supportQualitys: { - // kw: ['128k'], - // }, - // }, + { + id: 'v5', + name: 'lx-music-source-v5 聚合源', + disabled: false, + supportQualitys: { + kw: ['128k', '320k', 'flac'], + kg: ['128k', '320k', 'flac'], + tx: ['128k', '320k', 'flac'], + wy: ['128k', '320k', 'flac'], + mg: ['128k', '320k', 'flac'], + // bd: ['128k', '320k', 'flac'], + }, + }, ] export default sources diff --git a/musicSdk/api-source.js b/musicSdk/api-source.ts similarity index 53% rename from musicSdk/api-source.js rename to musicSdk/api-source.ts index c40fca9..bde68e1 100644 --- a/musicSdk/api-source.js +++ b/musicSdk/api-source.ts @@ -1,32 +1,24 @@ -import apiSourceInfo from './api-source-info.js' +// 接口选择层:按 apiSource 配置把请求路由到 v5 聚合源或服务器内置直连接口 +import apiSourceInfo from './api-source-info.ts' import { apiSource, userApi } from '../src/renderer/store.js' import internalApi from '../src/apis/index.js' import { createApi as createLxSourceApi } from '../src/apis/lx-source.js' -// import api_temp_kw from './kw/api-temp.js' -// // import api_test_bd from './bd/api-test.js' -// import api_test_tx from './tx/api-test.js' -// import api_test_kg from './kg/api-test.js' -// import api_test_kw from './kw/api-test.js' -// import api_test_mg from './mg/api-test.js' -// import api_test_wy from './wy/api-test.js' -const allApi = { +interface SourceApi { + getMusicUrl(songInfo: any, type: string): { promise: Promise; cancelHttp(): void } + [key: string]: any +} + +const allApi: Record = { v5_kw: createLxSourceApi('kw'), v5_kg: createLxSourceApi('kg'), v5_tx: createLxSourceApi('tx'), v5_wy: createLxSourceApi('wy'), v5_mg: createLxSourceApi('mg'), - // temp_kw: api_temp_kw, - // // test_bd: api_test_bd, - // test_tx: api_test_tx, - // test_kg: api_test_kg, - // test_kw: api_test_kw, - // test_mg: api_test_mg, - // test_wy: api_test_wy, } -const apiList = {} -const supportQuality = {} +const apiList: Record = {} +const supportQuality: Record = {} for (const api of apiSourceInfo) { supportQuality[api.id] = api.supportQualitys @@ -35,9 +27,9 @@ for (const api of apiSourceInfo) { } } -const getAPI = source => apiList[`${apiSource.value}_api_${source}`] +const getAPI = (source: string): SourceApi | undefined => apiList[`${apiSource.value}_api_${source}`] -const apis = source => { +export const apis = (source: string): SourceApi => { if (/^user_api/.test(apiSource.value)) return userApi.apis[source] // 服务器内置直连接口 if (apiSource.value == 'internal') { @@ -45,9 +37,9 @@ const apis = source => { if (api) return api throw new Error('Api is not found') } - let api = getAPI(source) + const api = getAPI(source) if (api) return api throw new Error('Api is not found') } -export { apis, supportQuality } +export { supportQuality } diff --git a/musicSdk/bd/hotSearch.js b/musicSdk/bd/hotSearch.ts similarity index 84% rename from musicSdk/bd/hotSearch.js rename to musicSdk/bd/hotSearch.ts index 7e44c48..965ae20 100644 --- a/musicSdk/bd/hotSearch.js +++ b/musicSdk/bd/hotSearch.ts @@ -1,7 +1,8 @@ -import { httpFetch } from '../request.js' +import { httpFetch } from '../request.ts' +import type { HttpRequestObject } from '../types.ts' export default { - _requestObj: null, + _requestObj: null as HttpRequestObject | null, async getList(retryNum = 0) { if (this._requestObj) this._requestObj.cancelHttp() if (retryNum > 2) return Promise.reject(new Error('try max num')) diff --git a/musicSdk/bd/index.js b/musicSdk/bd/index.ts similarity index 71% rename from musicSdk/bd/index.js rename to musicSdk/bd/index.ts index f0c499c..1dc8e56 100644 --- a/musicSdk/bd/index.js +++ b/musicSdk/bd/index.ts @@ -1,10 +1,10 @@ -import leaderboard from './leaderboard.js' -import { apis } from '../api-source.js' -import musicInfo from './musicInfo.js' -import songList from './songList.js' -import { httpFetch } from '../request.js' -import musicSearch from './musicSearch.js' -import hotSearch from './hotSearch.js' +import leaderboard from './leaderboard.ts' +import { apis } from '../api-source.ts' +import musicInfo from './musicInfo.ts' +import songList from './songList.ts' +import { httpFetch } from '../request.ts' +import musicSearch from './musicSearch.ts' +import hotSearch from './hotSearch.ts' const bd = { leaderboard, @@ -12,7 +12,7 @@ const bd = { musicSearch, hotSearch, getMusicUrl(songInfo, type) { - return apis('bd').getMusicUrl(songInfo, type) + return apis('bd').getMusicUrl!(songInfo, type) }, getPic(songInfo) { const requestObj = this.getMusicInfo(songInfo) diff --git a/musicSdk/bd/leaderboard.js b/musicSdk/bd/leaderboard.ts similarity index 97% rename from musicSdk/bd/leaderboard.js rename to musicSdk/bd/leaderboard.ts index 8e82276..36de6f4 100644 --- a/musicSdk/bd/leaderboard.js +++ b/musicSdk/bd/leaderboard.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.js' +import { httpFetch } from '../request.ts' // import { formatPlayTime } from '../index.js' @@ -86,8 +86,8 @@ export default { filterData(rawList) { // console.log(rawList) return rawList.map(item => { - const types = [] - const _types = {} + const types: any[] = [] + const _types: Record = {} let size = null types.push({ type: '128k', size }) _types['128k'] = { diff --git a/musicSdk/bd/musicInfo.js b/musicSdk/bd/musicInfo.ts similarity index 94% rename from musicSdk/bd/musicInfo.js rename to musicSdk/bd/musicInfo.ts index 95868c0..8f114b6 100644 --- a/musicSdk/bd/musicInfo.js +++ b/musicSdk/bd/musicInfo.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.js' +import { httpFetch } from '../request.ts' export default { cache: {}, diff --git a/musicSdk/bd/musicSearch.js b/musicSdk/bd/musicSearch.ts similarity index 92% rename from musicSdk/bd/musicSearch.js rename to musicSdk/bd/musicSearch.ts index 30ace38..6d49325 100644 --- a/musicSdk/bd/musicSearch.js +++ b/musicSdk/bd/musicSearch.ts @@ -1,7 +1,7 @@ // import '../../polyfill/array.find.js' -import { httpFetch } from '../request.js' -import { formatPlayTime } from '../index.js' +import { httpFetch } from '../request.ts' +import { formatPlayTime } from '../index.ts' // import { debug } from '../../utils/env.js' // import { formatSinger } from './util.js' @@ -16,13 +16,13 @@ export default { }, handleResult(rawData) { let ids = new Set() - const list = [] + const list: any[] = [] if (!rawData) return list rawData.forEach(item => { if (ids.has(item.song_id)) return ids.add(item.song_id) - const types = [] - const _types = {} + const types: any[] = [] + const _types: Record = {} let size = null let itemTypes = item.all_rate.split(',') if (itemTypes.includes('128')) { diff --git a/musicSdk/bd/songList.js b/musicSdk/bd/songList.ts similarity index 89% rename from musicSdk/bd/songList.js rename to musicSdk/bd/songList.ts index 3f815d2..4ca8869 100644 --- a/musicSdk/bd/songList.js +++ b/musicSdk/bd/songList.ts @@ -1,12 +1,13 @@ -import { httpFetch } from '../request.js' -import { formatPlayTime } from '../index.js' -import { toMD5 } from '../utils.js' +import { httpFetch } from '../request.ts' +import { formatPlayTime } from '../index.ts' +import { toMD5 } from '../utils.ts' import CryptoJS from 'crypto-js' +import type { HttpRequestObject } from '../types.ts' export default { - _requestObj_tags: null, - _requestObj_list: null, - _requestObj_listRecommend: null, + _requestObj_tags: null as HttpRequestObject | null, + _requestObj_list: null as HttpRequestObject | null, + _requestObj_listRecommend: null as HttpRequestObject | null, limit_list: 30, limit_song: 10000, successCode: 22000, @@ -29,7 +30,7 @@ export default { let privateKey = toMD5('baidu_taihe_music_secret_key' + timestamp).substr(8, 16) let key = CryptoJS.enc.Utf8.parse(privateKey) let iv = CryptoJS.enc.Utf8.parse(privateKey) - let arrData = [] + let arrData: string[] = [] let strData = '' for (let key in jsonData) arrData.push(key) arrData.sort() @@ -40,7 +41,7 @@ export default { } let JsonFormatter = { stringify(cipherParams) { - let jsonObj = { + let jsonObj: Record = { ct: cipherParams.ciphertext.toString(CryptoJS.enc.Base64), } if (cipherParams.iv) { @@ -116,7 +117,7 @@ export default { if (this._requestObj_tags) this._requestObj_tags.cancelHttp() if (tryNum > 2) return Promise.reject(new Error('try max num')) this._requestObj_tags = httpFetch(this.getTagsUrl()) - return this._requestObj_tags.promise.then(({ body }) => { + return this._requestObj_tags!.promise.then(({ body }) => { if (body.error_code !== this.successCode) return this.getTags(++tryNum) return { hotTag: this.filterInfoHotTag(body.result.hot), @@ -150,7 +151,7 @@ export default { if (this._requestObj_list) this._requestObj_list.cancelHttp() if (tryNum > 2) return Promise.reject(new Error('try max num')) this._requestObj_list = httpFetch(this.getListUrl(sortId, tagId, page)) - return this._requestObj_list.promise.then(({ body }) => { + return this._requestObj_list!.promise.then(({ body }) => { if (body.error_code !== this.successCode) return this.getList(sortId, tagId, page, ++tryNum) return { list: this.filterList(body.diyInfo), @@ -168,8 +169,8 @@ export default { * @param {*} num */ formatPlayCount(num) { - if (num > 100000000) return parseInt(num / 10000000) / 10 + '亿' - if (num > 10000) return parseInt(num / 1000) / 10 + '万' + if (num > 100000000) return parseInt((num / 10000000) as any) / 10 + '亿' + if (num > 10000) return parseInt((num / 1000) as any) / 10 + '万' return num }, filterList(rawData) { @@ -215,8 +216,8 @@ export default { filterData(rawList) { // console.log(rawList) return rawList.map(item => { - const types = [] - const _types = {} + const types: any[] = [] + const _types: Record = {} let size = null let itemTypes = item.all_rate.split(',') if (itemTypes.includes('128')) { diff --git a/musicSdk/index.js b/musicSdk/index.ts similarity index 54% rename from musicSdk/index.js rename to musicSdk/index.ts index bd0d80d..02384fd 100644 --- a/musicSdk/index.js +++ b/musicSdk/index.ts @@ -1,11 +1,12 @@ -import kw from './kw/index.js' -import kg from './kg/index.js' -import tx from './tx/index.js' -import wy from './wy/index.js' -import mg from './mg/index.js' -import bd from './bd/index.js' -import xm from './xm.js' -import { supportQuality } from './api-source.js' +import kw from './kw/index.ts' +import kg from './kg/index.ts' +import tx from './tx/index.ts' +import wy from './wy/index.ts' +import mg from './mg/index.ts' +import bd from './bd/index.ts' +import xm from './xm.ts' +import { supportQuality } from './api-source.ts' +import type { PlatformModule, SearchResult, SongInfo } from './types.ts' import { sizeFormate, formatPlayTime, @@ -15,11 +16,11 @@ import { decodeName, } from '../src/index.js' -// 通用工具函数(SDK 内 `import { ... } from '../index.js'` 的解析目标) +// 通用工具函数(SDK 内 `import { ... } from '../index.ts'` 的解析目标) export { sizeFormate, formatPlayTime, dateFormat, dateFormat2, formatPlayCount, decodeName } const SINGERS_SEPARATOR = /、|&|;|;|\/|,|,|\||\]|\[|!|!/g -const SUPPORTED_SOURCES = [ +const SUPPORTED_SOURCES: Array<{ id: string; name: string; module: PlatformModule }> = [ { id: 'kw', name: '酷我音乐', module: kw }, { id: 'kg', name: '酷狗音乐', module: kg }, { id: 'tx', name: 'QQ音乐', module: tx }, @@ -33,48 +34,57 @@ const SOURCE_MODULES = Object.fromEntries(SUPPORTED_SOURCES.map((s) => [s.id, s. export const sources = SUPPORTED_SOURCES.map(({ id, name }) => ({ id, name })) -export const init = () => +export const init = (): Promise => Promise.all(SUPPORTED_SOURCES.map((s) => s.module.init?.()).filter(Boolean)) export { supportQuality } -const trimStr = (str) => (typeof str === 'string' ? str.trim() : str) +const trimStr = (str: unknown): string => (typeof str === 'string' ? str.trim() : str as string) -const filterStr = (str) => +const filterStr = (str: unknown): string => typeof str === 'string' ? str.replace(/\s|'|\.|,|,|&|"|、|\(|\)|(|)|`|~|-|<|>|\||\/|\]|\[|!|!/g, '') : String(str ?? '') -const getIntervalSeconds = (interval) => { +const getIntervalSeconds = (interval: unknown): number => { if (!interval) return 0 const parts = String(interval).split(':') let seconds = 0 let unit = 1 while (parts.length) { - seconds += parseInt(parts.pop()) * unit + seconds += parseInt(parts.pop()!) * unit unit *= 60 } return seconds } -const sortSingle = (singer) => { +const sortSingle = (singer: unknown): string => { if (!singer) return '' - return SINGERS_SEPARATOR.test(singer) - ? singer.split(SINGERS_SEPARATOR).sort((a, b) => a.localeCompare(b)).join('、') - : singer + const s = String(singer) + return SINGERS_SEPARATOR.test(s) + ? s.split(SINGERS_SEPARATOR).sort((a, b) => a.localeCompare(b)).join('、') + : s +} + +interface MatchCandidate extends SongInfo { + fSinger?: string + fMusicName?: string + fAlbumName?: string + fInterval?: number } /** * 多平台聚合搜索 - * @param {object} params - * @param {string} params.name - * @param {string} [params.singer] - * @param {string} [params.source] 指定平台时,聚合结果会跳过该平台 - * @param {number} [params.limit=25] + * @param params.name 歌名 + * @param params.singer 歌手 + * @param params.excludeSource 指定平台时,聚合结果会跳过该平台 + * @param params.limit 单平台结果条数 */ -export const searchMusic = async ({ name, singer, source: excludeSource, limit = 25 }) => { +export const searchMusic = async ( + { name, singer, source: excludeSource, limit = 25 }: { name: string; singer?: string; source?: string; limit?: number }, +): Promise> => { const musicName = trimStr(name) - const tasks = [] + const tasks: Array> = [] for (const source of SUPPORTED_SOURCES) { if ( source.id === 'xm' || @@ -91,9 +101,9 @@ export const searchMusic = async ({ name, singer, source: excludeSource, limit = return (await Promise.all(tasks)).filter(Boolean) } -const pickMatching = (items, predicate) => { - const matched = [] - const rest = [] +const pickMatching = (items: T[], predicate: (item: T) => boolean): { matched: T[]; rest: T[] } => { + const matched: T[] = [] + const rest: T[] = [] for (const item of items) { if (predicate(item)) matched.push(item) else rest.push(item) @@ -104,7 +114,9 @@ const pickMatching = (items, predicate) => { /** * 跨平台精确匹配歌曲(按歌手、歌名、专辑、时长综合排序) */ -export const findMusic = async ({ name, singer, albumName, interval, source: s }) => { +export const findMusic = async ( + { name, singer, albumName, interval, source: s }: { name: string; singer?: string; albumName?: string; interval?: string; source?: string }, +): Promise => { const lists = await searchMusic({ name, singer, source: s, limit: 25 }) const fMusicName = filterStr(name).toLowerCase() @@ -112,32 +124,34 @@ export const findMusic = async ({ name, singer, albumName, interval, source: s } const fAlbumName = filterStr(albumName).toLowerCase() const fInterval = getIntervalSeconds(interval) - const isEqualsInterval = (intv) => + const isEqualsInterval = (intv: number) => Math.abs((fInterval || intv) - (intv || fInterval)) < 5 - const isIncludesName = (n) => fMusicName.includes(n) || n.includes(fMusicName) - const isIncludesSinger = (sng) => + 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) => (fAlbumName ? fAlbumName === alb : true) + const isEqualsAlbum = (alb: string) => (fAlbumName ? fAlbumName === alb : true) - let candidates = [] + let candidates: MatchCandidate[] = [] for (const source of lists) { + if (!source) continue for (const item of source.list) { - item.name = trimStr(item.name) - item.singer = trimStr(item.singer) - item.fSinger = filterStr(sortSingle(item.singer).toLowerCase()) - item.fMusicName = filterStr(String(item.name ?? '').toLowerCase()) - item.fAlbumName = filterStr(String(item.albumName ?? '').toLowerCase()) - item.fInterval = getIntervalSeconds(item.interval) - if (!isEqualsInterval(item.fInterval)) { - item.name = null + const cand = item as MatchCandidate + cand.name = trimStr(cand.name) + cand.singer = trimStr(cand.singer) + cand.fSinger = filterStr(sortSingle(cand.singer).toLowerCase()) + cand.fMusicName = filterStr(String(cand.name ?? '').toLowerCase()) + cand.fAlbumName = filterStr(String(cand.albumName ?? '').toLowerCase()) + cand.fInterval = getIntervalSeconds(cand.interval) + if (!isEqualsInterval(cand.fInterval)) { + cand.name = null continue } - candidates.push(item) + candidates.push(cand) } } - const result = [] - const take = (predicate) => { + const result: MatchCandidate[] = [] + const take = (predicate: (item: MatchCandidate) => boolean) => { const { matched, rest } = pickMatching(candidates, predicate) result.push(...matched) candidates = rest @@ -153,13 +167,7 @@ export const findMusic = async ({ name, singer, albumName, interval, source: s } take((item) => item.fSinger === fSinger) take((item) => item.fAlbumName === fAlbumName) - for (const item of candidates) { - delete item.fSinger - delete item.fMusicName - delete item.fAlbumName - delete item.fInterval - } - for (const item of result) { + for (const item of [...candidates, ...result]) { delete item.fSinger delete item.fMusicName delete item.fAlbumName @@ -170,7 +178,7 @@ export const findMusic = async ({ name, singer, albumName, interval, source: s } return result } -export default { +const musicSdk = { sources, ...SOURCE_MODULES, init, @@ -178,3 +186,5 @@ export default { searchMusic, findMusic, } + +export default musicSdk diff --git a/musicSdk/kg/album.js b/musicSdk/kg/album.ts similarity index 95% rename from musicSdk/kg/album.js rename to musicSdk/kg/album.ts index d19d5ab..b64bd62 100644 --- a/musicSdk/kg/album.js +++ b/musicSdk/kg/album.ts @@ -1,5 +1,5 @@ -import { getMusicInfosByList } from './musicInfo.js' -import { createHttpFetch } from './util.js' +import { getMusicInfosByList } from './musicInfo.ts' +import { createHttpFetch } from './util.ts' export default { /** diff --git a/musicSdk/kg/comment.js b/musicSdk/kg/comment.ts similarity index 94% rename from musicSdk/kg/comment.js rename to musicSdk/kg/comment.ts index 3726a0a..d80f712 100644 --- a/musicSdk/kg/comment.js +++ b/musicSdk/kg/comment.ts @@ -1,11 +1,12 @@ -import { httpFetch } from '../request.js' -import { decodeName, dateFormat2 } from '../index.js' -import { signatureParams } from './util.js' +import { httpFetch } from '../request.ts' +import { decodeName, dateFormat2 } from '../index.ts' +import { signatureParams } from './util.ts' // import { getMusicInfoRaw } from './musicInfo.js' +import type { HttpRequestObject } from '../types.ts' export default { - _requestObj: null, - _requestObj2: null, + _requestObj: null as HttpRequestObject | null, + _requestObj2: null as HttpRequestObject | null, async getComment({ hash }, page = 1, limit = 20) { if (this._requestObj) this._requestObj.cancelHttp() diff --git a/musicSdk/kg/hotSearch.js b/musicSdk/kg/hotSearch.ts similarity index 79% rename from musicSdk/kg/hotSearch.js rename to musicSdk/kg/hotSearch.ts index ff982f8..46f54b3 100644 --- a/musicSdk/kg/hotSearch.js +++ b/musicSdk/kg/hotSearch.ts @@ -1,8 +1,9 @@ -import { httpFetch } from '../request.js' -import { decodeName } from '../index.js' +import { httpFetch } from '../request.ts' +import { decodeName } from '../index.ts' +import type { HttpRequestObject } from '../types.ts' export default { - _requestObj: null, + _requestObj: null as HttpRequestObject | null, async getList(retryNum = 0) { if (this._requestObj) this._requestObj.cancelHttp() if (retryNum > 2) return Promise.reject(new Error('try max num')) @@ -12,10 +13,10 @@ export default { headers: { dfid: '1ssiv93oVqMp27cirf2CvoF1', mid: '156798703528610303473757548878786007104', - clienttime: 1584257267, + clienttime: '1584257267', 'x-router': 'msearch.kugou.com', 'user-agent': 'Android9-AndroidPhone-10020-130-0-searchrecommendprotocol-wifi', - 'kg-rc': 1, + 'kg-rc': '1', }, }) const { body, statusCode } = await _requestObj.promise @@ -24,7 +25,7 @@ export default { return { source: 'kg', list: this.filterList(body.data.list) } }, filterList(rawList) { - const list = [] + const list: string[] = [] rawList.forEach(item => { item.keywords.map(k => list.push(decodeName(k.keyword))) }) diff --git a/musicSdk/kg/index.js b/musicSdk/kg/index.ts similarity index 63% rename from musicSdk/kg/index.js rename to musicSdk/kg/index.ts index 60646e8..fbe4131 100644 --- a/musicSdk/kg/index.js +++ b/musicSdk/kg/index.ts @@ -1,11 +1,11 @@ -import leaderboard from './leaderboard.js' -import { apis } from '../api-source.js' -import songList from './songList.js' -import musicSearch from './musicSearch.js' -import pic from './pic.js' -import lyric from './lyric.js' -import hotSearch from './hotSearch.js' -import comment from './comment.js' +import leaderboard from './leaderboard.ts' +import { apis } from '../api-source.ts' +import songList from './songList.ts' +import musicSearch from './musicSearch.ts' +import pic from './pic.ts' +import lyric from './lyric.ts' +import hotSearch from './hotSearch.ts' +import comment from './comment.ts' // import tipSearch from './tipSearch.js' const kg = { @@ -16,7 +16,7 @@ const kg = { hotSearch, comment, getMusicUrl(songInfo, type) { - return apis('kg').getMusicUrl(songInfo, type) + return apis('kg').getMusicUrl!(songInfo, type) }, getLyric(songInfo) { return lyric.getLyric(songInfo) diff --git a/musicSdk/kg/leaderboard.js b/musicSdk/kg/leaderboard.ts similarity index 94% rename from musicSdk/kg/leaderboard.js rename to musicSdk/kg/leaderboard.ts index 2521010..84162b6 100644 --- a/musicSdk/kg/leaderboard.js +++ b/musicSdk/kg/leaderboard.ts @@ -1,6 +1,7 @@ -import { httpFetch } from '../request.js' -import { decodeName, formatPlayTime, sizeFormate } from '../index.js' -import { formatSingerName } from '../utils.js' +import { httpFetch } from '../request.ts' +import { decodeName, formatPlayTime, sizeFormate } from '../index.ts' +import { formatSingerName } from '../utils.ts' +import type { HttpRequestObject, SongType, QualityInfo } from '../types.ts' let boardList = [{ id: 'kg__8888', name: 'TOP500', bangid: '8888' }, { id: 'kg__6666', name: '飙升榜', bangid: '6666' }, { id: 'kg__59703', name: '蜂鸟流行音乐榜', bangid: '59703' }, { id: 'kg__52144', name: '抖音热歌榜', bangid: '52144' }, { id: 'kg__52767', name: '快手热歌榜', bangid: '52767' }, { id: 'kg__24971', name: 'DJ热歌榜', bangid: '24971' }, { id: 'kg__23784', name: '网络红歌榜', bangid: '23784' }, { id: 'kg__44412', name: '说唱先锋榜', bangid: '44412' }, { id: 'kg__31308', name: '内地榜', bangid: '31308' }, { id: 'kg__33160', name: '电音榜', bangid: '33160' }, { id: 'kg__31313', name: '香港地区榜', bangid: '31313' }, { id: 'kg__51341', name: '民谣榜', bangid: '51341' }, { id: 'kg__54848', name: '台湾地区榜', bangid: '54848' }, { id: 'kg__31310', name: '欧美榜', bangid: '31310' }, { id: 'kg__33162', name: 'ACG新歌榜', bangid: '33162' }, { id: 'kg__31311', name: '韩国榜', bangid: '31311' }, { id: 'kg__31312', name: '日本榜', bangid: '31312' }, { id: 'kg__49225', name: '80后热歌榜', bangid: '49225' }, { id: 'kg__49223', name: '90后热歌榜', bangid: '49223' }, { id: 'kg__49224', name: '00后热歌榜', bangid: '49224' }, { id: 'kg__33165', name: '粤语金曲榜', bangid: '33165' }, { id: 'kg__33166', name: '欧美金曲榜', bangid: '33166' }, { id: 'kg__33163', name: '影视金曲榜', bangid: '33163' }, { id: 'kg__51340', name: '伤感榜', bangid: '51340' }, { id: 'kg__35811', name: '会员专享榜', bangid: '35811' }, { id: 'kg__37361', name: '雷达榜', bangid: '37361' }, { id: 'kg__21101', name: '分享榜', bangid: '21101' }, { id: 'kg__46910', name: '综艺新歌榜', bangid: '46910' }, { id: 'kg__30972', name: '酷狗音乐人原创榜', bangid: '30972' }, { id: 'kg__60170', name: '闽南语榜', bangid: '60170' }, { id: 'kg__65234', name: '儿歌榜', bangid: '65234' }, { id: 'kg__4681', name: '美国BillBoard榜', bangid: '4681' }, { id: 'kg__25028', name: 'Beatport电子舞曲榜', bangid: '25028' }, { id: 'kg__4680', name: '英国单曲榜', bangid: '4680' }, { id: 'kg__38623', name: '韩国Melon音乐榜', bangid: '38623' }, { id: 'kg__42807', name: 'joox本地热歌榜', bangid: '42807' }, { id: 'kg__36107', name: '小语种热歌榜', bangid: '36107' }, { id: 'kg__4673', name: '日本公信榜', bangid: '4673' }, { id: 'kg__46868', name: '日本SPACE SHOWER榜', bangid: '46868' }, { id: 'kg__42808', name: 'KKBOX风云榜', bangid: '42808' }, { id: 'kg__60171', name: '越南语榜', bangid: '60171' }, { id: 'kg__60172', name: '泰语榜', bangid: '60172' }, { id: 'kg__59895', name: 'R&B榜', bangid: '59895' }, { id: 'kg__59896', name: '摇滚榜', bangid: '59896' }, { id: 'kg__59897', name: '爵士榜', bangid: '59897' }, { id: 'kg__59898', name: '乡村音乐榜', bangid: '59898' }, { id: 'kg__59900', name: '纯音乐榜', bangid: '59900' }, { id: 'kg__59899', name: '古典榜', bangid: '59899' }, { id: 'kg__22603', name: '5sing音乐榜', bangid: '22603' }, { id: 'kg__21335', name: '繁星音乐榜', bangid: '21335' }, { id: 'kg__33161', name: '古风新歌榜', bangid: '33161' }] @@ -72,18 +73,18 @@ export default { limit: /pagesize: '(\d+)',/, listData: /global\.features = (\[.+\]);/, }, - _requestBoardsObj: null, + _requestBoardsObj: null as HttpRequestObject | null, getBoardsData() { if (this._requestBoardsObj) this._requestBoardsObj.cancelHttp() this._requestBoardsObj = httpFetch('http://mobilecdnbj.kugou.com/api/v5/rank/list?version=9108&plat=0&showtype=2&parentid=0&apiver=6&area_code=1&withsong=1') - return this._requestBoardsObj.promise + return this._requestBoardsObj!.promise }, getData(url) { const requestDataObj = httpFetch(url) return requestDataObj.promise }, getSinger(singers) { - let arr = [] + let arr: string[] = [] singers.forEach(singer => { arr.push(singer.author_name) }) @@ -92,8 +93,8 @@ export default { filterData(rawList) { // console.log(rawList) return rawList.map(item => { - const types = [] - const _types = {} + const types: Array = [] + const _types: Record = {} if (item.filesize !== 0) { let size = sizeFormate(item.filesize) types.push({ type: '128k', size, hash: item.hash }) @@ -147,7 +148,7 @@ export default { filterBoardsData(rawList) { // console.log(rawList) - let list = [] + let list: Array<{ id: string; name: string; bangid: string }> = [] for (const board of rawList) { if (board.isvol != 1) continue list.push({ diff --git a/musicSdk/kg/lyric.js b/musicSdk/kg/lyric.ts similarity index 87% rename from musicSdk/kg/lyric.js rename to musicSdk/kg/lyric.ts index f7a3421..1069d61 100644 --- a/musicSdk/kg/lyric.js +++ b/musicSdk/kg/lyric.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.js' +import { httpFetch } from '../request.ts' import { decodeKrc } from '../../src/common/lyricUtils/kg.js' export default { @@ -11,7 +11,7 @@ export default { intv += (intvArr.pop()) * unit unit *= 60 } - return parseInt(intv) + 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`, { @@ -38,12 +38,12 @@ export default { 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: { - 'KG-RC': 1, + 'KG-RC': '1', 'KG-THash': 'expand_search_manager.cpp:852736169:451', 'User-Agent': 'KuGou2012-9020-ExpandSearchManager', }, }) - requestObj.promise = requestObj.promise.then(({ body, statusCode }) => { + requestObj.promise = (requestObj.promise as any).then(({ body, statusCode }) => { if (statusCode !== 200) { if (tryNum > 5) return Promise.reject(new Error('歌词获取失败')) let tryRequestObj = this.searchLyric(name, hash, time, ++tryNum) @@ -61,15 +61,15 @@ export default { 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-RC': '1', 'KG-THash': 'expand_search_manager.cpp:852736169:451', 'User-Agent': 'KuGou2012-9020-ExpandSearchManager', }, }) - requestObj.promise = requestObj.promise.then(({ body, statusCode }) => { + requestObj.promise = (requestObj.promise as any).then(({ body, statusCode }) => { if (statusCode !== 200) { if (tryNum > 5) return Promise.reject(new Error('歌词获取失败')) - let tryRequestObj = this.getLyric(id, accessKey, fmt, ++tryNum) + let tryRequestObj = (this.getLyric as any)(id, accessKey, fmt, ++tryNum) requestObj.cancelHttp = tryRequestObj.cancelHttp.bind(tryRequestObj) return tryRequestObj.promise } @@ -97,12 +97,12 @@ 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, result.fmt) + let requestObj2 = this.getLyricDownload((result as any).id, (result as any).accessKey, (result as any).fmt) requestObj.cancelHttp = requestObj2.cancelHttp.bind(requestObj2) return requestObj2.promise - }) + }) as any return requestObj }, } diff --git a/musicSdk/kg/musicInfo.js b/musicSdk/kg/musicInfo.ts similarity index 79% rename from musicSdk/kg/musicInfo.js rename to musicSdk/kg/musicInfo.ts index 0d1829f..649b6a7 100644 --- a/musicSdk/kg/musicInfo.js +++ b/musicSdk/kg/musicInfo.ts @@ -1,7 +1,8 @@ -import { decodeName, formatPlayTime, sizeFormate } from '../index.js' -import { createHttpFetch } from './util.js' +import { decodeName, formatPlayTime, sizeFormate } from '../index.ts' +import { createHttpFetch } from './util.ts' +import type { SongInfo, SongType, QualityInfo } from '../types.ts' -const createGetMusicInfosTask = (hashs) => { +const createGetMusicInfosTask = (hashs: Array<{ hash: string }>): Array> => { let data = { area_code: '1', show_privilege: 1, @@ -16,7 +17,7 @@ const createGetMusicInfosTask = (hashs) => { fields: 'album_info,author_name,audio_info,ori_audio_name,base,songname,classification', } let list = hashs - let tasks = [] + let tasks: Array<{ data: Array<{ hash: string }> }> = [] while (list.length) { tasks.push(Object.assign({ data: list.slice(0, 100) }, data)) if (list.length < 100) break @@ -37,16 +38,16 @@ const createGetMusicInfosTask = (hashs) => { }).then(data => data.map(s => s[0]))) } -export const filterMusicInfoList = (rawList) => { +export const filterMusicInfoList = (rawList: any[]): SongInfo[] => { // console.log(rawList) let ids = new Set() - let list = [] + let list: SongInfo[] = [] rawList.forEach(item => { if (!item) return if (ids.has(item.audio_info.audio_id)) return ids.add(item.audio_info.audio_id) - const types = [] - const _types = {} + const types: Array = [] + const _types: Record = {} if (item.audio_info.filesize !== '0') { let size = sizeFormate(parseInt(item.audio_info.filesize)) types.push({ type: '128k', size, hash: item.audio_info.hash }) @@ -99,18 +100,18 @@ export const filterMusicInfoList = (rawList) => { return list } -export const getMusicInfos = async(hashs) => { +export const getMusicInfos = async(hashs: Array<{ hash: string }>): Promise => { return filterMusicInfoList(await Promise.all(createGetMusicInfosTask(hashs)).then(data => data.flat())) } -export const getMusicInfoRaw = async(hash) => { +export const getMusicInfoRaw = async(hash: string): Promise => { return Promise.all(createGetMusicInfosTask([{ hash }])).then(data => data.flat()[0]) } -export const getMusicInfo = async(hash) => { +export const getMusicInfo = async(hash: string): Promise => { return getMusicInfos([{ hash }]).then(data => data[0]) } -export const getMusicInfosByList = (list) => { +export const getMusicInfosByList = (list: any[]): Promise => { return getMusicInfos(list.map(item => ({ hash: item.hash }))) } diff --git a/musicSdk/kg/musicSearch.js b/musicSdk/kg/musicSearch.ts similarity index 91% rename from musicSdk/kg/musicSearch.js rename to musicSdk/kg/musicSearch.ts index 0e01960..2cfa291 100644 --- a/musicSdk/kg/musicSearch.js +++ b/musicSdk/kg/musicSearch.ts @@ -1,6 +1,7 @@ -import { httpFetch } from '../request.js' -import { decodeName, formatPlayTime, sizeFormate } from '../index.js' -import { formatSingerName } from '../utils.js' +import { httpFetch } from '../request.ts' +import { decodeName, formatPlayTime, sizeFormate } from '../index.ts' +import { formatSingerName } from '../utils.ts' +import type { SongType, QualityInfo } from '../types.ts' export default { @@ -13,8 +14,8 @@ export default { return searchRequest.promise.then(({ body }) => body) }, filterData(rawData) { - const types = [] - const _types = {} + const types: Array = [] + const _types: Record = {} if (rawData.FileSize !== 0) { let size = sizeFormate(rawData.FileSize) types.push({ type: '128k', size, hash: rawData.FileHash }) @@ -67,7 +68,7 @@ export default { }, handleResult(rawData) { let ids = new Set() - const list = [] + const list: any[] = [] rawData.forEach(item => { const key = item.Audioid + item.FileHash if (ids.has(key)) return diff --git a/musicSdk/kg/pic.js b/musicSdk/kg/pic.ts similarity index 95% rename from musicSdk/kg/pic.js rename to musicSdk/kg/pic.ts index 8102559..1b48eeb 100644 --- a/musicSdk/kg/pic.js +++ b/musicSdk/kg/pic.ts @@ -1,4 +1,4 @@ -import { httpFetch } from '../request.js' +import { httpFetch } from '../request.ts' export default { getPic(songInfo) { @@ -7,7 +7,7 @@ export default { { method: 'POST', headers: { - 'KG-RC': 1, + 'KG-RC': '1', 'KG-THash': 'expand_search_manager.cpp:852736169:451', 'User-Agent': 'KuGou2012-9020-ExpandSearchManager', }, diff --git a/musicSdk/kg/singer.js b/musicSdk/kg/singer.ts similarity index 95% rename from musicSdk/kg/singer.js rename to musicSdk/kg/singer.ts index 404ac19..fa4a859 100644 --- a/musicSdk/kg/singer.js +++ b/musicSdk/kg/singer.ts @@ -1,5 +1,5 @@ -import { getMusicInfosByList } from './musicInfo.js' -import { createHttpFetch } from './util.js' +import { getMusicInfosByList } from './musicInfo.ts' +import { createHttpFetch } from './util.ts' export default { /** diff --git a/musicSdk/kg/songList.js b/musicSdk/kg/songList.ts similarity index 94% rename from musicSdk/kg/songList.js rename to musicSdk/kg/songList.ts index 0dc91e5..b0d1390 100644 --- a/musicSdk/kg/songList.js +++ b/musicSdk/kg/songList.ts @@ -1,7 +1,8 @@ -import { httpFetch } from '../request.js' -import { decodeName, formatPlayTime, sizeFormate, dateFormat, formatPlayCount } from '../index.js' -import { toMD5 } from '../utils.js' -import { signatureParams } from './util.js' +import { httpFetch } from '../request.ts' +import { decodeName, formatPlayTime, sizeFormate, dateFormat, formatPlayCount } from '../index.ts' +import { toMD5 } from '../utils.ts' +import { signatureParams } from './util.ts' +import type { HttpRequestObject, SongInfo, SongType, QualityInfo } from '../types.ts' // 原版使用 @renderer/utils/musicSdk/kg/vendors/infSign.min(浏览器签名库), // 其 H5 签名算法为:{srcappid, clientver, clienttime, mid, uuid, dfid} + 业务参数, @@ -27,10 +28,10 @@ const handleSignature = (id, page, limit) => { } export default { - _requestObj_tags: null, - _requestObj_listInfo: null, - _requestObj_list: null, - _requestObj_listRecommend: null, + _requestObj_tags: null as HttpRequestObject | null, + _requestObj_listInfo: null as HttpRequestObject | null, + _requestObj_list: null as HttpRequestObject | null, + _requestObj_listRecommend: null as HttpRequestObject | null, listDetailLimit: 10000, currentTagInfo: { id: undefined, @@ -119,7 +120,7 @@ export default { if (index < 0) return null return decodeName(afterStr.substring(0, index)) }, - async getListDetailBySpecialId(id, page, tryNum = 0) { + async getListDetailBySpecialId(id, page?, tryNum = 0) { if (tryNum > 2) throw new Error('try max num') const { body } = await httpFetch(this.getSongListDetailUrl(id)).promise @@ -172,7 +173,7 @@ export default { // }, // } }, - getInfoUrl(tagId) { + getInfoUrl(tagId?) { return tagId ? `http://www2.kugou.kugou.com/yueku/v9/special/getSpecial?is_smarty=1&cdn=cdn&t=5&c=${tagId}` : 'http://www2.kugou.kugou.com/yueku/v9/special/getSpecial?is_smarty=1&' @@ -186,7 +187,7 @@ export default { }, filterInfoHotTag(rawData) { - const result = [] + const result: any[] = [] if (rawData.status !== 1) return result for (const key of Object.keys(rawData.data)) { let tag = rawData.data[key] @@ -199,7 +200,7 @@ export default { return result }, filterTagInfo(rawData) { - const result = [] + const result: any[] = [] for (const name of Object.keys(rawData)) { result.push({ name, @@ -221,7 +222,7 @@ export default { this._requestObj_list = httpFetch( this.getSongListUrl(sortId, tagId, page), ) - return this._requestObj_list.promise.then(({ body }) => { + return this._requestObj_list!.promise.then(({ body }) => { if (!body || body.status !== 1) return this.getSongList(sortId, tagId, page, ++tryNum) return this.filterList(body.special_db) }) @@ -249,7 +250,7 @@ export default { }, }, ) - return this._requestObj_listRecommend.promise.then(({ body }) => { + return this._requestObj_listRecommend!.promise.then(({ body }) => { if (body.status !== 1) return this.getSongListRecommend(++tryNum) return this.filterList(body.data.special_list) }) @@ -308,7 +309,7 @@ export default { fields: 'album_info,author_name,audio_info,ori_audio_name,base,songname', } let list = hashs - let tasks = [] + let tasks: any[] = [] while (list.length) { tasks.push(Object.assign({ data: list.slice(0, 100) }, data)) if (list.length < 100) break @@ -452,7 +453,7 @@ export default { async getUserListDetailByLink({ info }, link) { let listInfo = info['0'] let total = listInfo.count - let tasks = [] + let tasks: any[] = [] let page = 0 while (total) { const limit = total > 90 ? 90 : total @@ -484,7 +485,7 @@ export default { } }, createGetListDetail2Task(id, total) { - let tasks = [] + let tasks: any[] = [] let page = 0 while (total) { const limit = total > 300 ? 300 : total @@ -653,32 +654,33 @@ 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 (location) { + if (loc) { // console.log(location) - if (location.includes('global_collection_id')) return this.getUserListDetail2(location.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1')) - if (location.includes('gcid_')) { + 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] if (gcid) { const global_collection_id = await this.decodeGcid(gcid) if (global_collection_id) return this.getUserListDetail2(global_collection_id) } } - if (location.includes('chain=')) return this.getUserListDetail3(location.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'), page) - if (location.includes('.html')) { - if (location.includes('zlist.html')) { - let link = location.replace(/^(.*)zlist\.html/, 'https://m3ws.kugou.com/zlist/list') + if (loc.includes('chain=')) return this.getUserListDetail3(loc.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'), page) + if (loc.includes('.html')) { + if (loc.includes('zlist.html')) { + let link = loc.replace(/^(.*)zlist\.html/, 'https://m3ws.kugou.com/zlist/list') if (link.includes('pagesize')) { link = link.replace('pagesize=30', 'pagesize=' + this.listDetailLimit).replace('page=1', 'page=' + page) } else { link += `&pagesize=${this.listDetailLimit}&page=${page}` } return this.getUserListDetail(link, page, ++retryNum) - } else return this.getUserListDetail3(location.replace(/.+\/(\w+).html(?:\?.*|&.*$|#.*$|$)/, '$1'), page) + } else return this.getUserListDetail3(loc.replace(/.+\/(\w+).html(?:\?.*|&.*$|#.*$|$)/, '$1'), page) } // console.log('location', location) - return this.getUserListDetail(location, page, ++retryNum) + return this.getUserListDetail(loc, page, ++retryNum) } if (typeof body == 'string') { let global_collection_id = body.match(/"global_collection_id":"(\w+)"/)?.[1] @@ -713,8 +715,8 @@ export default { filterData(rawList) { // console.log(rawList) return rawList.map(item => { - const types = [] - const _types = {} + const types: Array<{ type: string; size: string; hash?: string }> = [] + const _types: Record = {} if (item.filesize !== 0) { let size = sizeFormate(item.filesize) types.push({ type: '128k', size, hash: item.hash }) @@ -831,13 +833,13 @@ export default { filterData2(rawList) { // console.log(rawList) let ids = new Set() - let list = [] + let list: SongInfo[] = [] rawList.forEach(item => { if (!item) return if (ids.has(item.audio_info.audio_id)) return ids.add(item.audio_info.audio_id) - const types = [] - const _types = {} + const types: Array = [] + const _types: Record = {} if (item.audio_info.filesize !== '0') { let size = sizeFormate(parseInt(item.audio_info.filesize)) types.push({ type: '128k', size, hash: item.audio_info.hash }) @@ -895,7 +897,7 @@ export default { if (this._requestObj_listInfo) this._requestObj_listInfo.cancelHttp() if (tryNum > 2) return Promise.reject(new Error('try max num')) this._requestObj_listInfo = httpFetch(this.getInfoUrl(tagId)) - return this._requestObj_listInfo.promise.then(({ body }) => { + return this._requestObj_listInfo!.promise.then(({ body }) => { if (body.status !== 1) return this.getListInfo(tagId, ++tryNum) return { limit: body.data.params.pagesize, @@ -933,7 +935,7 @@ export default { if (this._requestObj_tags) this._requestObj_tags.cancelHttp() if (tryNum > 2) return Promise.reject(new Error('try max num')) this._requestObj_tags = httpFetch(this.getInfoUrl()) - return this._requestObj_tags.promise.then(({ body }) => { + return this._requestObj_tags!.promise.then(({ body }) => { if (body.status !== 1) return this.getTags(++tryNum) return { hotTag: this.filterInfoHotTag(body.data.hotTag), diff --git a/musicSdk/kg/tipSearch.js b/musicSdk/kg/tipSearch.ts similarity index 90% rename from musicSdk/kg/tipSearch.js rename to musicSdk/kg/tipSearch.ts index 038dcb1..2933fcb 100644 --- a/musicSdk/kg/tipSearch.js +++ b/musicSdk/kg/tipSearch.ts @@ -1,7 +1,7 @@ -import { createHttpFetch } from './util.js' +import { createHttpFetch } from './util.ts' export default { - requestObj: null, + requestObj: null as any, cancelTipSearch() { if (this.requestObj && this.requestObj.cancelHttp) this.requestObj.cancelHttp() }, diff --git a/musicSdk/kg/util.js b/musicSdk/kg/util.ts similarity index 77% rename from musicSdk/kg/util.js rename to musicSdk/kg/util.ts index 3e83b43..54360ed 100644 --- a/musicSdk/kg/util.js +++ b/musicSdk/kg/util.ts @@ -1,5 +1,6 @@ -import { toMD5 } from '../utils.js' -import { httpFetch } from '../request.js' +import { toMD5 } from '../utils.ts' +import { httpFetch } from '../request.ts' +import type { HttpOptions } from '../types.ts' // s.content[0].lyricContent.forEach(([str]) => { // console.log(str) @@ -10,7 +11,7 @@ import { httpFetch } from '../request.js' * @param {*} params * @param {*} apiver */ -export const signatureParams = (params, platform = 'android', body = '') => { +export const signatureParams = (params: string, platform = 'android', body = ''): string => { let keyparam = 'OIlwieks28dk2k092lksi2UIkp' if (platform === 'web') keyparam = 'NVPh5oo715z5DIWAeQlhMDsWXXQV4hwt' let param_list = params.split('&') @@ -25,7 +26,7 @@ export const signatureParams = (params, platform = 'android', body = '') => { * @param {*} options * @param {*} retryNum */ -export const createHttpFetch = async(url, options, retryNum = 0) => { +export const createHttpFetch = async(url: string, options?: HttpOptions, retryNum = 0): Promise => { if (retryNum > 2) throw new Error('try max num') let result try { diff --git a/musicSdk/kw/album.js b/musicSdk/kw/album.ts similarity index 88% rename from musicSdk/kw/album.js rename to musicSdk/kw/album.ts index cf0d361..3966d70 100644 --- a/musicSdk/kw/album.js +++ b/musicSdk/kw/album.ts @@ -1,6 +1,7 @@ -import { httpFetch } from '../request.js' -import { decodeName } from '../index.js' -import { formatSinger, objStr2JSON } from './util.js' +import { httpFetch } from '../request.ts' +import { decodeName } from '../index.ts' +import { formatSinger, objStr2JSON } from './util.ts' +import type { Quality } from '../types.ts' // let requestObj_list export default { @@ -11,8 +12,8 @@ export default { // console.log(rawList.length, rawList2.length) return rawList.map((item, inedx) => { let formats = item.formats.split('|') - let types = [] - let _types = {} + let types: Array<{ type: Quality; size: string | null }> = [] + let _types: Partial> = {} if (formats.includes('MP3128')) { types.push({ type: '128k', size: null }) _types['128k'] = { @@ -71,9 +72,9 @@ export default { * 格式化播放数量 * @param {*} num */ - formatPlayCount(num) { - if (num > 100000000) return parseInt(num / 10000000) / 10 + '亿' - if (num > 10000) return parseInt(num / 1000) / 10 + '万' + formatPlayCount(num: any) { + if (num > 100000000) return parseInt((num / 10000000) as any) / 10 + '亿' + if (num > 10000) return parseInt((num / 1000) as any) / 10 + '万' return num }, getAlbumListDetail(id, page, retryNum = 0) { diff --git a/musicSdk/kw/comment.js b/musicSdk/kw/comment.ts similarity index 91% rename from musicSdk/kw/comment.js rename to musicSdk/kw/comment.ts index f3fbb3e..5e29cb2 100644 --- a/musicSdk/kw/comment.js +++ b/musicSdk/kw/comment.ts @@ -1,9 +1,10 @@ -import { httpFetch } from '../request.js' -import { dateFormat2 } from '../index.js' +import { httpFetch } from '../request.ts' +import { dateFormat2 } from '../index.ts' +import type { HttpRequestObject } from '../types.ts' export default { - _requestObj: null, - _requestObj2: null, + _requestObj: null as HttpRequestObject | null, + _requestObj2: null as HttpRequestObject | null, async getComment({ songmid }, page = 1, limit = 20) { if (this._requestObj) this._requestObj.cancelHttp() diff --git a/musicSdk/kw/hotSearch.js b/musicSdk/kw/hotSearch.ts similarity index 85% rename from musicSdk/kw/hotSearch.js rename to musicSdk/kw/hotSearch.ts index 27730f9..a7de583 100644 --- a/musicSdk/kw/hotSearch.js +++ b/musicSdk/kw/hotSearch.ts @@ -1,7 +1,8 @@ -import { httpFetch } from '../request.js' +import { httpFetch } from '../request.ts' +import type { HttpRequestObject } from '../types.ts' export default { - _requestObj: null, + _requestObj: null as HttpRequestObject | null, async getList(retryNum = 0) { if (this._requestObj) this._requestObj.cancelHttp() if (retryNum > 2) return Promise.reject(new Error('try max num')) diff --git a/musicSdk/kw/index.js b/musicSdk/kw/index.ts similarity index 74% rename from musicSdk/kw/index.js rename to musicSdk/kw/index.ts index 0aa1e1b..2c95328 100644 --- a/musicSdk/kw/index.js +++ b/musicSdk/kw/index.ts @@ -1,19 +1,20 @@ -import { httpFetch } from '../request.js' -import tipSearch from './tipSearch.js' -import musicSearch from './musicSearch.js' -import { formatSinger } from './util.js' -import leaderboard from './leaderboard.js' -import lyric from './lyric.js' -import pic from './pic.js' -import { apis } from '../api-source.js' -import songList from './songList.js' -import hotSearch from './hotSearch.js' -import comment from './comment.js' +import { httpFetch } from '../request.ts' +import tipSearch from './tipSearch.ts' +import musicSearch from './musicSearch.ts' +import { formatSinger } from './util.ts' +import leaderboard from './leaderboard.ts' +import lyric from './lyric.ts' +import pic from './pic.ts' +import { apis } from '../api-source.ts' +import songList from './songList.ts' +import hotSearch from './hotSearch.ts' +import comment from './comment.ts' +import type { HttpRequestObject } from '../types.ts' const kw = { - _musicInfoRequestObj: null, + _musicInfoRequestObj: null as HttpRequestObject | null, _musicInfoPromiseCancelFn: null, - _musicPicRequestObj: null, + _musicPicRequestObj: null as HttpRequestObject | null, _musicPicPromiseCancelFn: null, // context: null, @@ -60,19 +61,19 @@ const kw = { }, getMusicUrl(songInfo, type) { - return apis('kw').getMusicUrl(songInfo, type) + return apis('kw').getMusicUrl!(songInfo, type) }, getMusicInfo(songInfo) { if (this._musicInfoRequestObj) this._musicInfoRequestObj.cancelHttp() this._musicInfoRequestObj = httpFetch(`http://www.kuwo.cn/api/www/music/musicInfo?mid=${songInfo.songmid}`) - return this._musicInfoRequestObj.promise.then(({ body }) => { + return this._musicInfoRequestObj!.promise.then(({ body }) => { return body.code === 200 ? body.data : Promise.reject(new Error(body.msg)) }) }, getMusicUrls(musicInfo, cb) { - let tasks = [] + let tasks: Array> = [] let songId = musicInfo.songmid musicInfo.types.forEach(type => { tasks.push(kw.getMusicUrl(songId, type.type).promise) diff --git a/musicSdk/kw/leaderboard.js b/musicSdk/kw/leaderboard.ts similarity index 91% rename from musicSdk/kw/leaderboard.js rename to musicSdk/kw/leaderboard.ts index 8a82d73..698c8c8 100644 --- a/musicSdk/kw/leaderboard.js +++ b/musicSdk/kw/leaderboard.ts @@ -1,19 +1,20 @@ -import { httpFetch } from '../request.js' -import { formatPlayTime, decodeName } from '../index.js' -import { formatSinger, wbdCrypto } from './util.js' +import { httpFetch } from '../request.ts' +import { formatPlayTime, decodeName } from '../index.ts' +import { formatSinger, wbdCrypto } from './util.ts' +import type { HttpRequestObject, Quality, QualityInfo, SongType } from '../types.ts' 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 sortQualityArray = (array: SongType[]): SongType[] => { const qualityMap = { flac24bit: 4, flac: 3, '320k': 2, '128k': 1, } - const rawQualityArray = [] - const newQualityArray = [] + const rawQualityArray: Array<{ type: number; index: number }> = [] + const newQualityArray: SongType[] = [] array.forEach((item, index) => { const type = qualityMap[item.type] @@ -30,6 +31,12 @@ const sortQualityArray = array => { return newQualityArray } +interface BoardItem { + id: string + name: string + bangid: number | string +} + export default { list: [ { @@ -87,27 +94,27 @@ export default { name: '日语榜', bangid: 183, }, - ], + ] as BoardItem[], // 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, + _requestBoardsObj: null as HttpRequestObject | null, getBoardsData() { if (this._requestBoardsObj) this._requestBoardsObj.cancelHttp() this._requestBoardsObj = httpFetch('http://qukudata.kuwo.cn/q.k?op=query&cont=tree&node=2&pn=0&rn=1000&fmt=json&level=2') - return this._requestBoardsObj.promise + return this._requestBoardsObj!.promise }, - getData(url) { + getData(url: string) { const requestDataObj = httpFetch(url) return requestDataObj.promise }, filterData(rawList) { return rawList.map(item => { - let types = [] - const _types = {} + let types: SongType[] = [] + const _types: Partial> = {} const qualitys = new Set() item.n_minfo.split(';').forEach(i => { @@ -161,7 +168,7 @@ export default { filterBoardsData(rawList) { // console.log(rawList) - let list = [] + let list: any[] = [] for (const board of rawList) { if (board.source != '1') continue list.push({ diff --git a/musicSdk/kw/lyric.js b/musicSdk/kw/lyric.ts similarity index 94% rename from musicSdk/kw/lyric.js rename to musicSdk/kw/lyric.ts index 11f2e3d..b94ffc2 100644 --- a/musicSdk/kw/lyric.js +++ b/musicSdk/kw/lyric.ts @@ -1,6 +1,6 @@ -import { httpFetch } from '../request.js' -import { decodeLyric, lrcTools } from './util.js' -import { decodeName } from '../index.js' +import { httpFetch } from '../request.ts' +import { decodeLyric, lrcTools } from './util.ts' +import { decodeName } from '../index.ts' /* export default { @@ -69,7 +69,7 @@ export default { const buf_key = Buffer.from('yeelion') const buf_key_len = buf_key.length -const buildParams = (id, isGetLyricx) => { +const buildParams = (id: string, isGetLyricx: boolean): string => { let params = `user=12345,web,web,web&requester=localhost&req=1&rid=MUSIC_${id}` if (isGetLyricx) params += '&lrcx=1' const buf_str = Buffer.from(params) @@ -148,8 +148,8 @@ export default { }, */ sortLrcArr(arr) { const lrcSet = new Set() - let lrc = [] - let lrcT = [] + let lrc: any[] = [] + let lrcT: any[] = [] let isLyricx = false for (const item of arr) { @@ -186,10 +186,10 @@ export default { transformLrc(tags, lrclist) { return `${tags.join('\n')}\n${lrclist ? lrclist.map(l => `[${l.time}]${l.text}\n`).join('') : '暂无歌词'}` }, - parseLrc(lrc) { + parseLrc(lrc: string) { const lines = lrc.split(/\r\n|\r|\n/) - let tags = [] - let lrcArr = [] + let tags: string[] = [] + let lrcArr: Array<{ time: string; text: string }> = [] for (let i = 0; i < lines.length; i++) { const line = lines[i].trim() let result = timeExp.exec(line) @@ -238,7 +238,7 @@ export default { 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 => { + return decodeLyric({ lrcBase64: raw!.toString('base64'), isGetLyricx }).then(base64Data => { // let lrcInfo // try { // lrcInfo = this.parseLrc(Buffer.from(base64Data, 'base64').toString()) diff --git a/musicSdk/kw/musicSearch.js b/musicSdk/kw/musicSearch.ts similarity index 88% rename from musicSdk/kw/musicSearch.js rename to musicSdk/kw/musicSearch.ts index ee9131d..139b130 100644 --- a/musicSdk/kw/musicSearch.js +++ b/musicSdk/kw/musicSearch.ts @@ -1,9 +1,10 @@ // import '../../polyfill/array.find.js' -import { httpFetch } from '../request.js' -import { formatPlayTime, decodeName } from '../index.js' +import { httpFetch } from '../request.ts' +import { formatPlayTime, decodeName } from '../index.ts' // import { debug } from '../../utils/env.js' -import { formatSinger } from './util.js' +import { formatSinger } from './util.ts' +import type { Quality, QualityInfo, SongInfo, SongType } from '../types.ts' export default { regExps: { @@ -14,7 +15,7 @@ export default { page: 0, allPage: 1, // cancelFn: null, - musicSearch(str, page, limit) { + 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 }, @@ -24,8 +25,8 @@ export default { // getLrc(songId) { // return httpGet(`http://mobile.kuwo.cn/mpage/html5/songinfoandlrc?mid=${songId}&flag=0`) // }, - handleResult(rawData) { - const result = [] + handleResult(rawData: any) { + const result: SongInfo[] = [] if (!rawData) return result // console.log(rawData) for (let i = 0; i < rawData.length; i++) { @@ -38,8 +39,8 @@ export default { return null } - const types = [] - const _types = {} + const types: SongType[] = [] + const _types: Partial> = {} let infoArr = info.N_MINFO.split(';') for (let info of infoArr) { @@ -99,7 +100,7 @@ export default { // console.log(result) return result }, - search(str, page = 1, limit, retryNum = 0) { + search(str: string, page = 1, limit?: number, retryNum = 0) { if (retryNum > 2) return Promise.reject(new Error('try max num')) if (limit == null) limit = this.limit // http://newlyric.kuwo.cn/newlyric.lrc?62355680 diff --git a/musicSdk/kw/pic.js b/musicSdk/kw/pic.ts similarity index 70% rename from musicSdk/kw/pic.js rename to musicSdk/kw/pic.ts index 72a334c..770a27e 100644 --- a/musicSdk/kw/pic.js +++ b/musicSdk/kw/pic.ts @@ -1,7 +1,8 @@ -import { httpFetch } from '../request.js' +import { httpFetch } from '../request.ts' +import type { SongInfo } from '../types.ts' export default { - getPic({ songmid }) { + getPic({ songmid }: SongInfo) { const requestObj = httpFetch(`http://artistpicserver.kuwo.cn/pic.web?corp=kuwo&type=rid_pic&pictype=500&size=500&rid=${songmid}`) requestObj.promise = requestObj.promise.then(({ body }) => /^http/.test(body) ? body : null) return requestObj.promise diff --git a/musicSdk/kw/songList.js b/musicSdk/kw/songList.ts similarity index 90% rename from musicSdk/kw/songList.js rename to musicSdk/kw/songList.ts index b54400a..6163321 100644 --- a/musicSdk/kw/songList.js +++ b/musicSdk/kw/songList.ts @@ -1,12 +1,13 @@ -import { httpFetch } from '../request.js' -import { formatPlayTime, decodeName } from '../index.js' -import { formatSinger, objStr2JSON } from './util.js' -import album from './album.js' +import { httpFetch } from '../request.ts' +import { formatPlayTime, decodeName } from '../index.ts' +import { formatSinger, objStr2JSON } from './util.ts' +import album from './album.ts' +import type { HttpRequestObject, Quality, QualityInfo, SongType } from '../types.ts' export default { - _requestObj_tags: null, - _requestObj_hotTags: null, - _requestObj_list: null, + _requestObj_tags: null as HttpRequestObject | null, + _requestObj_hotTags: null as HttpRequestObject | null, + _requestObj_list: null as HttpRequestObject | null, limit_list: 36, limit_song: 1000, successCode: 200, @@ -28,7 +29,7 @@ export default { }, tagsUrl: 'http://wapi.kuwo.cn/api/pc/classify/playlist/getTagList?cmd=rcm_keyword_playlist&user=0&prod=kwplayer_pc_9.0.5.0&vipver=9.0.5.0&source=kwplayer_pc_9.0.5.0&loginUid=0&loginSid=0&appUid=76039576', hotTagUrl: 'http://wapi.kuwo.cn/api/pc/classify/playlist/getRcmTagList?loginUid=0&loginSid=0&appUid=76039576', - getListUrl({ sortId, id, type, page }) { + getListUrl({ sortId, id, type, page }: { sortId: string; id: string | null; type: string; page: number }) { if (!id) return `http://wapi.kuwo.cn/api/pc/classify/playlist/getRcmPlayList?loginUid=0&loginSid=0&appUid=76039576&&pn=${page}&rn=${this.limit_list}&order=${sortId}` switch (type) { case '10000': return `http://wapi.kuwo.cn/api/pc/classify/playlist/getTagPlayList?loginUid=0&loginSid=0&appUid=76039576&pn=${page}&id=${id}&rn=${this.limit_list}` @@ -36,7 +37,7 @@ export default { } // http://wapi.kuwo.cn/api/pc/classify/playlist/getTagPlayList?loginUid=0&loginSid=0&appUid=76039576&id=173&pn=1&rn=100 }, - getListDetailUrl(id, page) { + getListDetailUrl(id: string, page: number) { // http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=2858093057&pn=0&rn=100&encode=utf8&keyset=pl2012&identity=kuwo&pcmp4=1&vipver=MUSIC_9.0.5.0_W1&newver=1 return `http://nplserver.kuwo.cn/pl.svc?op=getlistinfo&pid=${id}&pn=${page - 1}&rn=${this.limit_song}&encode=utf8&keyset=pl2012&identity=kuwo&pcmp4=1&vipver=MUSIC_9.0.5.0_W1&newver=1` // http://mobileinterfaces.kuwo.cn/er.s?type=get_pc_qz_data&f=web&id=140&prod=pc @@ -48,7 +49,7 @@ export default { if (this._requestObj_tags) this._requestObj_tags.cancelHttp() if (tryNum > 2) return Promise.reject(new Error('try max num')) this._requestObj_tags = httpFetch(this.tagsUrl) - return this._requestObj_tags.promise.then(({ body }) => { + return this._requestObj_tags!.promise.then(({ body }) => { if (body.code !== this.successCode) return this.getTag(++tryNum) return this.filterTagInfo(body.data) }) @@ -58,7 +59,7 @@ export default { if (this._requestObj_hotTags) this._requestObj_hotTags.cancelHttp() if (tryNum > 2) return Promise.reject(new Error('try max num')) this._requestObj_hotTags = httpFetch(this.hotTagUrl) - return this._requestObj_hotTags.promise.then(({ body }) => { + return this._requestObj_hotTags!.promise.then(({ body }) => { if (body.code !== this.successCode) return this.getHotTag(++tryNum) return this.filterInfoHotTag(body.data[0].data) }) @@ -84,20 +85,21 @@ export default { }, // 获取列表数据 - getList(sortId, tagId, page, tryNum = 0) { + getList(sortId: string, tagId: string | undefined, page: number, tryNum = 0) { if (this._requestObj_list) this._requestObj_list.cancelHttp() if (tryNum > 2) return Promise.reject(new Error('try max num')) - let id - let type + let id: string | null + let type: string if (tagId) { let arr = tagId.split('-') id = arr[0] - type = arr[1] + type = arr[1] ?? '' } else { id = null + type = '' } - this._requestObj_list = httpFetch(this.getListUrl({ sortId, id, type, page })) - return this._requestObj_list.promise.then(({ body }) => { + this._requestObj_list = httpFetch(this.getListUrl({ sortId, id, type, page } as any) as any) + return this._requestObj_list!.promise.then(({ body }) => { if (!id || type == '10000') { if (body.code !== this.successCode) return this.getList(sortId, tagId, page, ++tryNum) return { @@ -125,9 +127,9 @@ export default { * 格式化播放数量 * @param {*} num */ - formatPlayCount(num) { - if (num > 100000000) return parseInt(num / 10000000) / 10 + '亿' - if (num > 10000) return parseInt(num / 1000) / 10 + '万' + formatPlayCount(num: any) { + if (num > 100000000) return parseInt((num / 10000000) as any) / 10 + '亿' + if (num > 10000) return parseInt((num / 1000) as any) / 10 + '万' return num }, filterList(rawData) { @@ -146,7 +148,7 @@ export default { }, filterList2(rawData) { // console.log(rawData) - const list = [] + const list: any[] = [] rawData.forEach(item => { if (!item.label) return list.push(...item.list.map(item => ({ @@ -225,8 +227,8 @@ export default { filterBDListDetail(rawList) { return rawList.map(item => { - let types = [] - let _types = {} + let types: SongType[] = [] + let _types: Partial> = {} for (let info of item.audios) { info.size = info.size?.toLocaleUpperCase() switch (info.bitrate) { @@ -288,7 +290,7 @@ export default { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36', plat: 'h5', }, - }).promise.catch(() => ({ code: 0 })) + }).promise.catch(() => ({ code: 0 } as any)) if (infoData.code != 200) return null @@ -306,7 +308,7 @@ export default { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36', plat: 'h5', }, - }).promise.catch(() => ({ code: 0 })) + }).promise.catch(() => ({ code: 0 } as any)) if (infoData.code != 200) return null @@ -346,7 +348,7 @@ export default { const source = /source=(\d+)/.exec(id)?.[1] if (!listId) return Promise.reject(new Error('failed')) - const task = [this.getListDetailMusicListByBDList(listId, source, page)] + const task: Array> = [this.getListDetailMusicListByBDList(listId, source, page)] switch (source) { case '4': task.push(this.getListDetailMusicListByBDListInfo(listId, source)) @@ -392,8 +394,8 @@ export default { // console.log(rawData) return rawData.map(item => { let infoArr = item.N_MINFO.split(';') - let types = [] - let _types = {} + let types: SongType[] = [] + let _types: Partial> = {} for (let info of infoArr) { info = info.match(this.regExps.mInfo) if (info) { diff --git a/musicSdk/kw/tipSearch.js b/musicSdk/kw/tipSearch.ts similarity index 64% rename from musicSdk/kw/tipSearch.js rename to musicSdk/kw/tipSearch.ts index f9253b8..06272c6 100644 --- a/musicSdk/kw/tipSearch.js +++ b/musicSdk/kw/tipSearch.ts @@ -1,32 +1,35 @@ -// import { decodeName } from '../index.js' -// import { tokenRequest } from './util.js' -import { httpFetch } from '../request.js' +// import { decodeName } from '../index.ts' +// import { tokenRequest } from './util.ts' +import { httpFetch } from '../request.ts' +import type { HttpRequestObject } from '../types.ts' export default { regExps: { relWord: /RELWORD=(.+)/, }, - requestObj: null, - async tipSearchBySong(str) { + requestObj: null as HttpRequestObject | null, + async tipSearchBySong(str: string) { // 报错403,加了referer还是有问题(直接换一个 // this.requestObj = await tokenRequest(`http://www.kuwo.cn/api/www/search/searchKey?key=${encodeURIComponent(str)}`) this.cancelTipSearch() this.requestObj = httpFetch(`https://tips.kuwo.cn/t.s?corp=kuwo&newver=3&p2p=1¬race=0&c=mbox&w=${encodeURIComponent(str)}&encoding=utf8&rformat=json`, { - Referer: 'http://www.kuwo.cn/', + headers: { + Referer: 'http://www.kuwo.cn/', + }, }) - return this.requestObj.promise.then(({ body, statusCode }) => { + return this.requestObj!.promise.then(({ body, statusCode }) => { if (statusCode != 200 || !body.WORDITEMS) return Promise.reject(new Error('请求失败')) return body.WORDITEMS }) }, - handleResult(rawData) { + handleResult(rawData: any) { return rawData.map(item => item.RELWORD) }, cancelTipSearch() { if (this.requestObj && this.requestObj.cancelHttp) this.requestObj.cancelHttp() }, - async search(str) { + async search(str: string) { return this.tipSearchBySong(str).then(result => this.handleResult(result)) }, } diff --git a/musicSdk/kw/util.js b/musicSdk/kw/util.ts similarity index 82% rename from musicSdk/kw/util.js rename to musicSdk/kw/util.ts index 61b2c05..482559a 100644 --- a/musicSdk/kw/util.js +++ b/musicSdk/kw/util.ts @@ -1,8 +1,8 @@ -// import { httpGet, httpFetch } from '../request.js' +// import { httpGet, httpFetch } from '../request.ts' import { WIN_MAIN_RENDERER_EVENT_NAME } from '../../src/common/ipcNames.js' import { rendererInvoke } from '../../src/common/rendererIpc.js' import { createCipheriv, createDecipheriv } from 'crypto' -import { toMD5 } from '../utils.js' +import { toMD5 } from '../utils.ts' // const kw_token = { // token: null, @@ -30,14 +30,14 @@ import { toMD5 } from '../utils.js' // return JSON.parse(str.replace(/(^{'|'}\n$|'}$|':'|','|':\[{'|'}\],'|':{'|'},'|'},{'|':\['|':\[\],'|':{},'|'}]})/g, s => translationMap[s])) // } -export const objStr2JSON = str => { +export const objStr2JSON = (str: string): any => { return JSON.parse(str.replace(/('(?=(,\s*')))|('(?=:))|((?<=([:,]\s*))')|((?<={)')|('(?=}))/g, '"')) } -export const formatSinger = rawData => rawData.replace(/&/g, '、') +export const formatSinger = (rawData: string): string => rawData.replace(/&/g, '、') -export const matchToken = headers => { +export const matchToken = (headers: Record): string | null => { try { return headers['set-cookie'][0].match(/kw_token=(\w+)/)[1] } catch (err) { @@ -63,7 +63,8 @@ export const matchToken = headers => { // }) // }) -export const decodeLyric = base64Data => rendererInvoke(WIN_MAIN_RENDERER_EVENT_NAME.handle_kw_decode_lyric, base64Data) +export const decodeLyric = (base64Data: { lrcBase64: string; isGetLyricx: boolean }): Promise => + rendererInvoke(WIN_MAIN_RENDERER_EVENT_NAME.handle_kw_decode_lyric, base64Data) // export const tokenRequest = async(url, options = {}) => { // let token = kw_token.token @@ -86,6 +87,13 @@ export const decodeLyric = base64Data => rendererInvoke(WIN_MAIN_RENDERER_EVENT_ // return requestObj // } +interface LrcWordInfo { + startTime: number + endTime: number + timeStr: string + newTimeStr?: string +} + export const lrcTools = { rxps: { wordLine: /^(\[\d{1,2}:.*\d{1,4}\])\s*(\S+(?:\s+\S+)*)?\s*/, @@ -96,9 +104,9 @@ export const lrcTools = { offset: 1, offset2: 1, isOK: false, - lines: [], - tags: [], - getWordInfo(str, str2, prevWord) { + lines: [] as string[], + tags: [] as string[], + getWordInfo(str: string, str2: string, prevWord?: LrcWordInfo): LrcWordInfo { const offset = parseInt(str) const offset2 = parseInt(str2) let startTime = Math.abs((offset + offset2) / (this.offset * 2)) @@ -120,7 +128,7 @@ export const lrcTools = { timeStr: `<${startTime},${endTime - startTime}>`, } }, - parseLine(line) { + parseLine(line: string): void { if (line.length < 6) return let result = this.rxps.wordLine.exec(line) if (result) { @@ -135,7 +143,7 @@ export const lrcTools = { let preTimeInfo for (const timeStr of wordTimes) { const result = this.rxps.wordTime.exec(timeStr) - const wordInfo = this.getWordInfo(result[1], result[2], preTimeInfo) + const wordInfo = this.getWordInfo(result![1], result![2], preTimeInfo) words = words.replace(timeStr, wordInfo.timeStr) if (preTimeInfo?.newTimeStr) words = words.replace(preTimeInfo.timeStr, preTimeInfo.newTimeStr) preTimeInfo = wordInfo @@ -160,7 +168,7 @@ export const lrcTools = { this.tags.push(line) } }, - parse(lrc) { + parse(lrc: string): string { // console.log(lrc) const lines = lrc.split(/\r\n|\r|\n/) const tools = Object.create(this) @@ -183,30 +191,30 @@ export const lrcTools = { } -const createAesEncrypt = (buffer, mode, key, iv) => { +const createAesEncrypt = (buffer: Buffer, mode: string, key: Buffer | string, iv: string | Buffer): Buffer => { const cipher = createCipheriv(mode, key, iv) return Buffer.concat([cipher.update(buffer), cipher.final()]) } -const createAesDecrypt = (buffer, mode, key, iv) => { +const createAesDecrypt = (buffer: Buffer, mode: string, key: Buffer | string, iv: string | Buffer): Buffer => { 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: Buffer.from([112, 87, 39, 61, 199, 250, 41, 191, 57, 68, 45, 114, 221, 94, 140, 228] as any, 'binary'), aesIv: '', appId: 'y67sprxhhpws', - decodeData(base64Result) { + decodeData(base64Result: string): any { const data = Buffer.from(decodeURIComponent(base64Result), 'base64') return JSON.parse(createAesDecrypt(data, this.aesMode, this.aesKey, this.aesIv).toString()) }, - createSign(data, time) { + createSign(data: string, time: number): string { const str = `${this.appId}${data}${time}` return toMD5(str).toUpperCase() }, - buildParam(jsonData) { + buildParam(jsonData: unknown): string { const data = Buffer.from(JSON.stringify(jsonData)) const time = Date.now() diff --git a/musicSdk/message.js b/musicSdk/message.ts similarity index 100% rename from musicSdk/message.js rename to musicSdk/message.ts diff --git a/musicSdk/mg/comment.js b/musicSdk/mg/comment.ts similarity index 93% rename from musicSdk/mg/comment.js rename to musicSdk/mg/comment.ts index b1af131..b790f7a 100644 --- a/musicSdk/mg/comment.js +++ b/musicSdk/mg/comment.ts @@ -1,11 +1,12 @@ -import { httpFetch } from '../request.js' -import getSongId from './songId.js' -import { dateFormat2 } from '../index.js' +import { httpFetch } from '../request.ts' +import getSongId from './songId.ts' +import { dateFormat2 } from '../index.ts' +import type { HttpRequestObject } from '../types.ts' export default { - _requestObj: null, - _requestObj2: null, - _requestObj3: null, + _requestObj: null as HttpRequestObject | null, + _requestObj2: null as HttpRequestObject | null, + _requestObj3: null as HttpRequestObject | null, lastCommentIds: new Map(), async getComment(musicInfo, page = 1, limit = 20) { if (this._requestObj) this._requestObj.cancelHttp() diff --git a/musicSdk/mg/hotSearch.js b/musicSdk/mg/hotSearch.ts similarity index 82% rename from musicSdk/mg/hotSearch.js rename to musicSdk/mg/hotSearch.ts index ced94c8..8b38abd 100644 --- a/musicSdk/mg/hotSearch.js +++ b/musicSdk/mg/hotSearch.ts @@ -1,7 +1,8 @@ -import { httpFetch } from '../request.js' +import { httpFetch } from '../request.ts' +import type { HttpRequestObject } from '../types.ts' export default { - _requestObj: null, + _requestObj: null as HttpRequestObject | null, async getList(retryNum = 0) { if (this._requestObj) this._requestObj.cancelHttp() if (retryNum > 2) return Promise.reject(new Error('try max num')) diff --git a/musicSdk/mg/index.js b/musicSdk/mg/index.ts similarity index 50% rename from musicSdk/mg/index.js rename to musicSdk/mg/index.ts index 1723376..779ba5c 100644 --- a/musicSdk/mg/index.js +++ b/musicSdk/mg/index.ts @@ -1,12 +1,12 @@ -import { apis } from '../api-source.js' -import leaderboard from './leaderboard.js' -import songList from './songList.js' -import musicSearch from './musicSearch.js' -import pic from './pic.js' -import lyric from './lyric.js' -import hotSearch from './hotSearch.js' -import comment from './comment.js' -// import tipSearch from './tipSearch.js' +import { apis } from '../api-source.ts' +import leaderboard from './leaderboard.ts' +import songList from './songList.ts' +import musicSearch from './musicSearch.ts' +import pic from './pic.ts' +import lyric from './lyric.ts' +import hotSearch from './hotSearch.ts' +import comment from './comment.ts' +// import tipSearch from './tipSearch.ts' const mg = { // tipSearch, @@ -16,7 +16,7 @@ const mg = { hotSearch, comment, getMusicUrl(songInfo, type) { - return apis('mg').getMusicUrl(songInfo, type) + return apis('mg').getMusicUrl!(songInfo, type) }, getLyric(songInfo) { return lyric.getLyric(songInfo) diff --git a/musicSdk/mg/leaderboard.js b/musicSdk/mg/leaderboard.ts similarity index 93% rename from musicSdk/mg/leaderboard.js rename to musicSdk/mg/leaderboard.ts index 922d66c..18f01df 100644 --- a/musicSdk/mg/leaderboard.js +++ b/musicSdk/mg/leaderboard.ts @@ -1,5 +1,6 @@ -import { httpFetch } from '../request.js' -import { filterMusicInfoList } from './musicInfo.js' +import { httpFetch } from '../request.ts' +import { filterMusicInfoList } from './musicInfo.ts' +import type { Source, HttpRequestObject } from '../types.ts' // const boardList = [{ id: 'mg__27553319', name: '咪咕尖叫新歌榜', bangid: '27553319' }, { id: 'mg__27186466', name: '咪咕尖叫热歌榜', bangid: '27186466' }, { id: 'mg__27553408', name: '咪咕尖叫原创榜', bangid: '27553408' }, { id: 'mg__23189800', name: '咪咕港台榜', bangid: '23189800' }, { id: 'mg__23189399', name: '咪咕内地榜', bangid: '23189399' }, { id: 'mg__19190036', name: '咪咕欧美榜', bangid: '19190036' }, { id: 'mg__23189813', name: '咪咕日韩榜', bangid: '23189813' }, { id: 'mg__23190126', name: '咪咕彩铃榜', bangid: '23190126' }, { id: 'mg__15140045', name: '咪咕KTV榜', bangid: '15140045' }, { id: 'mg__15140034', name: '咪咕网络榜', bangid: '15140034' }, { id: 'mg__23217754', name: 'MV榜', bangid: '23217754' }, { id: 'mg__23218151', name: '新专辑榜', bangid: '23218151' }, { id: 'mg__21958042', name: 'iTunes榜', bangid: '21958042' }, { id: 'mg__21975570', name: 'billboard榜', bangid: '21975570' }, { id: 'mg__22272815', name: '台湾Hito中文榜', bangid: '22272815' }, { id: 'mg__22272904', name: '中国TOP排行榜', bangid: '22272904' }, { id: 'mg__22272943', name: '韩国Melon榜', bangid: '22272943' }, { id: 'mg__22273437', name: '英国UK榜', bangid: '22273437' }] @@ -20,7 +21,15 @@ import { filterMusicInfoList } from './musicInfo.js' // // { id: 'mg__22272943', name: '韩国Melon榜', bangid: '22272943', webId: 'mnet' }, // // { id: 'mg__22273437', name: '英国UK榜', bangid: '22273437', webId: 'uk' }, // ] -const boardList = [ +interface BoardItem { + id: string + name: string + bangid: string + source: Source + // 旧数据字段,部分条目缺失(缺失时 getDetailPageUrl 拼出 undefined,与原实现一致) + webId?: string +} +const boardList: BoardItem[] = [ { id: 'mg__27553319', name: '新歌榜', @@ -141,9 +150,9 @@ export default { // return `http://m.music.migu.cn/migu/remoting/cms_list_tag?nid=${id}&pageSize=${this.limit}&pageNo=${page - 1}` }, successCode: '000000', - requestBoardsObj: null, + requestBoardsObj: null as HttpRequestObject | null, getBoardsData() { - if (this.requestBoardsObj) this._requestBoardsObj.cancelHttp() + if (this.requestBoardsObj) (this as any)._requestBoardsObj.cancelHttp() this.requestBoardsObj = httpFetch('https://app.c.nf.migu.cn/pc/bmw/rank/rank-index/v1.0', { // this.requestBoardsObj = httpFetch('https://app.c.nf.migu.cn/MIGUM3.0/v1.0/template/rank-list/release', { // this.requestBoardsObj = httpFetch('https://app.c.nf.migu.cn/MIGUM2.0/v2.0/content/indexrank.do?templateVersion=8', { @@ -153,7 +162,7 @@ export default { channel: '0146921', }, }) - return this.requestBoardsObj.promise + return this.requestBoardsObj!.promise }, getData(url) { const requestObj = httpFetch(url) diff --git a/musicSdk/mg/lyric.js b/musicSdk/mg/lyric.ts similarity index 85% rename from musicSdk/mg/lyric.js rename to musicSdk/mg/lyric.ts index 8925d84..70638db 100644 --- a/musicSdk/mg/lyric.js +++ b/musicSdk/mg/lyric.ts @@ -1,6 +1,6 @@ -import { httpFetch } from '../request.js' -import { getMusicInfo } from './musicInfo.js' -import { decrypt } from './utils/mrc.js' +import { httpFetch } from '../request.ts' +import { getMusicInfo } from './musicInfo.ts' +import { decrypt } from './utils/mrc.ts' const mrcTools = { rxps: { @@ -11,8 +11,8 @@ const mrcTools = { parseLyric(str) { str = str.replace(/\r/g, '') const lines = str.split('\n') - const lxlrcLines = [] - const lrcLines = [] + const lxlrcLines: string[] = [] + const lrcLines: string[] = [] for (const line of lines) { if (line.length < 6) continue @@ -20,12 +20,12 @@ const mrcTools = { if (!result) continue const startTime = parseInt(result[1]) - let time = startTime + let time: any = startTime let ms = time % 1000 time /= 1000 - let m = parseInt(time / 60).toString().padStart(2, '0') + let m = parseInt((time / 60) as unknown as string).toString().padStart(2, '0') time %= 60 - let s = parseInt(time).toString().padStart(2, '0') + let s = parseInt(time as unknown as string).toString().padStart(2, '0') time = `${m}:${s}.${ms}` let words = line.replace(this.rxps.lineTime, '') @@ -36,7 +36,7 @@ const mrcTools = { if (!times) continue times = times.map(time => { const result = /\((\d+),(\d+)\)/.exec(time) - return `<${parseInt(result[1]) - startTime},${result[2]}>` + return `<${parseInt(result![1]) - startTime},${result![2]}>` }) const wordArr = words.split(this.rxps.wordTime) const newWords = times.map((time, index) => `${time}${wordArr[index]}`).join('') diff --git a/musicSdk/mg/musicInfo.js b/musicSdk/mg/musicInfo.ts similarity index 81% rename from musicSdk/mg/musicInfo.js rename to musicSdk/mg/musicInfo.ts index 55b3b4c..7dfd05b 100644 --- a/musicSdk/mg/musicInfo.js +++ b/musicSdk/mg/musicInfo.ts @@ -1,10 +1,11 @@ -import { sizeFormate, formatPlayTime } from '../index.js' -import { createHttpFetch } from './utils/index.js' -import { formatSingerName } from '../utils.js' +import { sizeFormate, formatPlayTime } from '../index.ts' +import { createHttpFetch } from './utils/index.ts' +import { formatSingerName } from '../utils.ts' +import type { SongInfo, SongType, QualityInfo, Quality } from '../types.ts' -const createGetMusicInfosTask = (ids) => { +const createGetMusicInfosTask = (ids: Array) => { let list = ids - let tasks = [] + const tasks: Array> = [] while (list.length) { tasks.push(list.slice(0, 100)) if (list.length < 100) break @@ -19,15 +20,15 @@ const createGetMusicInfosTask = (ids) => { }).then(data => data.resource))) } -export const filterMusicInfoList = (rawList) => { +export const filterMusicInfoList = (rawList: any[]): SongInfo[] => { // console.log(rawList) let ids = new Set() - const list = [] + const list: any[] = [] rawList.forEach(item => { if (!item.songId || ids.has(item.songId)) return ids.add(item.songId) - const types = [] - const _types = {} + const types: SongType[] = [] + const _types: Partial> = {} item.newRateFormats?.forEach(type => { let size switch (type.formatType) { @@ -90,12 +91,12 @@ export const filterMusicInfoList = (rawList) => { export const filterMusicInfoListV5 = (rawList) => { // console.log(rawList) let ids = new Set() - const list = [] + const list: any[] = [] rawList.forEach(item => { if (!item.songId || ids.has(item.songId)) return ids.add(item.songId) - const types = [] - const _types = {} + const types: SongType[] = [] + const _types: Partial> = {} item.audioFormats?.forEach(type => { let size switch (type.formatType) { @@ -153,10 +154,10 @@ export const filterMusicInfoListV5 = (rawList) => { return list } -export const getMusicInfo = async(copyrightId) => { +export const getMusicInfo = async(copyrightId?: string): Promise => { return getMusicInfos([copyrightId]).then(data => data[0]) } -export const getMusicInfos = async(copyrightIds) => { +export const getMusicInfos = async(copyrightIds: Array): Promise => { return filterMusicInfoList((await createGetMusicInfosTask(copyrightIds)).flat()) } diff --git a/musicSdk/mg/musicSearch.js b/musicSdk/mg/musicSearch.ts similarity index 95% rename from musicSdk/mg/musicSearch.js rename to musicSdk/mg/musicSearch.ts index d92d19f..064e5e1 100644 --- a/musicSdk/mg/musicSearch.js +++ b/musicSdk/mg/musicSearch.ts @@ -1,8 +1,9 @@ -import { httpFetch } from '../request.js' -import { sizeFormate, formatPlayTime } from '../index.js' -import { toMD5, formatSingerName } from '../utils.js' +import { httpFetch } from '../request.ts' +import { sizeFormate, formatPlayTime } from '../index.ts' +import { toMD5, formatSingerName } from '../utils.ts' +import type { SongType, QualityInfo, Quality } from '../types.ts' -export const createSignature = (time, str) => { +export const createSignature = (time: string, str: string): { sign: string, deviceId: string } => { const deviceId = '963B7AA0D21511ED807EE5846EC87D20' const signatureMd5 = '6cdc72a439cef99a3418d2a78aa28c73' const sign = toMD5(`${str}${signatureMd5}yyapp2d16148780a1dcc7408e06336b98cfd50${deviceId}${time}`) @@ -126,7 +127,7 @@ export default { }, filterData(rawData) { // console.log(rawData) - const list = [] + const list: any[] = [] const ids = new Set() rawData.forEach(item => { @@ -134,8 +135,8 @@ export default { if (!data.songId || !data.copyrightId || ids.has(data.copyrightId)) return ids.add(data.copyrightId) - const types = [] - const _types = {} + const types: SongType[] = [] + const _types: Partial> = {} data.audioFormats && data.audioFormats.forEach(type => { let size switch (type.formatType) { diff --git a/musicSdk/mg/pic.js b/musicSdk/mg/pic.ts similarity index 85% rename from musicSdk/mg/pic.js rename to musicSdk/mg/pic.ts index 595ed47..e28396c 100644 --- a/musicSdk/mg/pic.js +++ b/musicSdk/mg/pic.ts @@ -1,5 +1,5 @@ -import { httpFetch } from '../request.js' -import getSongId from './songId.js' +import { httpFetch } from '../request.ts' +import getSongId from './songId.ts' export default { async getPicUrl(songId, tryNum = 0) { @@ -11,7 +11,7 @@ export default { requestObj.promise.then(({ body }) => { if (body.returnCode !== '000000') { if (tryNum > 5) return Promise.reject(new Error('图片获取失败')) - let tryRequestObj = this.getPic(songId, ++tryNum) + let tryRequestObj = (this as any).getPic(songId, ++tryNum) requestObj.cancelHttp = tryRequestObj.cancelHttp.bind(tryRequestObj) return tryRequestObj.promise } diff --git a/musicSdk/mg/songId.js b/musicSdk/mg/songId.ts similarity index 84% rename from musicSdk/mg/songId.js rename to musicSdk/mg/songId.ts index 6fdd438..596fcac 100644 --- a/musicSdk/mg/songId.js +++ b/musicSdk/mg/songId.ts @@ -1,10 +1,11 @@ // import { httpFetch } from '../request.js' -import { getMusicInfo } from './musicInfo.js' +import { getMusicInfo } from './musicInfo.ts' +import type { SongInfo } from '../types.ts' -const getSongId = async(mInfo) => { +const getSongId = async(mInfo: SongInfo): Promise => { if (mInfo.songmid != mInfo.copyrightId) return mInfo.songmid const musicInfo = await getMusicInfo(mInfo.copyrightId) - return musicInfo.songmid + return musicInfo!.songmid } diff --git a/musicSdk/mg/songList.js b/musicSdk/mg/songList.ts similarity index 97% rename from musicSdk/mg/songList.js rename to musicSdk/mg/songList.ts index b4c3e4d..13f8ce2 100644 --- a/musicSdk/mg/songList.js +++ b/musicSdk/mg/songList.ts @@ -1,14 +1,15 @@ -import { httpFetch } from '../request.js' -import { formatPlayCount } from '../index.js' -import { filterMusicInfoListV5 } from './musicInfo.js' -import { createSignature } from './musicSearch.js' -import { createHttpFetch } from './utils/index.js' +import { httpFetch } from '../request.ts' +import { formatPlayCount } from '../index.ts' +import { filterMusicInfoListV5 } from './musicInfo.ts' +import { createSignature } from './musicSearch.ts' +import { createHttpFetch } from './utils/index.ts' +import type { HttpRequestObject } from '../types.ts' // const tagData = { code: '000000', info: 'SUCCESS', columnInfo: { columnTitle: '分类', columnId: '15244430', columnPid: '15031270', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 6, columnStatus: 1, columnCreateTime: '2016-11-10 10:53:05.077', columntype: 2011, contents: [{ contentId: '18464615', relationType: 2011, objectInfo: { columnTitle: '热门', columnId: '18464615', columnPid: '15244430', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 8, columnStatus: 1, columnCreateTime: '2017-02-20 16:09:13.400', columntype: 2011, contents: [{ contentId: '1000001672', relationType: 4034, objectInfo: { tagId: '1000001672', tagName: '流行', resourceType: '2034' }, relationSort: 9 }, { contentId: '1003449727', relationType: 4034, objectInfo: { tagId: '1003449727', tagName: '厂牌', resourceType: '2034' }, relationSort: 8 }, { contentId: '1000001795', relationType: 4034, objectInfo: { tagId: '1000001795', tagName: '伤感', resourceType: '2034' }, relationSort: 7 }, { contentId: '1001076080', relationType: 4034, objectInfo: { tagId: '1001076080', tagName: '电影', resourceType: '2034' }, relationSort: 6 }, { contentId: '1000001675', relationType: 4034, objectInfo: { tagId: '1000001675', tagName: '中国风', resourceType: '2034' }, relationSort: 5 }, { contentId: '1000001635', relationType: 4034, objectInfo: { tagId: '1000001635', tagName: '经典老歌', resourceType: '2034' }, relationSort: 4 }, { contentId: '1000001831', relationType: 4034, objectInfo: { tagId: '1000001831', tagName: '翻唱', resourceType: '2034' }, relationSort: 3 }, { contentId: '1000001762', relationType: 4034, objectInfo: { tagId: '1000001762', tagName: '国语', resourceType: '2034' }, relationSort: 1 }], dataVersion: '1620410266029', customizedPicUrls: [] }, relationSort: 6 }, { contentId: '15244503', relationType: 2011, objectInfo: { columnTitle: '主题', columnId: '15244503', columnPid: '15244430', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 23, columnStatus: 1, columnCreateTime: '2016-11-10 10:54:10.261', columntype: 2011, contents: [{ contentId: '1003449727', relationType: 4034, objectInfo: { tagId: '1003449727', tagName: '厂牌', resourceType: '2034' }, relationSort: 29 }, { contentId: '1001076080', relationType: 4034, objectInfo: { tagId: '1001076080', tagName: '电影', resourceType: '2034' }, relationSort: 28 }, { contentId: '1001076078', relationType: 4034, objectInfo: { tagId: '1001076078', tagName: '电视剧', resourceType: '2034' }, relationSort: 27 }, { contentId: '1001076083', relationType: 4034, objectInfo: { tagId: '1001076083', tagName: '综艺', resourceType: '2034' }, relationSort: 26 }, { contentId: '1000001827', relationType: 4034, objectInfo: { tagId: '1000001827', tagName: 'KTV', resourceType: '2034' }, relationSort: 23 }, { contentId: '1000001698', relationType: 4034, objectInfo: { tagId: '1000001698', tagName: '爱情', resourceType: '2034' }, relationSort: 22 }, { contentId: '1000001635', relationType: 4034, objectInfo: { tagId: '1000001635', tagName: '经典老歌', resourceType: '2034' }, relationSort: 21 }, { contentId: '1001076096', relationType: 4034, objectInfo: { tagId: '1001076096', tagName: '网络热歌', resourceType: '2034' }, relationSort: 20 }, { contentId: '1000001780', relationType: 4034, objectInfo: { tagId: '1000001780', tagName: '儿童歌曲', resourceType: '2034' }, relationSort: 19 }, { contentId: '1000587702', relationType: 4034, objectInfo: { tagId: '1000587702', tagName: '广场舞', resourceType: '2034' }, relationSort: 18 }, { contentId: '1000587717', relationType: 4034, objectInfo: { tagId: '1000587717', tagName: '70后', resourceType: '2034' }, relationSort: 17 }, { contentId: '1000587718', relationType: 4034, objectInfo: { tagId: '1000587718', tagName: '80后', resourceType: '2034' }, relationSort: 16 }, { contentId: '1000587726', relationType: 4034, objectInfo: { tagId: '1000587726', tagName: '90后', resourceType: '2034' }, relationSort: 15 }, { contentId: '1000001670', relationType: 4034, objectInfo: { tagId: '1000001670', tagName: '红歌', resourceType: '2034' }, relationSort: 14 }, { contentId: '1000587698', relationType: 4034, objectInfo: { tagId: '1000587698', tagName: '游戏', resourceType: '2034' }, relationSort: 13 }, { contentId: '1000587706', relationType: 4034, objectInfo: { tagId: '1000587706', tagName: '动漫', resourceType: '2034' }, relationSort: 12 }, { contentId: '1000001675', relationType: 4034, objectInfo: { tagId: '1000001675', tagName: '中国风', resourceType: '2034' }, relationSort: 11 }, { contentId: '1000587712', relationType: 4034, objectInfo: { tagId: '1000587712', tagName: '青春校园', resourceType: '2034' }, relationSort: 10 }, { contentId: '1000587673', relationType: 4034, objectInfo: { tagId: '1000587673', tagName: '小清新', resourceType: '2034' }, relationSort: 9 }, { contentId: '1000093902', relationType: 4034, objectInfo: { tagId: '1000093902', tagName: 'DJ舞曲', resourceType: '2034' }, relationSort: 7 }, { contentId: '1000093963', relationType: 4034, objectInfo: { tagId: '1000093963', tagName: '广告', resourceType: '2034' }, relationSort: 6 }, { contentId: '1000001831', relationType: 4034, objectInfo: { tagId: '1000001831', tagName: '翻唱', resourceType: '2034' }, relationSort: 2 }, { contentId: '1003449726', relationType: 4034, objectInfo: { tagId: '1003449726', tagName: '读书', resourceType: '2034' }, relationSort: 1 }], dataVersion: '1620410266055', customizedPicUrls: [] }, relationSort: 5 }, { contentId: '15244509', relationType: 2011, objectInfo: { columnTitle: '风格', columnId: '15244509', columnPid: '15244430', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 12, columnStatus: 1, columnCreateTime: '2016-11-10 10:54:57.257', columntype: 2011, contents: [{ contentId: '1000001672', relationType: 4034, objectInfo: { tagId: '1000001672', tagName: '流行', resourceType: '2034' }, relationSort: 14 }, { contentId: '1000001808', relationType: 4034, objectInfo: { tagId: '1000001808', tagName: 'R&B', resourceType: '2034' }, relationSort: 13 }, { contentId: '1000001809', relationType: 4034, objectInfo: { tagId: '1000001809', tagName: '嘻哈', resourceType: '2034' }, relationSort: 12 }, { contentId: '1000001674', relationType: 4034, objectInfo: { tagId: '1000001674', tagName: '摇滚', resourceType: '2034' }, relationSort: 11 }, { contentId: '1000001682', relationType: 4034, objectInfo: { tagId: '1000001682', tagName: '电子', resourceType: '2034' }, relationSort: 10 }, { contentId: '1000001852', relationType: 4034, objectInfo: { tagId: '1000001852', tagName: '电子舞曲', resourceType: '2034' }, relationSort: 9 }, { contentId: '1000001681', relationType: 4034, objectInfo: { tagId: '1000001681', tagName: '爵士', resourceType: '2034' }, relationSort: 6 }, { contentId: '1000001683', relationType: 4034, objectInfo: { tagId: '1000001683', tagName: '乡村', resourceType: '2034' }, relationSort: 5 }, { contentId: '1000001851', relationType: 4034, objectInfo: { tagId: '1000001851', tagName: '蓝调', resourceType: '2034' }, relationSort: 4 }, { contentId: '1000001775', relationType: 4034, objectInfo: { tagId: '1000001775', tagName: '民谣', resourceType: '2034' }, relationSort: 3 }, { contentId: '1000001807', relationType: 4034, objectInfo: { tagId: '1000001807', tagName: '纯音乐', resourceType: '2034' }, relationSort: 2 }, { contentId: '1000001783', relationType: 4034, objectInfo: { tagId: '1000001783', tagName: '古典', resourceType: '2034' }, relationSort: 1 }], dataVersion: '1620410266033', customizedPicUrls: [] }, relationSort: 4 }, { contentId: '18464665', relationType: 2011, objectInfo: { columnTitle: '语种', columnId: '18464665', columnPid: '15244430', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 6, columnStatus: 1, columnCreateTime: '2017-02-20 16:07:16.566', columntype: 2011, contents: [{ contentId: '1000001762', relationType: 4034, objectInfo: { tagId: '1000001762', tagName: '国语', resourceType: '2034' }, relationSort: 6 }, { contentId: '1000001763', relationType: 4034, objectInfo: { tagId: '1000001763', tagName: '粤语', resourceType: '2034' }, relationSort: 5 }, { contentId: '1000001766', relationType: 4034, objectInfo: { tagId: '1000001766', tagName: '英语', resourceType: '2034' }, relationSort: 4 }, { contentId: '1000001599', relationType: 4034, objectInfo: { tagId: '1000001599', tagName: '韩语', resourceType: '2034' }, relationSort: 3 }, { contentId: '1000001767', relationType: 4034, objectInfo: { tagId: '1000001767', tagName: '日语', resourceType: '2034' }, relationSort: 2 }, { contentId: '1003449724', relationType: 4034, objectInfo: { tagId: '1003449724', tagName: '小语种', resourceType: '2034' }, relationSort: 1 }], dataVersion: '1620410266036', customizedPicUrls: [] }, relationSort: 3 }, { contentId: '18464583', relationType: 2011, objectInfo: { columnTitle: '心情', columnId: '18464583', columnPid: '15244430', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 13, columnStatus: 1, columnCreateTime: '2017-02-20 15:59:03.412', columntype: 2011, contents: [{ contentId: '1000587677', relationType: 4034, objectInfo: { tagId: '1000587677', tagName: '幸福', resourceType: '2034' }, relationSort: 15 }, { contentId: '1000587710', relationType: 4034, objectInfo: { tagId: '1000587710', tagName: '治愈', resourceType: '2034' }, relationSort: 14 }, { contentId: '1000001703', relationType: 4034, objectInfo: { tagId: '1000001703', tagName: '思念', resourceType: '2034' }, relationSort: 13 }, { contentId: '1000587667', relationType: 4034, objectInfo: { tagId: '1000587667', tagName: '期待', resourceType: '2034' }, relationSort: 12 }, { contentId: '1000001700', relationType: 4034, objectInfo: { tagId: '1000001700', tagName: '励志', resourceType: '2034' }, relationSort: 11 }, { contentId: '1000001694', relationType: 4034, objectInfo: { tagId: '1000001694', tagName: '欢快', resourceType: '2034' }, relationSort: 10 }, { contentId: '1002600588', relationType: 4034, objectInfo: { tagId: '1002600588', tagName: '叛逆', resourceType: '2034' }, relationSort: 9 }, { contentId: '1002600585', relationType: 4034, objectInfo: { tagId: '1002600585', tagName: '宣泄', resourceType: '2034' }, relationSort: 8 }, { contentId: '1000001696', relationType: 4034, objectInfo: { tagId: '1000001696', tagName: '怀旧', resourceType: '2034' }, relationSort: 7 }, { contentId: '1000587679', relationType: 4034, objectInfo: { tagId: '1000587679', tagName: '减压', resourceType: '2034' }, relationSort: 6 }, { contentId: '1000001699', relationType: 4034, objectInfo: { tagId: '1000001699', tagName: '寂寞', resourceType: '2034' }, relationSort: 5 }, { contentId: '1002600579', relationType: 4034, objectInfo: { tagId: '1002600579', tagName: '忧郁', resourceType: '2034' }, relationSort: 4 }, { contentId: '1000001795', relationType: 4034, objectInfo: { tagId: '1000001795', tagName: '伤感', resourceType: '2034' }, relationSort: 3 }], dataVersion: '1620410266187', customizedPicUrls: [] }, relationSort: 2 }, { contentId: '18464638', relationType: 2011, objectInfo: { columnTitle: '场景', columnId: '18464638', columnPid: '15244430', opNumItem: { playNum: 0, playNumDesc: '0', keepNum: 0, keepNumDesc: '0', commentNum: 0, commentNumDesc: '0', shareNum: 0, shareNumDesc: '0', orderNumByWeek: 0, orderNumByWeekDesc: '0', orderNumByTotal: 0, orderNumByTotalDesc: '0', thumbNum: 0, thumbNumDesc: '0', followNum: 0, followNumDesc: '0', subscribeNum: 0, subscribeNumDesc: '0', livePlayNum: 0, livePlayNumDesc: '0', popularNum: 0, popularNumDesc: '0', bookingNum: 0, bookingNumDesc: '0' }, contentsCount: 13, columnStatus: 1, columnCreateTime: '2017-02-20 16:02:59.711', columntype: 2011, contents: [{ contentId: '1000587689', relationType: 4034, objectInfo: { tagId: '1000587689', tagName: '清晨', resourceType: '2034' }, relationSort: 21 }, { contentId: '1000587690', relationType: 4034, objectInfo: { tagId: '1000587690', tagName: '夜晚', resourceType: '2034' }, relationSort: 20 }, { contentId: '1000587688', relationType: 4034, objectInfo: { tagId: '1000587688', tagName: '睡前安眠', resourceType: '2034' }, relationSort: 19 }, { contentId: '1003449726', relationType: 4034, objectInfo: { tagId: '1003449726', tagName: '读书', resourceType: '2034' }, relationSort: 18 }, { contentId: '1003449723', relationType: 4034, objectInfo: { tagId: '1003449723', tagName: '下午·茶', resourceType: '2034' }, relationSort: 16 }, { contentId: '1000093923', relationType: 4034, objectInfo: { tagId: '1000093923', tagName: '驾车', resourceType: '2034' }, relationSort: 15 }, { contentId: '1003449615', relationType: 4034, objectInfo: { tagId: '1003449615', tagName: '运动', resourceType: '2034' }, relationSort: 13 }, { contentId: '1000587694', relationType: 4034, objectInfo: { tagId: '1000587694', tagName: '散步', resourceType: '2034' }, relationSort: 12 }, { contentId: '1000001749', relationType: 4034, objectInfo: { tagId: '1000001749', tagName: '旅行', resourceType: '2034' }, relationSort: 11 }, { contentId: '1000587686', relationType: 4034, objectInfo: { tagId: '1000587686', tagName: '夜店', resourceType: '2034' }, relationSort: 10 }, { contentId: '1002600606', relationType: 4034, objectInfo: { tagId: '1002600606', tagName: '派对', resourceType: '2034' }, relationSort: 9 }, { contentId: '1000001634', relationType: 4034, objectInfo: { tagId: '1000001634', tagName: '咖啡馆', resourceType: '2034' }, relationSort: 3 }, { contentId: '1000587692', relationType: 4034, objectInfo: { tagId: '1000587692', tagName: '瑜伽', resourceType: '2034' }, relationSort: 1 }], dataVersion: '1620846028994', customizedPicUrls: [] }, relationSort: 1 }], dataVersion: '1620846028941', customizedPicUrls: [] } } export default { - _requestObj_tags: null, - _requestObj_list: null, + _requestObj_tags: null as HttpRequestObject | null, + _requestObj_list: null as HttpRequestObject | null, limit_list: 30, limit_song: 50, successCode: '000000', @@ -200,7 +201,7 @@ export default { // source: 'mg', // } // }) - return this._requestObj_list.promise.then(({ body }) => { + return this._requestObj_list!.promise.then(({ body }) => { // console.log(body) // if (body.retCode !== '000000') return this.getList(sortId, tagId, page, ++tryNum) if (body.code !== '000000') return this.getList(sortId, tagId, page, ++tryNum) @@ -214,7 +215,7 @@ export default { } }) }, - filterList2(listData, list = [], ids = new Set()) { + filterList2(listData, list: any[] = [], ids = new Set()) { for (const item of listData) { if (item.contents) this.filterList2(item.contents, list, ids) else if (item.resType == '2021' && !ids.has(item.resId)) { @@ -255,7 +256,7 @@ export default { if (this._requestObj_tags) this._requestObj_tags.cancelHttp() if (tryNum > 2) return Promise.reject(new Error('try max num')) this._requestObj_tags = httpFetch(this.tagsUrl, { headers: this.defaultHeaders }) - return this._requestObj_tags.promise.then(({ body }) => { + return this._requestObj_tags!.promise.then(({ body }) => { if (body.code !== this.successCode) return this.getTag(++tryNum) // console.log(body) return this.filterTagInfo(body.data) @@ -314,7 +315,7 @@ export default { }, filterSongListResult(raw) { - const list = [] + const list: any[] = [] raw.forEach(item => { if (!item.id) return diff --git a/musicSdk/mg/tipSearch.js b/musicSdk/mg/tipSearch.ts similarity index 89% rename from musicSdk/mg/tipSearch.js rename to musicSdk/mg/tipSearch.ts index 34bfe64..f25e016 100644 --- a/musicSdk/mg/tipSearch.js +++ b/musicSdk/mg/tipSearch.ts @@ -1,7 +1,7 @@ -import { createHttpFetch } from './utils/index.js' +import { createHttpFetch } from './utils/index.ts' export default { - requestObj: null, + requestObj: null as any, cancelTipSearch() { if (this.requestObj && this.requestObj.cancelHttp) this.requestObj.cancelHttp() }, diff --git a/musicSdk/mg/utils/index.js b/musicSdk/mg/utils/index.ts similarity index 77% rename from musicSdk/mg/utils/index.js rename to musicSdk/mg/utils/index.ts index 3be6097..5d6416e 100644 --- a/musicSdk/mg/utils/index.js +++ b/musicSdk/mg/utils/index.ts @@ -1,4 +1,5 @@ -import { httpFetch } from '../../request.js' +import { httpFetch } from '../../request.ts' +import type { HttpOptions } from '../../types.ts' /** * 创建一个适用于MG的Http请求 @@ -6,7 +7,7 @@ import { httpFetch } from '../../request.js' * @param {*} options * @param {*} retryNum */ -export const createHttpFetch = async(url, options, retryNum = 0) => { +export const createHttpFetch = async(url: string, options?: HttpOptions, retryNum = 0): Promise => { if (retryNum > 2) throw new Error('try max num') let result try { diff --git a/musicSdk/mg/utils/mrc.js b/musicSdk/mg/utils/mrc.ts similarity index 69% rename from musicSdk/mg/utils/mrc.js rename to musicSdk/mg/utils/mrc.ts index 98ebb68..bbb4b58 100644 --- a/musicSdk/mg/utils/mrc.js +++ b/musicSdk/mg/utils/mrc.ts @@ -16,7 +16,7 @@ const keyArr = [ ] -const teaDecrypt = (data, key) => { +const teaDecrypt = (data: bigint[], key: bigint[]): bigint[] => { const length = data.length const lengthBitint = BigInt(length) if (length >= 1) { @@ -31,14 +31,14 @@ const teaDecrypt = (data, key) => { while (true) { j6-- if (j6 > 0n) { - let j7 = data[(j6 - 1n)] - let i = j6 - j2 = toLong(data[i] - (toLong(toLong(j2 ^ j4) + toLong(j7 ^ key[toLong(toLong(3n & j6) ^ j5)])) ^ toLong(toLong(toLong(j7 >> 5n) ^ toLong(j2 << 2n)) + toLong(toLong(j2 >> 3n) ^ toLong(j7 << 4n))))) + let j7 = data[(j6 - 1n) as unknown as number] + let i = j6 as unknown as number + j2 = toLong(data[i] - (toLong(toLong(j2 ^ j4) + toLong(j7 ^ key[toLong(toLong(3n & j6) ^ j5) as unknown as number])) ^ toLong(toLong(toLong(j7 >> 5n) ^ toLong(j2 << 2n)) + toLong(toLong(j2 >> 3n) ^ toLong(j7 << 4n))))) data[i] = j2 } else break } - let j8 = data[lengthBitint - 1n] - j2 = toLong(data[0n] - toLong(toLong(toLong(key[toLong(toLong(j6 & 3n) ^ j5)] ^ j8) + toLong(j2 ^ j4)) ^ toLong(toLong(toLong(j8 >> 5n) ^ toLong(j2 << 2n)) + toLong(toLong(j2 >> 3n) ^ toLong(j8 << 4n))))) + let j8 = data[lengthBitint - 1n as unknown as number] + j2 = toLong(data[0n as unknown as number] - toLong(toLong(toLong(key[toLong(toLong(j6 & 3n) ^ j5) as unknown as number] ^ j8) + toLong(j2 ^ j4)) ^ toLong(toLong(toLong(j8 >> 5n) ^ toLong(j2 << 2n)) + toLong(toLong(j2 >> 3n) ^ toLong(j8 << 4n))))) data[0] = j2 j3 = toLong(j4 - DELTA) } @@ -46,26 +46,26 @@ const teaDecrypt = (data, key) => { return data } -const longArrToString = (data) => { - const arrayList = [] +const longArrToString = (data: bigint[]): string => { + const arrayList: string[] = [] for (const j of data) arrayList.push(longToBytes(j).toString('utf16le')) return arrayList.join('') } // https://stackoverflow.com/a/29132118 -const longToBytes = (l) => { +const longToBytes = (l: bigint): Buffer => { const result = Buffer.alloc(8) for (let i = 0; i < 8; i++) { - result[i] = parseInt(l & 0xFFn) + result[i] = parseInt((l & 0xFFn) as unknown as string) l >>= 8n } return result } -const toBigintArray = (data) => { +const toBigintArray = (data: string): bigint[] => { const length = Math.floor(data.length / 16) - const jArr = Array(length) + const jArr: bigint[] = Array(length) for (let i = 0; i < length; i++) { jArr[i] = toLong(data.substring(i * 16, (i * 16) + 16)) } @@ -75,14 +75,14 @@ const toBigintArray = (data) => { // https://github.com/lyswhut/lx-music-desktop/issues/445#issuecomment-1139338682 const MAX = 9223372036854775807n const MIN = -9223372036854775808n -const toLong = str => { +const toLong = (str: string | bigint): bigint => { const num = typeof str == 'string' ? BigInt('0x' + str) : str if (num > MAX) return toLong(num - (1n << 64n)) else if (num < MIN) return toLong(num + (1n << 64n)) return num } -export const decrypt = (data) => { +export const decrypt = (data: string | null): string | null => { // console.log(data.length) // -3551594764563790630 // console.log(toLongArrayFromArr(Buffer.from(key))) diff --git a/musicSdk/options.js b/musicSdk/options.ts similarity index 57% rename from musicSdk/options.js rename to musicSdk/options.ts index c6ce350..d98ac4c 100644 --- a/musicSdk/options.js +++ b/musicSdk/options.ts @@ -1,9 +1,9 @@ +// SDK 公共请求常量 export const bHh = '624868746c' -export const headers = { +export const headers: Record = { 'User-Agent': 'lx-music request', [bHh]: [bHh], } - export const timeout = 15000 diff --git a/musicSdk/request.js b/musicSdk/request.js deleted file mode 100644 index d7a8184..0000000 --- a/musicSdk/request.js +++ /dev/null @@ -1,4 +0,0 @@ -// SDK 根请求模块(转接至 src/common/request.js) -// musicSdk 内 `import { httpFetch } from '../request.js'` 的解析目标 - -export { httpFetch } from '../src/common/request.js' diff --git a/musicSdk/request.ts b/musicSdk/request.ts new file mode 100644 index 0000000..7af1270 --- /dev/null +++ b/musicSdk/request.ts @@ -0,0 +1,8 @@ +// SDK 根请求模块(转接至 src/common/request.js) +// musicSdk 内 `import { ... } from '../request.js'` 的解析目标 + +import { httpFetch as rawHttpFetch } from '../src/common/request.js' +import type { HttpRequestObject, HttpOptions } from './types.ts' + +export const httpFetch: (url: string, options?: HttpOptions) => HttpRequestObject = + rawHttpFetch as (url: string, options?: HttpOptions) => HttpRequestObject diff --git a/musicSdk/tx/comment.js b/musicSdk/tx/comment.ts similarity index 95% rename from musicSdk/tx/comment.js rename to musicSdk/tx/comment.ts index 48ae29b..9061839 100644 --- a/musicSdk/tx/comment.js +++ b/musicSdk/tx/comment.ts @@ -1,6 +1,7 @@ -import { httpFetch } from '../request.js' -import { dateFormat2 } from '../index.js' -import getMusicInfo from './musicInfo.js' +import type { HttpRequestObject } from '../types.ts' +import { httpFetch } from '../request.ts' +import { dateFormat2 } from '../index.ts' +import getMusicInfo from './musicInfo.ts' const emojis = { e400846: '😘', @@ -75,15 +76,16 @@ const songIdMap = new Map() const promises = new Map() export default { - _requestObj: null, - _requestObj2: null, + _requestObj: null as HttpRequestObject | null, + _requestObj2: null as HttpRequestObject | null, async getSongId({ songId, songmid }) { if (songId) return songId if (songIdMap.has(songmid)) return songIdMap.get(songmid) if (promises.has(songmid)) return (await promises.get(songmid)).songId const promise = getMusicInfo(songmid) - promises.set(promise) + promises.set(songmid, promise) const info = await promise + if (!info) throw new Error('获取歌曲信息失败') songIdMap.set(songmid, info.songId) promises.delete(songmid) return info.songId diff --git a/musicSdk/tx/hotSearch.js b/musicSdk/tx/hotSearch.ts similarity index 91% rename from musicSdk/tx/hotSearch.js rename to musicSdk/tx/hotSearch.ts index 3983869..4377cf4 100644 --- a/musicSdk/tx/hotSearch.js +++ b/musicSdk/tx/hotSearch.ts @@ -1,7 +1,8 @@ -import { httpFetch } from '../request.js' +import type { HttpRequestObject } from '../types.ts' +import { httpFetch } from '../request.ts' export default { - _requestObj: null, + _requestObj: null as HttpRequestObject | null, async getList(retryNum = 0) { if (this._requestObj) this._requestObj.cancelHttp() if (retryNum > 2) return Promise.reject(new Error('try max num')) diff --git a/musicSdk/tx/index.js b/musicSdk/tx/index.ts similarity index 60% rename from musicSdk/tx/index.js rename to musicSdk/tx/index.ts index 78d3571..2d6793f 100644 --- a/musicSdk/tx/index.js +++ b/musicSdk/tx/index.ts @@ -1,11 +1,11 @@ -import leaderboard from './leaderboard.js' -import lyric from './lyric.js' -import songList from './songList.js' -import musicSearch from './musicSearch.js' -import { apis } from '../api-source.js' -import hotSearch from './hotSearch.js' -import comment from './comment.js' -// import tipSearch from './tipSearch.js' +import leaderboard from './leaderboard.ts' +import lyric from './lyric.ts' +import songList from './songList.ts' +import musicSearch from './musicSearch.ts' +import { apis } from '../api-source.ts' +import hotSearch from './hotSearch.ts' +import comment from './comment.ts' +// import tipSearch from './tipSearch.ts' const tx = { // tipSearch, @@ -16,7 +16,7 @@ const tx = { comment, getMusicUrl(songInfo, type) { - return apis('tx').getMusicUrl(songInfo, type) + return apis('tx')!.getMusicUrl(songInfo, type) }, getLyric(songInfo) { // let singer = songInfo.singer.indexOf('、') > -1 ? songInfo.singer.split('、')[0] : songInfo.singer diff --git a/musicSdk/tx/leaderboard.js b/musicSdk/tx/leaderboard.ts similarity index 92% rename from musicSdk/tx/leaderboard.js rename to musicSdk/tx/leaderboard.ts index 84d87dd..d8cb2c5 100644 --- a/musicSdk/tx/leaderboard.js +++ b/musicSdk/tx/leaderboard.ts @@ -1,6 +1,7 @@ -import { httpFetch } from '../request.js' -import { formatPlayTime, sizeFormate } from '../index.js' -import { formatSingerName } from '../utils.js' +import type { HttpRequestObject, SongInfo, SongType, Quality, QualityInfo } from '../types.ts' +import { httpFetch } from '../request.ts' +import { formatPlayTime, sizeFormate } from '../index.ts' +import { formatSingerName } from '../utils.ts' let boardList = [{ id: 'tx__4', name: '流行指数榜', bangid: '4' }, { id: 'tx__26', name: '热歌榜', bangid: '26' }, { id: 'tx__27', name: '新歌榜', bangid: '27' }, { id: 'tx__62', name: '飙升榜', bangid: '62' }, { id: 'tx__58', name: '说唱榜', bangid: '58' }, { id: 'tx__57', name: '喜力电音榜', bangid: '57' }, { id: 'tx__28', name: '网络歌曲榜', bangid: '28' }, { id: 'tx__5', name: '内地榜', bangid: '5' }, { id: 'tx__3', name: '欧美榜', bangid: '3' }, { id: 'tx__59', name: '香港地区榜', bangid: '59' }, { id: 'tx__16', name: '韩国榜', bangid: '16' }, { id: 'tx__60', name: '抖快榜', bangid: '60' }, { id: 'tx__29', name: '影视金曲榜', bangid: '29' }, { id: 'tx__17', name: '日本榜', bangid: '17' }, { id: 'tx__52', name: '腾讯音乐人原创榜', bangid: '52' }, { id: 'tx__36', name: 'K歌金曲榜', bangid: '36' }, { id: 'tx__61', name: '台湾地区榜', bangid: '61' }, { id: 'tx__63', name: 'DJ舞曲榜', bangid: '63' }, { id: 'tx__64', name: '综艺新歌榜', bangid: '64' }, { id: 'tx__65', name: '国风热歌榜', bangid: '65' }, { id: 'tx__67', name: '听歌识曲榜', bangid: '67' }, { id: 'tx__72', name: '动漫音乐榜', bangid: '72' }, { id: 'tx__73', name: '游戏音乐榜', bangid: '73' }, { id: 'tx__75', name: '有声榜', bangid: '75' }, { id: 'tx__131', name: '校园音乐人排行榜', bangid: '131' }] @@ -10,57 +11,57 @@ export default { { id: 'txlxzsb', name: '流行榜', - bangid: 4, + bangid: '4', }, { id: 'txrgb', name: '热歌榜', - bangid: 26, + bangid: '26', }, { id: 'txwlhgb', name: '网络榜', - bangid: 28, + bangid: '28', }, { id: 'txdyb', name: '抖音榜', - bangid: 60, + bangid: '60', }, { id: 'txndb', name: '内地榜', - bangid: 5, + bangid: '5', }, { id: 'txxgb', name: '香港榜', - bangid: 59, + bangid: '59', }, { id: 'txtwb', name: '台湾榜', - bangid: 61, + bangid: '61', }, { id: 'txoumb', name: '欧美榜', - bangid: 3, + bangid: '3', }, { id: 'txhgb', name: '韩国榜', - bangid: 16, + bangid: '16', }, { id: 'txrbb', name: '日本榜', - bangid: 17, + bangid: '17', }, { id: 'txtybb', name: 'YouTube榜', - bangid: 128, + bangid: '128', }, ], listDetailRequest(id, period, limit) { @@ -95,7 +96,7 @@ export default { }, periods: {}, periodUrl: 'https://c.y.qq.com/node/pc/wk_v15/top.html', - _requestBoardsObj: null, + _requestBoardsObj: null as HttpRequestObject | null, getBoardsData() { if (this._requestBoardsObj) this._requestBoardsObj.cancelHttp() this._requestBoardsObj = httpFetch('https://c.y.qq.com/v8/fcg-bin/fcg_myqq_toplist.fcg?g_tk=1928093487&inCharset=utf-8&outCharset=utf-8¬ice=0&format=json&uin=0&needNewCode=1&platform=h5') @@ -108,8 +109,8 @@ export default { filterData(rawList) { // console.log(rawList) return rawList.map(item => { - let types = [] - let _types = {} + let types: SongType[] = [] + let _types: Partial> = {} if (item.file.size_128mp3 !== 0) { let size = sizeFormate(item.file.size_128mp3) types.push({ type: '128k', size }) @@ -180,7 +181,7 @@ export default { }, filterBoardsData(rawList) { // console.log(rawList) - let list = [] + let list: any[] = [] for (const board of rawList) { // 排除 MV榜 if (board.id == 201) continue diff --git a/musicSdk/tx/lyric.js b/musicSdk/tx/lyric.ts similarity index 92% rename from musicSdk/tx/lyric.js rename to musicSdk/tx/lyric.ts index 0d810fb..9920420 100644 --- a/musicSdk/tx/lyric.js +++ b/musicSdk/tx/lyric.ts @@ -1,7 +1,8 @@ -import { httpFetch } from '../request.js' -import getMusicInfo from './musicInfo.js' -import { rendererInvoke } from '../../src/common/rendererIpc.js' -import { WIN_MAIN_RENDERER_EVENT_NAME } from '../../src/common/ipcNames.js' +import type { HttpRequestObject } from '../types.ts' +import { httpFetch } from '../request.ts' +import getMusicInfo from './musicInfo.ts' +import { rendererInvoke } from '../../src/common/rendererIpc.ts' +import { WIN_MAIN_RENDERER_EVENT_NAME } from '../../src/common/ipcNames.ts' const songIdMap = new Map() const promises = new Map() @@ -21,9 +22,9 @@ const parseTools = { if (Number.isNaN(timeMs)) return '' let ms = timeMs % 1000 timeMs /= 1000 - let m = parseInt(timeMs / 60).toString().padStart(2, '0') + let m = Math.floor(timeMs / 60).toString().padStart(2, '0') timeMs %= 60 - let s = parseInt(timeMs).toString().padStart(2, '0') + let s = Math.floor(timeMs).toString().padStart(2, '0') return `[${m}:${s}.${String(ms).padStart(3, '0')}]` }, parseLyric(lrc) { @@ -32,8 +33,8 @@ const parseTools = { if (!lrc) return { lyric: '', lxlyric: '' } const lines = lrc.split('\n') - const lxlrcLines = [] - const lrcLines = [] + const lxlrcLines: string[] = [] + const lrcLines: string[] = [] for (let line of lines) { line = line.trim() @@ -61,7 +62,7 @@ const parseTools = { let times = words.match(this.rxps.wordTimeAll) if (!times) continue times = times.map(time => { - const result = /\((\d+),(\d+)\)/.exec(time) + const result = /\((\d+),(\d+)\)/.exec(time)! return `<${Math.max(parseInt(result[1]) - startMsTime, 0)},${result[2]}>` }) const wordArr = words.split(this.rxps.wordTime) @@ -79,7 +80,7 @@ const parseTools = { if (!lrc) return { lyric: '', lxlyric: '' } const lines = lrc.split('\n') - const lrcLines = [] + const lrcLines: string[] = [] for (let line of lines) { line = line.trim() @@ -112,8 +113,8 @@ const parseTools = { // console.log(rlrc) const rlrcLines = rlrc.split('\n') let lrcLines = lrc.split('\n') - // let temp = [] - let newLrc = [] + // let temp: string[] = [] + let newLrc: string[] = [] rlrcLines.forEach((line) => { const result = this.rxps.lineTime2.exec(line) if (!result) return @@ -142,8 +143,8 @@ const parseTools = { // console.log(tlrc) const tlrcLines = tlrc.split('\n') let lrcLines = lrc.split('\n') - // let temp = [] - let newLrc = [] + // let temp: string[] = [] + let newLrc: string[] = [] tlrcLines.forEach((line) => { const result = this.rxps.lineTime2.exec(line) if (!result) return @@ -203,8 +204,9 @@ export default { if (songIdMap.has(songmid)) return songIdMap.get(songmid) if (promises.has(songmid)) return (await promises.get(songmid)).songId const promise = getMusicInfo(songmid) - promises.set(promise) + promises.set(songmid, promise) const info = await promise + if (!info) throw new Error('获取歌曲信息失败') songIdMap.set(songmid, info.songId) promises.delete(songmid) return info.songId diff --git a/musicSdk/tx/musicInfo.js b/musicSdk/tx/musicInfo.ts similarity index 88% rename from musicSdk/tx/musicInfo.js rename to musicSdk/tx/musicInfo.ts index e2a28ee..0664664 100644 --- a/musicSdk/tx/musicInfo.js +++ b/musicSdk/tx/musicInfo.ts @@ -1,8 +1,9 @@ -import { httpFetch } from '../request.js' -import { formatPlayTime, sizeFormate } from '../index.js' +import type { HttpRequestObject, SongType, Quality, QualityInfo } from '../types.ts' +import { httpFetch } from '../request.ts' +import { formatPlayTime, sizeFormate } from '../index.ts' const getSinger = (singers) => { - let arr = [] + let arr: string[] = [] singers.forEach(singer => { arr.push(singer.name) }) @@ -37,8 +38,8 @@ export default (songmid) => { const item = body.req.data.track_info if (!item.file?.media_mid) return null - let types = [] - let _types = {} + let types: SongType[] = [] + let _types: Partial> = {} const file = item.file if (file.size_128mp3 != 0) { let size = sizeFormate(file.size_128mp3) diff --git a/musicSdk/tx/musicSearch.js b/musicSdk/tx/musicSearch.ts similarity index 92% rename from musicSdk/tx/musicSearch.js rename to musicSdk/tx/musicSearch.ts index 5c49e82..3fd7943 100644 --- a/musicSdk/tx/musicSearch.js +++ b/musicSdk/tx/musicSearch.ts @@ -1,6 +1,7 @@ -import { formatPlayTime, sizeFormate } from '../index.js' -import { formatSingerName } from '../utils.js' -import { signRequest } from './utils/index.js' +import { formatPlayTime, sizeFormate } from '../index.ts' +import { formatSingerName } from '../utils.ts' +import { signRequest } from './utils/index.ts' +import type { SongInfo, SongType, Quality, QualityInfo } from '../types.ts' export default { limit: 50, @@ -81,12 +82,12 @@ export default { handleResult(rawList) { // console.log(rawList) if (!rawList || !Array.isArray(rawList)) return [] - const list = [] + const list: SongInfo[] = [] rawList.forEach(item => { if (!item.file?.media_mid) return - let types = [] - let _types = {} + let types: SongType[] = [] + let _types: Partial> = {} const file = item.file if (file.size_128mp3 != 0) { let size = sizeFormate(file.size_128mp3) diff --git a/musicSdk/tx/singer.js b/musicSdk/tx/singer.ts similarity index 93% rename from musicSdk/tx/singer.js rename to musicSdk/tx/singer.ts index 7ddbc44..39b326c 100644 --- a/musicSdk/tx/singer.js +++ b/musicSdk/tx/singer.ts @@ -1,11 +1,12 @@ -import { httpFetch } from '../request.js' +import type { HttpRequestObject, SongType, Quality, QualityInfo } from '../types.ts' +import { httpFetch } from '../request.ts' -import { formatPlayTime, sizeFormate } from '../index.js' -import { formatSingerName } from '../utils.js' +import { formatPlayTime, sizeFormate } from '../index.ts' +import { formatSingerName } from '../utils.ts' export const filterMusicInfoItem = item => { - const types = [] - const _types = {} + const types: SongType[] = [] + const _types: Partial> = {} if (item.file.size_128mp3 != 0) { let size = sizeFormate(item.file.size_128mp3) types.push({ type: '128k', size }) @@ -65,7 +66,7 @@ export const filterMusicInfoItem = item => { * @param {*} options * @param {*} retryNum */ -const createMusicuFetch = async(data, options, retryNum = 0) => { +const createMusicuFetch = async(data, options?, retryNum = 0) => { if (retryNum > 2) throw new Error('try max num') let result diff --git a/musicSdk/tx/songList.js b/musicSdk/tx/songList.ts similarity index 93% rename from musicSdk/tx/songList.js rename to musicSdk/tx/songList.ts index 3c983c5..6a07aa9 100644 --- a/musicSdk/tx/songList.js +++ b/musicSdk/tx/songList.ts @@ -1,11 +1,12 @@ -import { httpFetch } from '../request.js' -import { decodeName, formatPlayTime, sizeFormate, dateFormat, formatPlayCount } from '../index.js' -import { formatSingerName } from '../utils.js' +import type { HttpRequestObject, SongType, Quality, QualityInfo } from '../types.ts' +import { httpFetch } from '../request.ts' +import { decodeName, formatPlayTime, sizeFormate, dateFormat, formatPlayCount } from '../index.ts' +import { formatSingerName } from '../utils.ts' export default { - _requestObj_tags: null, - _requestObj_hotTags: null, - _requestObj_list: null, + _requestObj_tags: null as HttpRequestObject | null, + _requestObj_hotTags: null as HttpRequestObject | null, + _requestObj_list: null as HttpRequestObject | null, limit_list: 36, limit_song: 100000, successCode: 0, @@ -68,7 +69,7 @@ export default { if (this._requestObj_tags) this._requestObj_tags.cancelHttp() if (tryNum > 2) return Promise.reject(new Error('try max num')) this._requestObj_tags = httpFetch(this.tagsUrl) - return this._requestObj_tags.promise.then(({ body }) => { + return this._requestObj_tags!.promise.then(({ body }) => { if (body.code !== this.successCode) return this.getTag(++tryNum) return this.filterTagInfo(body.tags.data.v_group) }) @@ -78,14 +79,14 @@ export default { if (this._requestObj_hotTags) this._requestObj_hotTags.cancelHttp() if (tryNum > 2) return Promise.reject(new Error('try max num')) this._requestObj_hotTags = httpFetch(this.hotTagUrl) - return this._requestObj_hotTags.promise.then(({ statusCode, body }) => { + return this._requestObj_hotTags!.promise.then(({ statusCode, body }) => { if (statusCode !== 200) return this.getHotTag(++tryNum) return this.filterInfoHotTag(body) }) }, filterInfoHotTag(html) { let hotTag = html.match(this.regExps.hotTagHtml) - const hotTags = [] + const hotTags: any[] = [] if (!hotTag) return hotTags hotTag.forEach(tagHtml => { @@ -120,7 +121,7 @@ export default { this.getListUrl(sortId, tagId, page), ) // console.log(this.getListUrl(sortId, tagId, page)) - return this._requestObj_list.promise.then(({ body }) => { + 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) }) @@ -226,8 +227,8 @@ export default { filterListDetail(rawList) { // console.log(rawList) return rawList.map(item => { - let types = [] - let _types = {} + let types: SongType[] = [] + let _types: Partial> = {} if (item.file.size_128mp3 !== 0) { let size = sizeFormate(item.file.size_128mp3) types.push({ type: '128k', size }) diff --git a/musicSdk/tx/tipSearch.js b/musicSdk/tx/tipSearch.ts similarity index 87% rename from musicSdk/tx/tipSearch.js rename to musicSdk/tx/tipSearch.ts index ec21628..00abcac 100644 --- a/musicSdk/tx/tipSearch.js +++ b/musicSdk/tx/tipSearch.ts @@ -1,10 +1,11 @@ -import { httpFetch } from '../request.js' +import type { HttpRequestObject } from '../types.ts' +import { httpFetch } from '../request.ts' export default { // regExps: { // relWord: /RELWORD=(.+)/, // }, - requestObj: null, + requestObj: null as HttpRequestObject | null, tipSearch(str) { this.cancelTipSearch() this.requestObj = httpFetch(`https://c.y.qq.com/splcloud/fcgi-bin/smartbox_new.fcg?is_xml=0&format=json&key=${encodeURIComponent(str)}&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0`, { diff --git a/musicSdk/tx/utils/crypto.js b/musicSdk/tx/utils/crypto.ts similarity index 100% rename from musicSdk/tx/utils/crypto.js rename to musicSdk/tx/utils/crypto.ts diff --git a/musicSdk/tx/utils/index.js b/musicSdk/tx/utils/index.ts similarity index 71% rename from musicSdk/tx/utils/index.js rename to musicSdk/tx/utils/index.ts index 1d89814..963a2da 100644 --- a/musicSdk/tx/utils/index.js +++ b/musicSdk/tx/utils/index.ts @@ -1,6 +1,7 @@ +import type { HttpRequestObject } from '../../types.ts' -import { httpFetch } from '../../request.js' -import { zzcSign } from './crypto.js' +import { httpFetch } from '../../request.ts' +import { zzcSign } from './crypto.ts' export const signRequest = async(data) => { // console.log(data) diff --git a/musicSdk/types.ts b/musicSdk/types.ts new file mode 100644 index 0000000..10ff0a1 --- /dev/null +++ b/musicSdk/types.ts @@ -0,0 +1,146 @@ +// SDK 共享类型定义 +// 所有平台模块与根模块的类型锚点。类型只描述实际返回的数据形状,不改变运行时行为。 + +/** 音乐平台标识 */ +export type Source = 'kw' | 'kg' | 'tx' | 'wy' | 'mg' | 'bd' | 'xm' + +/** 音质标识(wav 仅部分接口声明使用) */ +export type Quality = '128k' | '320k' | 'flac' | 'flac24bit' | 'wav' + +/** 单音质资源描述(搜索结果 types 数组项) */ +export interface SongType { + type: Quality + size: string +} + +/** 单音质详情(搜索结果 _types 映射项) */ +export interface QualityInfo { + size: string +} + +/** 歌曲信息(搜索结果项 / 取流入参) */ +export interface SongInfo { + songmid?: string + hash?: string + copyrightId?: string + songStringId?: string + albumId?: string + name?: string | null + singer?: string + source?: Source + interval?: string | number + albumName?: string + img?: string | null + lrc?: string | null + otherSource?: string | null + types?: SongType[] + _types?: Partial> + typeUrl?: Partial> + [key: string]: unknown +} + +/** httpFetch 响应(与 src/common/request.js 契约一致) */ +export interface HttpResponse { + statusCode: number + statusMessage?: string + headers: Record + body: any + raw?: Buffer +} + +/** httpFetch 返回的可取消请求对象 */ +export interface HttpRequestObject { + promise: Promise + cancelHttp(): void +} + +/** httpFetch 选项(src/common/request.js 子集) */ +export interface HttpOptions { + method?: string + headers?: Record + body?: string | object + form?: Record + timeout?: number + lookup?: unknown + family?: number +} + +/** 带取消句柄的异步结果(getMusicUrl/getLyric 等的统一返回形态) */ +export interface RequestObj { + promise: Promise + cancelHttp(): void +} + +/** 取流结果 */ +export interface MusicUrlResult { + type: string + url: string +} + +/** 歌词结果 */ +export interface LyricInfo { + lyric: string + tlyric: string + rlyric?: string + lxlyric?: string +} + +/** 搜索结果 */ +export interface SearchResult { + list: SongInfo[] + allPage: number + total: number + limit: number + source: Source +} + +/** 搜索模块(平台 musicSearch 子模块) */ +export interface MusicSearchModule { + search(str: string, page?: number, limit?: number, retryNum?: number): Promise + [key: string]: unknown +} + +/** 歌词模块 */ +export interface LyricModule { + getLyric(songInfo: SongInfo, ...rest: unknown[]): Promise | RequestObj + [key: string]: unknown +} + +/** 封面模块 */ +export interface PicModule { + getPic(songInfo: SongInfo, ...rest: unknown[]): Promise | RequestObj + [key: string]: unknown +} + +/** 热搜模块 */ +export interface HotSearchModule { + getList(): Promise + [key: string]: unknown +} + +/** 评论模块 */ +export interface CommentModule { + getComment(songInfo: any, page?: number, limit?: number): Promise + getHotComment(songInfo: any, page?: number, limit?: number): Promise + [key: string]: unknown +} + +/** 平台模块(各平台默认导出需满足的最小形状) + * 注:SDK 内部实现大量返回 httpFetch 原生的 HttpRequestObject, + * 实际 promise 会在 .then() 中被改写为对应结果类型;此处只约束调用侧可见形态。 + */ +export interface PlatformModule { + init?(): Promise | void + musicSearch?: MusicSearchModule + leaderboard?: any + songList?: any + hotSearch?: HotSearchModule + comment?: CommentModule + tipSearch?: any + getMusicUrl?(songInfo: SongInfo, type: Quality): HttpRequestObject + getLyric?(songInfo: SongInfo, ...rest: unknown[]): HttpRequestObject + getPic?(songInfo: SongInfo, ...rest: unknown[]): HttpRequestObject | Promise + getMusicInfo?(songInfo: SongInfo): HttpRequestObject | Promise + getMusicDetailPageUrl?(songInfo: SongInfo): string + [key: string]: any +} diff --git a/musicSdk/utils.js b/musicSdk/utils.ts similarity index 50% rename from musicSdk/utils.js rename to musicSdk/utils.ts index 1d23179..31cc0d3 100644 --- a/musicSdk/utils.js +++ b/musicSdk/utils.ts @@ -2,47 +2,57 @@ import crypto from 'crypto' import dns from 'dns' import { decodeName } from '../src/common/utils.js' -export const toMD5 = str => crypto.createHash('md5').update(str).digest('hex') +export const toMD5 = (str: string): string => crypto.createHash('md5').update(str).digest('hex') +interface CachedIp { + address: string + family: number +} -const ipMap = new Map() -export const getHostIp = hostname => { +const ipMap = new Map() + +export const getHostIp = (hostname: string): CachedIp | undefined => { const result = ipMap.get(hostname) if (typeof result === 'object') return result if (result === true) return ipMap.set(hostname, true) - // console.log(hostname) dns.lookup(hostname, { // family: 4, all: false, }, (err, address, family) => { if (err) return console.log(err) - // console.log(address, family) ipMap.set(hostname, { address, family }) }) } -export const dnsLookup = (hostname, options, callback) => { +export const dnsLookup = ( + hostname: string, + options: dns.LookupOptions, + callback: (err: NodeJS.ErrnoException | null, address: string, family: number) => void, +): void => { const result = getHostIp(hostname) if (result) return callback(null, result.address, result.family) - dns.lookup(hostname, options, callback) + dns.lookup(hostname, options, callback as any) } - /** * 格式化歌手 - * @param singers 歌手数组 + * @param singers 歌手数组或字符串 * @param nameKey 歌手名键值 * @param join 歌手分割字符 */ -export const formatSingerName = (singers, nameKey = 'name', join = '、') => { +export const formatSingerName = ( + singers: Array> | string | null | undefined, + nameKey = 'name', + join = '、', +): string => { if (Array.isArray(singers)) { - const singer = [] + const singer: string[] = [] singers.forEach(item => { - let name = item[nameKey] + const name = item[nameKey] if (!name) return - singer.push(name) + singer.push(String(name)) }) return decodeName(singer.join(join)) } diff --git a/musicSdk/wy/comment.js b/musicSdk/wy/comment.ts similarity index 92% rename from musicSdk/wy/comment.js rename to musicSdk/wy/comment.ts index ecbabd5..b63b7e9 100644 --- a/musicSdk/wy/comment.js +++ b/musicSdk/wy/comment.ts @@ -1,6 +1,7 @@ -import { httpFetch } from '../request.js' -import { weapi } from './utils/crypto.js' -import { dateFormat2 } from '../index.js' +import { httpFetch } from '../request.ts' +import { weapi } from './utils/crypto.ts' +import { dateFormat2 } from '../index.ts' +import type { HttpRequestObject } from '../types.ts' const emojis = [ ['大笑', '😃'], @@ -65,13 +66,19 @@ const emojis = [ ['叉', '❌'], ] -const applyEmoji = text => { +const applyEmoji = (text: string): string => { for (const e of emojis) text = text.replaceAll(`[${e[0]}]`, e[1]) return text } let cursorTools = { - cache: {}, + cache: {} as Record, getCursor(id, page, limit) { let cacheData = this.cache[id] if (!cacheData) cacheData = this.cache[id] = {} @@ -115,8 +122,8 @@ let cursorTools = { } export default { - _requestObj: null, - _requestObj2: null, + _requestObj: null as HttpRequestObject | null, + _requestObj2: null as HttpRequestObject | null, async getComment({ songmid }, page = 1, limit = 20) { if (this._requestObj) this._requestObj.cancelHttp() diff --git a/musicSdk/wy/hotSearch.js b/musicSdk/wy/hotSearch.ts similarity index 79% rename from musicSdk/wy/hotSearch.js rename to musicSdk/wy/hotSearch.ts index 6507ac4..6c39ebc 100644 --- a/musicSdk/wy/hotSearch.js +++ b/musicSdk/wy/hotSearch.ts @@ -1,7 +1,8 @@ -import { eapiRequest } from './utils/index.js' +import { eapiRequest } from './utils/index.ts' +import type { HttpRequestObject } from '../types.ts' export default { - _requestObj: null, + _requestObj: null as HttpRequestObject | null, async getList(retryNum = 0) { if (this._requestObj) this._requestObj.cancelHttp() if (retryNum > 2) return Promise.reject(new Error('try max num')) diff --git a/musicSdk/wy/index.js b/musicSdk/wy/index.ts similarity index 58% rename from musicSdk/wy/index.js rename to musicSdk/wy/index.ts index 27a3580..3222883 100644 --- a/musicSdk/wy/index.js +++ b/musicSdk/wy/index.ts @@ -1,11 +1,11 @@ -import leaderboard from './leaderboard.js' -import { apis } from '../api-source.js' -import getLyric from './lyric.js' -import getMusicInfo from './musicInfo.js' -import musicSearch from './musicSearch.js' -import songList from './songList.js' -import hotSearch from './hotSearch.js' -import comment from './comment.js' +import leaderboard from './leaderboard.ts' +import { apis } from '../api-source.ts' +import getLyric from './lyric.ts' +import getMusicInfo from './musicInfo.ts' +import musicSearch from './musicSearch.ts' +import songList from './songList.ts' +import hotSearch from './hotSearch.ts' +import comment from './comment.ts' // import tipSearch from './tipSearch.js' const wy = { @@ -16,7 +16,7 @@ const wy = { hotSearch, comment, getMusicUrl(songInfo, type) { - return apis('wy').getMusicUrl(songInfo, type) + return apis('wy').getMusicUrl!(songInfo, type) }, getLyric(songInfo) { return getLyric(songInfo.songmid) diff --git a/musicSdk/wy/leaderboard.js b/musicSdk/wy/leaderboard.ts similarity index 93% rename from musicSdk/wy/leaderboard.js rename to musicSdk/wy/leaderboard.ts index 7f356f3..f04cb26 100644 --- a/musicSdk/wy/leaderboard.js +++ b/musicSdk/wy/leaderboard.ts @@ -1,6 +1,7 @@ -import { weapi } from './utils/crypto.js' -import { httpFetch } from '../request.js' -import musicDetailApi from './musicDetail.js' +import { weapi } from './utils/crypto.ts' +import { httpFetch } from '../request.ts' +import musicDetailApi from './musicDetail.ts' +import type { HttpRequestObject } from '../types.ts' const topList = [{ id: 'wy__19723756', name: '飙升榜', bangid: '19723756' }, { id: 'wy__3779629', name: '新歌榜', bangid: '3779629' }, @@ -106,14 +107,14 @@ export default { regExps: { list: /