- 四平台 tipSearch 全部删除(永不做搜索联想),types 同步去掉 tipSearch 字段 - 歌词解码器归位:kg/krcDecode、tx/qrcDecode、kw/lyricDecode(原 common/ 下三处) - rendererIpc/ipcNames IPC 桥删除,SDK 纯服务端化 - supportQuality 由各平台 apis 内联导出(sdk/index 汇总),kg/kw/tx/wy 改直连 apis/*,api-source 旧层移除
49 lines
1.5 KiB
TypeScript
49 lines
1.5 KiB
TypeScript
// 酷我歌词解码(原主进程 IPC 处理器的纯 JS 实现)
|
||
// - 酷我歌词(inflate + yeelion XOR + gb18030)
|
||
// 算法来源: kw 桌面端歌词解码实现
|
||
|
||
import zlib from 'node:zlib'
|
||
import iconv from 'iconv-lite'
|
||
|
||
const handleInflate = (data: Buffer): Promise<Buffer> => new Promise((resolve, reject) => {
|
||
zlib.inflate(data, (err, result) => {
|
||
if (err) return reject(err)
|
||
resolve(result)
|
||
})
|
||
})
|
||
|
||
const buf_key = Buffer.from('yeelion')
|
||
const buf_key_len = buf_key.length
|
||
|
||
const decodeKwLyric = async(buf, isGetLyricx) => {
|
||
if (buf.toString('utf8', 0, 10) != 'tp=content') return ''
|
||
const lrcData = await handleInflate(buf.subarray(buf.indexOf('\r\n\r\n') + 4))
|
||
|
||
if (!isGetLyricx) return iconv.decode(lrcData, 'gb18030')
|
||
|
||
const buf_str = Buffer.from(lrcData.toString(), 'base64')
|
||
const buf_str_len = buf_str.length
|
||
const output = new Uint8Array(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_str[i] ^ buf_key[j]
|
||
i++
|
||
j++
|
||
}
|
||
}
|
||
|
||
return iconv.decode(Buffer.from(output), 'gb18030')
|
||
}
|
||
|
||
/**
|
||
* 酷我歌词解码
|
||
* @param {{ lrcBase64: string, isGetLyricx: boolean }} params
|
||
* @returns {Promise<string>} 解码后歌词的 base64
|
||
*/
|
||
export const handleKwDecodeLyric = async({ lrcBase64, isGetLyricx }) => {
|
||
const lrc = await decodeKwLyric(Buffer.from(lrcBase64, 'base64'), isGetLyricx)
|
||
return Buffer.from(lrc).toString('base64')
|
||
}
|