refactor(sdk): musicSdk 全量迁移至 TypeScript

This commit is contained in:
snowy-yang committed 2026-08-29 00:23:50 +08:00
1 parent f289df4cd7
commit 1dfb7a59ca
83 files changed
+924 -732

No files matched your search

@@ -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<string, {
page?: number
prevCursor?: number
cursor?: number
orderType?: number
offset?: number
}>,
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()
@@ -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'))
@@ -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)
@@ -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: /<textarea id="song-list-pre-data" style="display:none;">(.+?)<\/textarea>/,
},
_requestBoardsObj: null,
_requestBoardsObj: null as HttpRequestObject | null,
getBoardsData() {
if (this._requestBoardsObj) this._requestBoardsObj.cancelHttp()
this._requestBoardsObj = httpFetch('https://music.163.com/weapi/toplist', {
method: 'post',
form: weapi({}),
})
return this._requestBoardsObj.promise
return this._requestBoardsObj!.promise
},
getData(id) {
const requestBoardsDetailObj = httpFetch('https://music.163.com/weapi/v3/playlist/detail', {
@@ -129,7 +130,7 @@ export default {
filterBoardsData(rawList) {
// console.log(rawList)
let list = []
let list: any[] = []
for (const board of rawList) {
// 排除 MV榜
// if (board.id == 201) continue
@@ -171,7 +172,7 @@ export default {
let resp
try {
resp = await this.getData(bangid)
} catch (err) {
} catch (err: any) {
if (err.message == 'try max num') {
throw err
} else {
@@ -182,8 +183,8 @@ export default {
// console.log(resp.body)
let musicDetail
try {
musicDetail = await musicDetailApi.getList(resp.body.playlist.trackIds.map(trackId => trackId.id))
} catch (err) {
musicDetail = await (musicDetailApi as any).getList(resp.body.playlist.trackIds.map(trackId => trackId.id))
} catch (err: any) {
console.log(err)
if (err.message == 'try max num') {
throw err
+15 -14
View File
@@ -1,5 +1,6 @@
import { httpFetch } from '../request.js'
import { eapi } from './utils/crypto.js'
import { httpFetch } from '../request.ts'
import { eapi } from './utils/crypto.ts'
import type { LyricInfo, HttpRequestObject } from '../types.ts'
// import { decodeName } from '../...js'
// const parseLyric = (str, lrc) => {
@@ -34,7 +35,7 @@ import { eapi } from './utils/crypto.js'
// return lxlyric.trim()
// }
const eapiRequest = (url, data) => {
const eapiRequest = (url: string, data: object) => {
return httpFetch('https://interface3.music.163.com/eapi/song/lyric/v1', {
method: 'post',
headers: {
@@ -65,14 +66,14 @@ const parseTools = {
if (Number.isNaN(timeMs)) return ''
let ms = timeMs % 1000
timeMs /= 1000
let m = parseInt(timeMs / 60).toString().padStart(2, '0')
let m = parseInt((timeMs / 60) as any).toString().padStart(2, '0')
timeMs %= 60
let s = parseInt(timeMs).toString().padStart(2, '0')
let s = parseInt(timeMs as any).toString().padStart(2, '0')
return `[${m}:${s}.${ms}]`
},
parseLyric(lines) {
const lxlrcLines = []
const lrcLines = []
const lxlrcLines: string[] = []
const lrcLines: string[] = []
for (let line of lines) {
line = line.trim()
@@ -97,7 +98,7 @@ const parseTools = {
if (!times) continue
times = times.map(time => {
const result = /\((\d+),(\d+),\d+\)/.exec(time)
return `<${Math.max(parseInt(result[1]) - startMsTime, 0)},${result[2]}>`
return `<${Math.max(parseInt(result![1]) - startMsTime, 0)},${result![2]}>`
})
const wordArr = words.split(this.rxps.wordTime)
wordArr.shift()
@@ -137,8 +138,8 @@ const parseTools = {
let lrcLines = lrc.split('\n')
const targetlrcLines = targetlrc.split('\n')
const timeRxp = /^\[([\d:.]+)\]/
let temp = []
let newLrc = []
let temp: string[] = []
let newLrc: string[] = []
targetlrcLines.forEach((line) => {
const result = timeRxp.exec(line)
if (!result) return
@@ -147,7 +148,7 @@ const parseTools = {
const t1 = this.getIntv(result[1])
while (lrcLines.length) {
const lrcLine = lrcLines.shift()
const lrcLine = lrcLines.shift()!
const lrcLineResult = timeRxp.exec(lrcLine)
if (!lrcLineResult) continue
const t2 = this.getIntv(lrcLineResult[1])
@@ -248,7 +249,7 @@ const parseTools = {
// }
// https://github.com/lyswhut/lx-music-mobile/issues/370
const fixTimeLabel = (lrc, tlrc, romalrc) => {
const fixTimeLabel = (lrc: string, tlrc?: string, romalrc?: string) => {
if (lrc) {
let newLrc = lrc.replace(/\[(\d{2}:\d{2}):(\d{2})]/g, '[$1.$2]')
let newTlrc = tlrc?.replace(/\[(\d{2}:\d{2}):(\d{2})]/g, '[$1.$2]') ?? tlrc
@@ -263,7 +264,7 @@ const fixTimeLabel = (lrc, tlrc, romalrc) => {
}
// https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/lyric_new.js
export default songmid => {
export default (songmid: string): HttpRequestObject => {
const requestObj = eapiRequest('/api/song/lyric/v1', {
id: songmid,
cp: false,
@@ -283,6 +284,6 @@ export default songmid => {
// console.log(info)
if (!info.lyric) return Promise.reject(new Error('Get lyric failed'))
return info
})
}) as any
return requestObj
}
@@ -1,11 +1,11 @@
import { httpFetch } from '../request.js'
import { weapi } from './utils/crypto.js'
import { formatPlayTime, sizeFormate } from '../index.js'
import { httpFetch } from '../request.ts'
import { weapi } from './utils/crypto.ts'
import { formatPlayTime, sizeFormate } from '../index.ts'
// https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/song_detail.js
export default {
getSinger(singers) {
let arr = []
let arr: any[] = []
singers?.forEach(singer => {
arr.push(singer.name)
})
@@ -13,10 +13,10 @@ export default {
},
filterList({ songs, privileges }) {
// console.log(songs, privileges)
const list = []
const list: any[] = []
songs.forEach((item, index) => {
const types = []
const _types = {}
const types: Array<{ type: string, size: string | null }> = []
const _types: Record<string, { size: string | null }> = {}
let size
let privilege = privileges[index]
if (privilege.id !== item.id) privilege = privileges.find(p => p.id === item.id)
@@ -1,8 +1,9 @@
// https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/song_detail.js
import { httpFetch } from '../request.js'
import { weapi } from './utils/crypto.js'
import { httpFetch } from '../request.ts'
import { weapi } from './utils/crypto.ts'
import type { RequestObj } from '../types.ts'
export default songmid => {
export default (songmid: string): RequestObj<any> => {
const requestObj = httpFetch('https://music.163.com/weapi/v3/song/detail', {
method: 'post',
headers: {
@@ -22,4 +23,3 @@ export default songmid => {
})
return requestObj
}
@@ -1,8 +1,8 @@
// import { httpFetch } from '../request.js'
// import { weapi } from './utils/crypto.js'
import { sizeFormate, formatPlayTime } from '../index.js'
import { sizeFormate, formatPlayTime } from '../index.ts'
// import musicDetailApi from './musicDetail.js'
import { eapiRequest } from './utils/index.js'
import { eapiRequest } from './utils/index.ts'
export default {
limit: 30,
@@ -29,7 +29,7 @@ export default {
return searchRequest.promise.then(({ body }) => body)
},
getSinger(singers) {
let arr = []
let arr: any[] = []
singers.forEach(singer => {
arr.push(singer.name)
})
@@ -40,8 +40,8 @@ export default {
if (!rawList) return []
return rawList.map(item => {
item = item.baseInfo.simpleSongData
const types = []
const _types = {}
const types: Array<{ type: string, size: string | null }> = []
const _types: Record<string, { size: string | null }> = {}
let size
if (item.privilege.maxBrLevel == 'hires') {
+12 -12
View File
@@ -1,6 +1,6 @@
import { eapiRequest } from './utils/index.js'
import { formatPlayTime, sizeFormate } from '../index.js'
import { formatSingerName } from '../utils.js'
import { eapiRequest } from './utils/index.ts'
import { formatPlayTime, sizeFormate } from '../index.ts'
import { formatSingerName } from '../utils.ts'
export default {
/**
@@ -8,7 +8,7 @@ export default {
* @param {*} id
*/
getInfo(id) {
return eapiRequest('/api/artist/head/info/get', { id }).then(({ body }) => {
return (eapiRequest('/api/artist/head/info/get', { id }) as any).then(({ body }) => {
if (!body || body.code != 200) throw new Error('get singer info faild.')
return {
source: 'wy',
@@ -34,11 +34,11 @@ export default {
*/
getSongList(id, page = 1, limit = 100) {
if (page === 1) page = 0
return eapiRequest('/api/v2/artist/songs', {
return (eapiRequest('/api/v2/artist/songs', {
id,
limit,
offset: limit * page,
}).then(({ body }) => {
}) as any).then(({ body }) => {
if (!body.songs || body.code != 200) throw new Error('get singer song list faild.')
const list = this.filterSongList(body.songs)
@@ -59,10 +59,10 @@ export default {
*/
getAlbumList(id, page = 1, limit = 10) {
if (page === 1) page = 0
return eapiRequest(`/api/artist/albums/${id}`, {
return (eapiRequest(`/api/artist/albums/${id}`, {
limit,
offset: limit * page,
}).then(({ body }) => {
}) as any).then(({ body }) => {
if (!body.hotAlbums || body.code != 200) throw new Error('get singer album list faild.')
const list = this.filterAlbumList(body.hotAlbums)
@@ -76,7 +76,7 @@ export default {
})
},
filterAlbumList(raw) {
const list = []
const list: any[] = []
raw.forEach(item => {
if (!item.id) return
list.push({
@@ -93,12 +93,12 @@ export default {
return list
},
filterSongList(raw) {
const list = []
const list: any[] = []
raw.forEach(item => {
if (!item.id) return
const types = []
const _types = {}
const types: Array<{ type: string, size: string | null }> = []
const _types: Record<string, { size: string | null }> = {}
let size
item.privilege.chargeInfoList.forEach(i => {
switch (i.rate) {
@@ -3,17 +3,18 @@
// https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/top_playlist.js
// https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/playlist_detail.js
import { weapi, linuxapi } from './utils/crypto.js'
import { httpFetch } from '../request.js'
import { formatPlayTime, sizeFormate, dateFormat, formatPlayCount } from '../index.js'
import musicDetailApi from './musicDetail.js'
import { eapiRequest } from './utils/index.js'
import { formatSingerName } from '../utils.js'
import { weapi, linuxapi } from './utils/crypto.ts'
import { httpFetch } from '../request.ts'
import { formatPlayTime, sizeFormate, dateFormat, formatPlayCount } from '../index.ts'
import musicDetailApi from './musicDetail.ts'
import { eapiRequest } from './utils/index.ts'
import { formatSingerName } from '../utils.ts'
import type { HttpRequestObject } 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: 30,
limit_song: 100000,
successCode: 200,
@@ -97,8 +98,8 @@ export default {
list = this.filterListDetail(body)
} else {
try {
list = (await musicDetailApi.getList(body.playlist.trackIds.slice(rangeStart, limit * page).map(trackId => trackId.id))).list
} catch (err) {
list = (await (musicDetailApi as any).getList(body.playlist.trackIds.slice(rangeStart, limit * page).map(trackId => trackId.id))).list
} catch (err: any) {
console.log(err)
if (err.message == 'try max num') {
throw err
@@ -125,10 +126,10 @@ export default {
},
filterListDetail({ playlist: { tracks }, privileges }) {
// console.log(tracks, privileges)
const list = []
const list: any[] = []
tracks.forEach((item, index) => {
const types = []
const _types = {}
const types: Array<{ type: string, size: string | null }> = []
const _types: Record<string, { size: string | null }> = {}
let size
let privilege = privileges[index]
if (privilege.id !== item.id) privilege = privileges.find(p => p.id === item.id)
@@ -216,7 +217,7 @@ export default {
total: true,
}),
})
return this._requestObj_list.promise.then(({ body }) => {
return this._requestObj_list!.promise.then(({ body }) => {
// console.log(body)
if (body.code !== this.successCode) return this.getList(sortId, tagId, page, ++tryNum)
return {
@@ -252,7 +253,7 @@ export default {
method: 'post',
form: weapi({}),
})
return this._requestObj_tags.promise.then(({ body }) => {
return this._requestObj_tags!.promise.then(({ body }) => {
// console.log(JSON.stringify(body))
if (body.code !== this.successCode) return this.getTag(++tryNum)
return this.filterTagInfo(body)
@@ -271,7 +272,7 @@ export default {
})
}
const list = []
const list: any[] = []
for (const key of Object.keys(categories)) {
list.push({
name: categories[key],
@@ -290,7 +291,7 @@ export default {
method: 'post',
form: weapi({}),
})
return this._requestObj_hotTags.promise.then(({ body }) => {
return this._requestObj_hotTags!.promise.then(({ body }) => {
// console.log(JSON.stringify(body))
if (body.code !== this.successCode) return this.getTag(++tryNum)
return this.filterHotTagInfo(body.tags)
@@ -1,9 +1,10 @@
import { httpFetch } from '../request.js'
import { weapi } from './utils/crypto.js'
import { formatSingerName } from '../utils.js'
import { httpFetch } from '../request.ts'
import { weapi } from './utils/crypto.ts'
import { formatSingerName } from '../utils.ts'
import type { HttpRequestObject } from '../types.ts'
export default {
requestObj: null,
requestObj: null as HttpRequestObject | null,
cancelTipSearch() {
if (this.requestObj && this.requestObj.cancelHttp) this.requestObj.cancelHttp()
},
@@ -19,7 +20,7 @@ export default {
s: str,
}),
})
return this.requestObj.promise.then(({ statusCode, body }) => {
return this.requestObj!.promise.then(({ statusCode, body }) => {
if (statusCode != 200 || body.code != 200) return Promise.reject(new Error('请求失败'))
return body.result.songs
})
@@ -7,31 +7,31 @@ const base62 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
const publicKey = '-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgtQn2JZ34ZC28NWYpAUd98iZ37BUrX/aKzmFbt7clFSs6sXqHauqKWqdtLkF2KexO40H1YTX8z2lSgBBOAxLsvaklV8k4cBFK9snQXE9/DDaFt6Rr7iVZMldczhC0JNgTz+SHXT6CBHuX3e9SdB1Ua44oncaTWz7OBGLbCiK45wIDAQAB\n-----END PUBLIC KEY-----'
const eapiKey = 'e82ckenh8dichen8'
const aesEncrypt = (buffer, mode, key, iv) => {
const aesEncrypt = (buffer: Buffer, mode: string, key: Buffer | string, iv: Buffer | string): Buffer => {
const cipher = createCipheriv(mode, key, iv)
return Buffer.concat([cipher.update(buffer), cipher.final()])
}
const aesDecrypt = function(cipherBuffer, mode, key, iv) {
const aesDecrypt = function(cipherBuffer: Buffer, mode: string, key: Buffer | string, iv: Buffer | string): Buffer {
let decipher = createDecipheriv(mode, key, iv)
return Buffer.concat([decipher.update(cipherBuffer), decipher.final()])
}
const rsaEncrypt = (buffer, key) => {
const rsaEncrypt = (buffer: Buffer, key: string): Buffer => {
buffer = Buffer.concat([Buffer.alloc(128 - buffer.length), buffer])
return publicEncrypt({ key, padding: constants.RSA_NO_PADDING }, buffer)
}
export const weapi = object => {
export const weapi = (object: object): { params: string, encSecKey: string } => {
const text = JSON.stringify(object)
const secretKey = randomBytes(16).map(n => (base62.charAt(n % 62).charCodeAt()))
const secretKey = randomBytes(16).map(n => ((base62.charAt(n % 62) as any).charCodeAt())) as Buffer
return {
params: aesEncrypt(Buffer.from(aesEncrypt(Buffer.from(text), 'aes-128-cbc', presetKey, iv).toString('base64')), 'aes-128-cbc', secretKey, iv).toString('base64'),
encSecKey: rsaEncrypt(secretKey.reverse(), publicKey).toString('hex'),
}
}
export const linuxapi = object => {
export const linuxapi = (object: object): { eparams: string } => {
const text = JSON.stringify(object)
return {
eparams: aesEncrypt(Buffer.from(text), 'aes-128-ecb', linuxapiKey, '').toString('hex').toUpperCase(),
@@ -39,7 +39,7 @@ export const linuxapi = object => {
}
export const eapi = (url, object) => {
export const eapi = (url: string, object: object | string): { params: string } => {
const text = typeof object === 'object' ? JSON.stringify(object) : object
const message = `nobody${url}use${text}md5forencrypt`
const digest = createHash('md5').update(message).digest('hex')
@@ -49,6 +49,6 @@ export const eapi = (url, object) => {
}
}
export const eapiDecrypt = cipherBuffer => {
export const eapiDecrypt = (cipherBuffer: Buffer): string => {
return aesDecrypt(cipherBuffer, 'aes-128-ecb', eapiKey, '').toString()
}
@@ -1,7 +1,8 @@
import { httpFetch } from '../../request.js'
import { eapi } from './crypto.js'
import { httpFetch } from '../../request.ts'
import { eapi } from './crypto.ts'
import type { HttpRequestObject } from '../../types.ts'
export const eapiRequest = (url, data) => {
export const eapiRequest = (url: string, data: object): HttpRequestObject => {
return httpFetch('http://interface.music.163.com/eapi/batch', {
method: 'post',
headers: {