import { httpFetch } from '../request.ts' import { decodeLyric, lrcTools } from './util.ts' import { decodeName } from '../index.ts' /* export default { formatTime(time) { let m = parseInt(time / 60) let s = (time % 60).toFixed(2) return (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s) }, sortLrcArr(arr) { const lrcSet = new Set() let lrc = [] let lrcT = [] for (const item of arr) { if (lrcSet.has(item.time)) { const tItem = lrc.pop() tItem.time = lrc[lrc.length - 1].time lrcT.push(tItem) lrc.push(item) } else { lrc.push(item) lrcSet.add(item.time) } } if (lrcT.length && lrc.length > lrcT.length) { const tItem = lrc.pop() tItem.time = lrc[lrc.length - 1].time lrcT.push(tItem) } return { lrc, lrcT, } }, transformLrc(songinfo, lrclist) { return `[ti:${songinfo.songName}]\n[ar:${songinfo.artist}]\n[al:${songinfo.album}]\n[by:]\n[offset:0]\n${lrclist ? lrclist.map(l => `[${this.formatTime(l.time)}]${l.lineLyric}\n`).join('') : '暂无歌词'}` }, getLyric(songId) { const requestObj = httpFetch(`http://m.kuwo.cn/newh5/singles/songinfoandlrc?musicId=${songId}`) requestObj.promise = requestObj.promise.then(({ body }) => { // console.log(body) if (!body.data?.lrclist?.length) return Promise.reject(new Error('Get lyric failed')) let lrcInfo try { lrcInfo = this.sortLrcArr(body.data.lrclist) } catch { return Promise.reject(new Error('Get lyric failed')) } // console.log(body.data.lrclist) // console.log(lrcInfo.lrc, lrcInfo.lrcT) // console.log({ // lyric: decodeName(this.transformLrc(body.data.songinfo, lrc)), // tlyric: decodeName(this.transformLrc(body.data.songinfo, lrcT)), // }) return { lyric: decodeName(this.transformLrc(body.data.songinfo, lrcInfo.lrc)), tlyric: lrcInfo.lrcT.length ? decodeName(this.transformLrc(body.data.songinfo, lrcInfo.lrcT)) : '', } }) return requestObj }, } */ const buf_key = Buffer.from('yeelion') const buf_key_len = buf_key.length 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) const buf_str_len = buf_str.length const output = new Uint16Array(buf_str_len) let i = 0 while (i < buf_str_len) { let j = 0 while (j < buf_key_len && i < buf_str_len) { output[i] = buf_key[j] ^ buf_str[i] i++ j++ } } return Buffer.from(output).toString('base64') } // console.log(buildParams('207527604', false)) // console.log(buildParams('207527604', true)) const timeExp = /^\[([\d:.]*)\]{1}/g const existTimeExp = /\[\d{1,2}:.*\d{1,4}\]/ const lyricxTag = /^<-?\d+,-?\d+>/ export default { /* sortLrcArr(arr) { const lrcSet = new Set() let lrc = [] let lrcT = [] let markIndex = [] for (const item of arr) { if (lrcSet.has(item.time)) { if (lrc.length < 2) continue const index = lrc.findIndex(l => l.time == item.time) markIndex.push(index) if (index == lrc.length - 1) { lrcT.push({ ...lrc[index], time: item.time }) lrc.push(item) } else { lrcT.push({ ...lrc[index], time: lrc[index + 1].time }) if (item.text) { // const lastIndex = lrc.length - 1 // markIndex.push(lastIndex) // lrcT.push({ ...lrc[lastIndex], time: lrc[lastIndex - 1].time }) lrc.push(item) } } } else { lrc.push(item) lrcSet.add(item.time) } } // console.log(markIndex) markIndex = Array.from(new Set(markIndex)) for (let index = markIndex.length - 1; index >= 0; index--) { lrc.splice(markIndex[index], 1) } // if (lrcT.length) { // if (lrc.length * 0.4 < lrcT.length) { // 翻译数量需大于歌词数量的0.4倍,否则认为没有翻译 // const tItem = lrc.pop() // tItem.time = lrc[lrc.length - 1].time // lrcT.push(tItem) // } else { // lrc = arr // lrcT = [] // } // } console.log(lrc, lrcT) return { lrc, lrcT, } }, */ sortLrcArr(arr) { const lrcSet = new Set() let lrc: any[] = [] let lrcT: any[] = [] let isLyricx = false for (const item of arr) { if (lrcSet.has(item.time)) { if (lrc.length < 2) continue const tItem = lrc.pop() tItem.time = lrc[lrc.length - 1].time lrcT.push(tItem) lrc.push(item) } else { lrc.push(item) lrcSet.add(item.time) } if (!isLyricx && lyricxTag.test(item.text)) isLyricx = true } if (!isLyricx && lrcT.length > lrc.length * 0.3 && lrc.length - lrcT.length > 6) { throw new Error('failed') // if (lrc.length * 0.4 < lrcT.length) { // 翻译数量需大于歌词数量的0.4倍,否则认为没有翻译 // const tItem = lrc.pop() // tItem.time = lrc[lrc.length - 1].time // lrcT.push(tItem) // } else { // lrc = arr // lrcT = [] // } } return { lrc, lrcT, } }, transformLrc(tags, lrclist) { return `${tags.join('\n')}\n${lrclist ? lrclist.map(l => `[${l.time}]${l.text}\n`).join('') : '暂无歌词'}` }, parseLrc(lrc: string) { const lines = lrc.split(/\r\n|\r|\n/) 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) if (result) { const text = line.replace(timeExp, '').trim() let time = RegExp.$1 if (/\.\d\d$/.test(time)) time += '0' lrcArr.push({ time, text, }) } else if (lrcTools.rxps.tagLine.test(line)) { tags.push(line) } } const lrcInfo = this.sortLrcArr(lrcArr) return { lyric: decodeName(this.transformLrc(tags, lrcInfo.lrc)), tlyric: lrcInfo.lrcT.length ? decodeName(this.transformLrc(tags, lrcInfo.lrcT)) : '', } }, // getLyric2(musicInfo, isGetLyricx = true) { // const requestObj = httpFetch(`http://newlyric.kuwo.cn/newlyric.lrc?${buildParams(musicInfo.songmid, isGetLyricx)}`) // requestObj.promise = requestObj.promise.then(({ statusCode, body, raw }) => { // if (statusCode != 200) return Promise.reject(new Error(JSON.stringify(body))) // return decodeLyric({ lrcBase64: raw.toString('base64'), isGetLyricx }).then(base64Data => { // let lrcInfo // console.log(Buffer.from(base64Data, 'base64').toString()) // try { // lrcInfo = this.parseLrc(Buffer.from(base64Data, 'base64').toString()) // } catch { // return Promise.reject(new Error('Get lyric failed')) // } // if (lrcInfo.tlyric) lrcInfo.tlyric = lrcInfo.tlyric.replace(lrcTools.rxps.wordTimeAll, '') // lrcInfo.lxlyric = lrcTools.parse(lrcInfo.lyric) // // console.log(lrcInfo.lyric) // // console.log(lrcInfo.tlyric) // // console.log(lrcInfo.lxlyric) // // console.log(JSON.stringify(lrcInfo)) // }) // }) // return requestObj // }, getLyric(musicInfo, isGetLyricx = true) { // this.getLyric2(musicInfo) const requestObj = httpFetch(`http://newlyric.kuwo.cn/newlyric.lrc?${buildParams(musicInfo.songmid, isGetLyricx)}`) requestObj.promise = requestObj.promise.then(({ statusCode, body, raw }) => { if (statusCode != 200) return Promise.reject(new Error(JSON.stringify(body))) return decodeLyric({ lrcBase64: raw!.toString('base64'), isGetLyricx }).then(base64Data => { // let lrcInfo // try { // lrcInfo = this.parseLrc(Buffer.from(base64Data, 'base64').toString()) // } catch { // return Promise.reject(new Error('Get lyric failed')) // } let lrcInfo // console.log(Buffer.from(base64Data, 'base64').toString()) try { lrcInfo = this.parseLrc(Buffer.from(base64Data, 'base64').toString()) } catch (err) { return Promise.reject(new Error('Get lyric failed')) } // console.log(lrcInfo) if (lrcInfo.tlyric) lrcInfo.tlyric = lrcInfo.tlyric.replace(lrcTools.rxps.wordTimeAll, '') try { lrcInfo.lxlyric = lrcTools.parse(lrcInfo.lyric) } catch { lrcInfo.lxlyric = '' } lrcInfo.lyric = lrcInfo.lyric.replace(lrcTools.rxps.wordTimeAll, '') if (!existTimeExp.test(lrcInfo.lyric)) return Promise.reject(new Error('Get lyric failed')) // console.log(lrcInfo) return lrcInfo }) }) return requestObj }, }