From 7e27ec488b8b66f19ca080e2f3d040afe9cc2cdc Mon Sep 17 00:00:00 2001 From: lyswhut Date: Tue, 31 Jan 2023 23:40:25 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0wy=E6=BA=90=E9=80=90=E5=AD=97?= =?UTF-8?q?=E6=AD=8C=E8=AF=8D=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- publish/changeLog.md | 1 + src/renderer/core/music/utils.ts | 4 +- src/renderer/utils/musicSdk/wy/lyric.js | 191 +++++++++++++++++++++--- 3 files changed, 171 insertions(+), 25 deletions(-) diff --git a/publish/changeLog.md b/publish/changeLog.md index a202d586..6c9df6a2 100644 --- a/publish/changeLog.md +++ b/publish/changeLog.md @@ -3,6 +3,7 @@ - 新增桌面歌词设置字体加粗设置,可以到设置-桌面歌词设置-加粗字体修改 - 新增是否自动下载更新设置,默认开启,可以去设置-软件更新更改 - 新增当前版本更新日志显示弹窗(建议大家阅读更新日志以了解当前版本的变化),在更新版本后将自动弹出 +- 添加wy源逐字歌词的支持 ### 优化 diff --git a/src/renderer/core/music/utils.ts b/src/renderer/core/music/utils.ts index a98c6b67..b48daf84 100644 --- a/src/renderer/core/music/utils.ts +++ b/src/renderer/core/music/utils.ts @@ -119,15 +119,17 @@ export const getCachedLyricInfo = async(musicInfo: LX.Music.MusicInfo): Promise< // } if (lrcInfo.lxlyric == null) { - switch (musicInfo.source) { + switch (musicInfo.source) { // 以下源支持lxlyric 重新获取 case 'kg': case 'kw': case 'mg': + case 'wy': break default: return lrcInfo } } else if (lrcInfo.rlyric == null) { + // 以下源支持 rlyric 重新获取 if (!['wy', 'kg'].includes(musicInfo.source)) return lrcInfo } else return lrcInfo } diff --git a/src/renderer/utils/musicSdk/wy/lyric.js b/src/renderer/utils/musicSdk/wy/lyric.js index 83ce416f..744209c4 100644 --- a/src/renderer/utils/musicSdk/wy/lyric.js +++ b/src/renderer/utils/musicSdk/wy/lyric.js @@ -1,5 +1,5 @@ import { httpFetch } from '../../request' -import { linuxapi } from './utils/crypto' +import { eapi } from './utils/crypto' // import { decodeName } from '../..' // const parseLyric = (str, lrc) => { @@ -34,33 +34,176 @@ import { linuxapi } from './utils/crypto' // return lxlyric.trim() // } -// https://github.com/Binaryify/NeteaseCloudMusicApi/pull/1523/files -export default songmid => { - const requestObj = httpFetch('https://music.163.com/api/linux/forward', { +const eapiRequest = (url, data) => { + return httpFetch('https://interface3.music.163.com/eapi/song/lyric/v1', { method: 'post', - 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36', - form: linuxapi({ - method: 'POST', - url: 'https://music.163.com/api/song/lyric?_nmclfl=1', - params: { - id: songmid, - tv: -1, - lv: -1, - rv: -1, - kv: -1, - }, - }), + headers: { + 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36', + origin: 'https://music.163.com', + // cookie: 'os=pc; deviceId=A9C064BB4584D038B1565B58CB05F95290998EE8B025AA2D07AE; osver=Microsoft-Windows-10-Home-China-build-19043-64bit; appver=2.5.2.197409; channel=netease; MUSIC_A=37a11f2eb9de9930cad479b2ad495b0e4c982367fb6f909d9a3f18f876c6b49faddb3081250c4980dd7e19d4bd9bf384e004602712cf2b2b8efaafaab164268a00b47359f85f22705cc95cb6180f3aee40f5be1ebf3148d888aa2d90636647d0c3061cd18d77b7a0; __csrf=05b50d54082694f945d7de75c210ef94; mode=Z7M-KP5(7)GZ; NMTID=00OZLp2VVgq9QdwokUgq3XNfOddQyIAAAF_6i8eJg; ntes_kaola_ad=1', + }, + form: eapi(url, data), + }) + // requestObj.promise = requestObj.promise.then(({ body }) => { + // // console.log(raw) + // console.log(body) + // // console.log(eapiDecrypt(raw)) + // // return eapiDecrypt(raw) + // return body + // }) + // return requestObj +} + +const parseTools = { + rxps: { + info: /^{"/, + lineTime: /^\[(\d+),\d+\]/, + wordTime: /\(\d+,\d+,\d+\)/, + wordTimeAll: /(\(\d+,\d+,\d+\))/g, + }, + msFormat(timeMs) { + if (Number.isNaN(timeMs)) return '' + let ms = timeMs % 1000 + timeMs /= 1000 + let m = parseInt(timeMs / 60).toString().padStart(2, '0') + timeMs %= 60 + let s = parseInt(timeMs).toString().padStart(2, '0') + return `[${m}:${s}.${ms}]` + }, + parseLyric(lines) { + const lxlrcLines = [] + const lrcLines = [] + + for (let line of lines) { + line = line.trim() + let result = this.rxps.lineTime.exec(line) + if (!result) continue + + const startMsTime = parseInt(result[1]) + const startTimeStr = this.msFormat(startMsTime) + if (!startTimeStr) continue + + let words = line.replace(this.rxps.lineTime, '') + + lrcLines.push(`${startTimeStr}${words.replace(this.rxps.wordTimeAll, '')}`) + + let times = words.match(this.rxps.wordTimeAll) + if (!times) continue + times = times.map(time => { + const result = /\((\d+),(\d+),\d+\)/.exec(time) + return `<${Math.max(parseInt(result[1]) - startMsTime, 0)},${result[2]}>` + }) + const wordArr = words.split(this.rxps.wordTime) + wordArr.shift() + const newWords = times.map((time, index) => `${time}${wordArr[index]}`).join('') + lxlrcLines.push(`${startTimeStr}${newWords}`) + } + return { + lyric: lrcLines.join('\n'), + lxlyric: lxlrcLines.join('\n'), + } + }, + parseHeaderInfo(str) { + str = str.trim() + str = str.replace(/\r/g, '') + if (!str) return null + const lines = str.split('\n') + return lines.map(line => { + if (!this.rxps.info.test(line)) return line + try { + const info = JSON.parse(line) + const timeTag = this.msFormat(info.t) + return timeTag ? `${timeTag}${info.c.map(t => t.tx).join('')}` : '' + } catch { + return '' + } + }) + }, + parse(ylrc, lrc, tlrc, rlrc) { + const info = { + lyric: '', + tlyric: '', + rlyric: '', + lxlyric: '', + } + if (ylrc) { + let lines = this.parseHeaderInfo(ylrc) + if (lines) { + const timeRxp = /^\[[\d:.]+\]/ + const headers = lines.filter(l => timeRxp.test(l)).join('\n') + const result = this.parseLyric(lines) + info.lxlyric = result.lxlyric + info.lyric = `${headers}\n${result.lyric}` + } else if (lrc) { + lines = this.parseHeaderInfo(lrc) + if (lines) info.lyric = lines.join('\n') + } + } else if (lrc) { + const lines = this.parseHeaderInfo(lrc) + if (lines) info.lyric = lines.join('\n') + } + if (tlrc) { + const lines = this.parseHeaderInfo(tlrc) + if (lines) info.tlyric = lines.join('\n') + } + if (rlrc) { + const lines = this.parseHeaderInfo(rlrc) + if (lines) info.rlyric = lines.join('\n') + } + + return info + }, +} + + +// https://github.com/Binaryify/NeteaseCloudMusicApi/pull/1523/files +// export default songmid => { +// const requestObj = httpFetch('https://music.163.com/api/linux/forward', { +// method: 'post', +// 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36', +// form: linuxapi({ +// method: 'POST', +// url: 'https://music.163.com/api/song/lyric?_nmclfl=1', +// params: { +// id: songmid, +// tv: -1, +// lv: -1, +// rv: -1, +// kv: -1, +// }, +// }), +// }) +// requestObj.promise = requestObj.promise.then(({ body }) => { +// if (body.code !== 200 || !body?.lrc?.lyric) return Promise.reject(new Error('Get lyric failed')) +// // console.log(body) +// return { +// lyric: body.lrc.lyric, +// tlyric: body.tlyric?.lyric ?? '', +// rlyric: body.romalrc?.lyric ?? '', +// // lxlyric: parseLyric(body.klyric.lyric), +// } +// }) +// return requestObj +// } + + +// https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/module/lyric_new.js +export default songmid => { + const requestObj = eapiRequest('/api/song/lyric/v1', { + id: songmid, + cp: false, + tv: 0, + lv: 0, + rv: 0, + kv: 0, + yv: 0, + ytv: 0, + yrv: 0, }) requestObj.promise = requestObj.promise.then(({ body }) => { - if (body.code !== 200 || !body?.lrc?.lyric) return Promise.reject(new Error('Get lyric failed')) // console.log(body) - return { - lyric: body.lrc.lyric, - tlyric: body.tlyric?.lyric ?? '', - rlyric: body.romalrc?.lyric ?? '', - // lxlyric: parseLyric(body.klyric.lyric), - } + if (body.code !== 200 || !body?.lrc?.lyric) return Promise.reject(new Error('Get lyric failed')) + return parseTools.parse(body.yrc?.lyric, body.lrc.lyric, body.tlyric?.lyric, body.romalrc?.lyric) }) return requestObj } -