增加kg专辑
This commit is contained in:
parent
b3dc8214e0
commit
4cb3ec9086
63
src/renderer/utils/musicSdk/kg/album.js
Normal file
63
src/renderer/utils/musicSdk/kg/album.js
Normal file
@ -0,0 +1,63 @@
|
||||
import { getMusicInfosByList } from './musicInfo'
|
||||
import { createHttpFetch } from './util'
|
||||
|
||||
export default {
|
||||
/**
|
||||
* 通过AlbumId获取专辑信息
|
||||
* @param {*} id
|
||||
*/
|
||||
async getAlbumInfo(id) {
|
||||
const albumInfoRequest = await createHttpFetch('http://kmrserviceretry.kugou.com/container/v1/album?dfid=1tT5He3kxrNC4D29ad1MMb6F&mid=22945702112173152889429073101964063697&userid=0&appid=1005&clientver=11589', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
appid: 1005,
|
||||
clienttime: 1681833686,
|
||||
clientver: 11589,
|
||||
data: [{ album_id: id }],
|
||||
fields: 'language,grade_count,intro,mix_intro,heat,category,sizable_cover,cover,album_name,type,quality,publish_company,grade,special_tag,author_name,publish_date,language_id,album_id,exclusive,is_publish,trans_param,authors,album_tag',
|
||||
isBuy: 0,
|
||||
key: 'e6f3306ff7e2afb494e89fbbda0becbf',
|
||||
mid: '22945702112173152889429073101964063697',
|
||||
show_album_tag: 0,
|
||||
},
|
||||
})
|
||||
if (!albumInfoRequest) return Promise.reject(new Error('get album info failed.'))
|
||||
const albumInfo = albumInfoRequest[0]
|
||||
|
||||
return {
|
||||
name: albumInfo.album_name,
|
||||
image: albumInfo.sizable_cover.replace('{size}', 240),
|
||||
desc: albumInfo.intro,
|
||||
authorName: albumInfo.author_name,
|
||||
// play_count: this.formatPlayCount(info.count),
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 通过AlbumId获取专辑
|
||||
* @param {*} id
|
||||
* @param {*} page
|
||||
*/
|
||||
async getAlbumDetail(id, page = 1, limit = 200) {
|
||||
const info = await this.getAlbumInfo(id)
|
||||
|
||||
const albumList = await createHttpFetch(`http://mobiles.kugou.com/api/v3/album/song?version=9108&albumid=${id}&plat=0&pagesize=${limit}&area_code=0&page=${page}&with_res_tag=0`)
|
||||
if (!albumList.info) return Promise.reject(new Error('Get album list failed.'))
|
||||
|
||||
let result = await getMusicInfosByList(albumList.info)
|
||||
|
||||
return {
|
||||
list: result || [],
|
||||
page,
|
||||
limit,
|
||||
total: albumList.total,
|
||||
source: 'kg',
|
||||
info: {
|
||||
name: info.name,
|
||||
img: info.image,
|
||||
desc: info.desc,
|
||||
author: info.authorName,
|
||||
// play_count: this.formatPlayCount(info.count),
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -1,12 +1,5 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { decodeName, formatPlayTime, sizeFormate } from '../../index'
|
||||
import { signatureParams } from './util'
|
||||
// import { debug } from '../../utils/env'
|
||||
|
||||
// const searchParams = (params, keyword) => {
|
||||
// let signature = signatureParams(params.replace('{keyword}', keyword))
|
||||
// return `${params.replace('{keyword}', encodeURIComponent(keyword))}&signature=${signature}`
|
||||
// }
|
||||
import { signatureParams, createHttpFetch } from './util'
|
||||
|
||||
export default {
|
||||
limit: 30,
|
||||
@ -15,8 +8,8 @@ export default {
|
||||
allPage: 1,
|
||||
musicSearch(str, page, limit) {
|
||||
const sign = signatureParams(`userid=0&area_code=1&appid=1005&dopicfull=1&page=${page}&token=0&privilegefilter=0&requestid=0&pagesize=${limit}&user_labels=&clienttime=0&sec_aggre=1&iscorrection=1&uuid=0&mid=0&keyword=${str}&dfid=-&clientver=11409&platform=AndroidFilter&tag=`, 3)
|
||||
const searchRequest = httpFetch(`https://gateway.kugou.com/complexsearch/v3/search/song?userid=0&area_code=1&appid=1005&dopicfull=1&page=${page}&token=0&privilegefilter=0&requestid=0&pagesize=${limit}&user_labels=&clienttime=0&sec_aggre=1&iscorrection=1&uuid=0&mid=0&dfid=-&clientver=11409&platform=AndroidFilter&tag=&keyword=${encodeURIComponent(str)}&signature=${sign}`)
|
||||
return searchRequest.promise.then(({ body }) => body)
|
||||
const searchRequest = createHttpFetch(`https://gateway.kugou.com/complexsearch/v3/search/song?userid=0&area_code=1&appid=1005&dopicfull=1&page=${page}&token=0&privilegefilter=0&requestid=0&pagesize=${limit}&user_labels=&clienttime=0&sec_aggre=1&iscorrection=1&uuid=0&mid=0&dfid=-&clientver=11409&platform=AndroidFilter&tag=&keyword=${encodeURIComponent(str)}&signature=${sign}`)
|
||||
return searchRequest.then(body => body)
|
||||
},
|
||||
filterSongData(rawData) {
|
||||
let ids = new Set()
|
||||
@ -85,18 +78,18 @@ export default {
|
||||
|
||||
return list
|
||||
},
|
||||
search(str, page = 1, limit, retryNum = 0) {
|
||||
async search(str, page = 1, limit, retryNum = 0) {
|
||||
if (++retryNum > 3) return Promise.reject(new Error('try max num'))
|
||||
if (limit == null) limit = this.limit
|
||||
|
||||
// http://newlyric.kuwo.cn/newlyric.lrc?62355680
|
||||
return this.musicSearch(str, page, limit).then(result => {
|
||||
if (!result || result.error_code !== 0) return this.search(str, page, limit, retryNum)
|
||||
// console.log(result)
|
||||
let list = this.filterSongData(result.data.lists)
|
||||
const sign = signatureParams(`userid=0&area_code=1&appid=1005&dopicfull=1&page=${page}&token=0&privilegefilter=0&requestid=0&pagesize=${limit}&user_labels=&clienttime=0&sec_aggre=1&iscorrection=1&uuid=0&mid=0&keyword=${str}&dfid=-&clientver=11409&platform=AndroidFilter&tag=`, 3)
|
||||
const searchResult = await createHttpFetch(`https://gateway.kugou.com/complexsearch/v3/search/song?userid=0&area_code=1&appid=1005&dopicfull=1&page=${page}&token=0&privilegefilter=0&requestid=0&pagesize=${limit}&user_labels=&clienttime=0&sec_aggre=1&iscorrection=1&uuid=0&mid=0&dfid=-&clientver=11409&platform=AndroidFilter&tag=&keyword=${encodeURIComponent(str)}&signature=${sign}`)
|
||||
|
||||
if (list == null) return this.search(str, page, limit, retryNum)
|
||||
let list = this.filterSongData(searchResult.lists)
|
||||
if (!list) return this.search(str, page, limit, retryNum)
|
||||
|
||||
this.total = result.data.total
|
||||
this.total = searchResult.total
|
||||
this.page = page
|
||||
this.allPage = Math.ceil(this.total / limit)
|
||||
|
||||
@ -107,6 +100,5 @@ export default {
|
||||
total: this.total,
|
||||
source: 'kg',
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { decodeName, formatPlayTime, sizeFormate, dateFormat } from '../../index'
|
||||
import infSign from './vendors/infSign.min'
|
||||
import { signatureParams } from './util'
|
||||
import { httpFetch } from '../../../request'
|
||||
import { decodeName, formatPlayTime, sizeFormate, dateFormat } from '../../../index'
|
||||
import infSign from '../vendors/infSign.min'
|
||||
import { signatureParams } from '../util'
|
||||
|
||||
const handleSignature = (id, page, limit) => new Promise((resolve, reject) => {
|
||||
infSign({ appid: 1058, type: 0, module: 'playlist', page, pagesize: limit, specialid: id }, null, {
|
||||
@ -2,6 +2,7 @@ import { httpFetch } from '../../request'
|
||||
import { decodeName, formatPlayTime, sizeFormate, dateFormat } from '../../index'
|
||||
import { signatureParams, createHttpFetch } from './util'
|
||||
import { getMusicInfosByList } from './musicInfo'
|
||||
import album from './album'
|
||||
|
||||
// import infSign from './vendors/infSign.min'
|
||||
// const handleSignature = (id, page, limit) => new Promise((resolve, reject) => {
|
||||
@ -55,6 +56,39 @@ export default {
|
||||
listDetailLink: /^.+\/(\d+)\.html(?:\?.*|&.*$|#.*$|$)/,
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取歌曲列表内的音乐
|
||||
* @param {*} id
|
||||
* @param {*} page
|
||||
*/
|
||||
async getListDetail(id, page) {
|
||||
id = id.toString()
|
||||
|
||||
if (id.includes('special/single/')) id = id.replace(this.regExps.listDetailLink, '$1')
|
||||
// fix https://www.kugou.com/songlist/xxx/?uid=xxx&chl=qq_client&cover=http%3A%2F%2Fimge.kugou.com%xxx.jpg&iszlist=1
|
||||
if (/https?:/.test(id)) {
|
||||
if (id.includes('#')) id = id.replace(/#.*$/, '')
|
||||
if (id.includes('global_collection_id')) return this.getUserListDetailByCollectionId(id.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1'), page)
|
||||
if (id.includes('chain=')) return this.getUserListDetail3(id.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'), page)
|
||||
if (id.includes('.html')) {
|
||||
if (id.includes('zlist.html')) {
|
||||
id = id.replace(/^(.*)zlist\.html/, 'https://m3ws.kugou.com/zlist/list')
|
||||
if (id.includes('pagesize')) {
|
||||
id = id.replace('pagesize=30', 'pagesize=' + this.listDetailLimit).replace('page=1', 'page=' + page)
|
||||
} else {
|
||||
id += `&pagesize=${this.listDetailLimit}&page=${page}`
|
||||
}
|
||||
} else if (!id.includes('song.html')) return this.getUserListDetail3(id.replace(/.+\/(\w+).html(?:\?.*|&.*$|#.*$|$)/, '$1'), page)
|
||||
}
|
||||
return this.getUserListDetail(id.replace(/^.*?http/, 'http'), page)
|
||||
}
|
||||
if (/^\d+$/.test(id)) return this.getUserListDetailByCode(id, page)
|
||||
if (id.startsWith('gid_')) return this.getUserListDetailByCollectionId(id.replace('gid_', ''), page)
|
||||
if (id.startsWith('id_')) return this.getUserListDetailBySpecialId(id.replace('id_', ''), page)
|
||||
|
||||
return new Error('Failed.')
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取SpecialId歌单
|
||||
* @param {*} id
|
||||
@ -67,7 +101,6 @@ export default {
|
||||
let listInfo = body.match(this.regExps.listInfo)
|
||||
if (!listData) return this.getListDetailBySpecialId(id, page, ++tryNum)
|
||||
let list = await getMusicInfosByList(JSON.parse(listData[1]))
|
||||
// listData = this.filterData(JSON.parse(listData[1]))
|
||||
let name
|
||||
let pic
|
||||
if (listInfo) {
|
||||
@ -293,7 +326,7 @@ export default {
|
||||
// },
|
||||
// }).then(body => {
|
||||
// if (!body.info) return Promise.reject(new Error('Get list failed.'))
|
||||
// const songList = this.filterCollectionIdList(body.info)
|
||||
// const songList = this.filterListByCollectionId(body.info)
|
||||
|
||||
// return {
|
||||
// list: songList || [],
|
||||
@ -326,7 +359,7 @@ export default {
|
||||
},
|
||||
}).then(body => {
|
||||
if (!body.info) return Promise.reject(new Error('Get list failed.'))
|
||||
const songList = this.filterCollectionIdList(body.info)
|
||||
const songList = this.filterListByCollectionId(body.info)
|
||||
|
||||
return {
|
||||
list: songList || [],
|
||||
@ -348,7 +381,7 @@ export default {
|
||||
* 过滤GlobalSpecialId歌单数据
|
||||
* @param {*} rawData
|
||||
*/
|
||||
filterCollectionIdList(rawData) {
|
||||
filterListByCollectionId(rawData) {
|
||||
let ids = new Set()
|
||||
let list = []
|
||||
rawData.forEach(item => {
|
||||
@ -436,7 +469,7 @@ export default {
|
||||
if (!codeInfo.global_collection_id) return this.getUserListDetailBySpecialId(codeInfo.id, page)
|
||||
break
|
||||
case 3:
|
||||
return this.getListDetailByAlbumId(codeInfo.id, page)
|
||||
return album.getAlbumDetail(codeInfo.id, page)
|
||||
}
|
||||
if (codeInfo.global_collection_id) return this.getUserListDetailByCollectionId(codeInfo.global_collection_id, page)
|
||||
|
||||
@ -658,19 +691,6 @@ export default {
|
||||
|
||||
async getUserListDetail(link, page, retryNum = 0) {
|
||||
if (retryNum > 3) return Promise.reject(new Error('link try max num'))
|
||||
if (link.includes('#')) link = link.replace(/#.*$/, '')
|
||||
if (link.includes('global_collection_id')) return this.getUserListDetailByCollectionId(link.replace(/^.*?global_collection_id=(\w+)(?:&.*$|#.*$|$)/, '$1'), page)
|
||||
if (link.includes('chain=')) return this.getUserListDetail3(link.replace(/^.*?chain=(\w+)(?:&.*$|#.*$|$)/, '$1'), page)
|
||||
if (link.includes('.html')) {
|
||||
if (link.includes('zlist.html')) {
|
||||
link = link.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}`
|
||||
}
|
||||
} else if (!link.includes('song.html')) return this.getUserListDetail3(link.replace(/.+\/(\w+).html(?:\?.*|&.*$|#.*$|$)/, '$1'), page)
|
||||
}
|
||||
|
||||
const requestLink = httpFetch(link, {
|
||||
headers: {
|
||||
@ -684,9 +704,9 @@ export default {
|
||||
if (statusCode > 400) return this.getUserListDetail(link, page, ++retryNum)
|
||||
if (typeof body == 'string') {
|
||||
if (body.includes('"global_collection_id":')) return this.getUserListDetailByCollectionId(body.replace(/^[\s\S]+?"global_collection_id":"(\w+)"[\s\S]+?$/, '$1'), page)
|
||||
if (body.includes('"albumid":')) return this.getListDetailByAlbumId(body.replace(/^[\s\S]+?"albumid":(\w+)[\s\S]+?$/, '$1'), page)
|
||||
if (body.includes('"album_id":') && link.includes('album/info')) return this.getListDetailByAlbumId(body.replace(/^[\s\S]+?"album_id":(\w+)[\s\S]+?$/, '$1'), page)
|
||||
if (body.includes('list_id = "') && link.includes('album/info')) return this.getListDetailByAlbumId(body.replace(/^[\s\S]+?list_id = "(\w+)"[\s\S]+?$/, '$1'), page)
|
||||
if (body.includes('"albumid":')) return album.getAlbumDetail(body.replace(/^[\s\S]+?"albumid":(\w+)[\s\S]+?$/, '$1'), page)
|
||||
if (body.includes('"album_id":') && link.includes('album/info')) return album.getAlbumDetail(body.replace(/^[\s\S]+?"album_id":(\w+)[\s\S]+?$/, '$1'), page)
|
||||
if (body.includes('list_id = "') && link.includes('album/info')) return album.getAlbumDetail(body.replace(/^[\s\S]+?list_id = "(\w+)"[\s\S]+?$/, '$1'), page)
|
||||
}
|
||||
if (location) {
|
||||
// 概念版分享链接 https://t1.kugou.com/xxx
|
||||
@ -710,79 +730,6 @@ export default {
|
||||
return this.getUserListDetailByLink(body, link)
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取歌曲列表内的音乐
|
||||
* @param {*} id
|
||||
* @param {*} page
|
||||
*/
|
||||
async getListDetail(id, page) {
|
||||
id = id.toString()
|
||||
|
||||
if (id.includes('special/single/')) id = id.replace(this.regExps.listDetailLink, '$1')
|
||||
// fix https://www.kugou.com/songlist/xxx/?uid=xxx&chl=qq_client&cover=http%3A%2F%2Fimge.kugou.com%xxx.jpg&iszlist=1
|
||||
if (/https?:/.test(id)) return this.getUserListDetail(id.replace(/^.*?http/, 'http'), page)
|
||||
if (/^\d+$/.test(id)) return this.getUserListDetailByCode(id, page)
|
||||
if (id.startsWith('gid_')) return this.getUserListDetailByCollectionId(id.replace('gid_', ''), page)
|
||||
if (id.startsWith('id_')) return this.getUserListDetailBySpecialId(id.replace('id_', ''), page)
|
||||
|
||||
return new Error('Failed.')
|
||||
},
|
||||
|
||||
filterData(rawList) {
|
||||
// console.log(rawList)
|
||||
return rawList.map(item => {
|
||||
const types = []
|
||||
const _types = {}
|
||||
if (item.filesize !== 0) {
|
||||
let size = sizeFormate(item.filesize)
|
||||
types.push({ type: '128k', size, hash: item.hash })
|
||||
_types['128k'] = {
|
||||
size,
|
||||
hash: item.hash,
|
||||
}
|
||||
}
|
||||
if (item.filesize_320 !== 0) {
|
||||
let size = sizeFormate(item.filesize_320)
|
||||
types.push({ type: '320k', size, hash: item.hash_320 })
|
||||
_types['320k'] = {
|
||||
size,
|
||||
hash: item.hash_320,
|
||||
}
|
||||
}
|
||||
if (item.filesize_ape !== 0) {
|
||||
let size = sizeFormate(item.filesize_ape)
|
||||
types.push({ type: 'ape', size, hash: item.hash_ape })
|
||||
_types.ape = {
|
||||
size,
|
||||
hash: item.hash_ape,
|
||||
}
|
||||
}
|
||||
if (item.filesize_flac !== 0) {
|
||||
let size = sizeFormate(item.filesize_flac)
|
||||
types.push({ type: 'flac', size, hash: item.hash_flac })
|
||||
_types.flac = {
|
||||
size,
|
||||
hash: item.hash_flac,
|
||||
}
|
||||
}
|
||||
return {
|
||||
singer: decodeName(item.singername),
|
||||
name: decodeName(item.songname),
|
||||
albumName: decodeName(item.album_name),
|
||||
albumId: item.album_id,
|
||||
songmid: item.audio_id,
|
||||
source: 'kg',
|
||||
interval: formatPlayTime(item.duration / 1000),
|
||||
img: null,
|
||||
lrc: null,
|
||||
hash: item.hash,
|
||||
types,
|
||||
_types,
|
||||
typeUrl: {},
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 获取列表信息
|
||||
getListInfo(tagId, tryNum = 0) {
|
||||
if (this._requestObj_listInfo) this._requestObj_listInfo.cancelHttp()
|
||||
|
||||
@ -35,7 +35,7 @@ export const signatureParams = (params, apiver = 9) => {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个Http请求
|
||||
* 创建一个适用于KG的Http请求
|
||||
* @param {*} url
|
||||
* @param {*} options
|
||||
* @param {*} retryNum
|
||||
|
||||
@ -1,6 +1,107 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { getMusicInfo } from './musicInfo'
|
||||
import { decrypt } from './mrc'
|
||||
|
||||
// const key = 'karakal@123Qcomyidongtiantianhaoting'
|
||||
const DELTA = 2654435769n
|
||||
const MIN_LENGTH = 32
|
||||
// const SPECIAL_CHAR = '0'
|
||||
const keyArr = [
|
||||
27303562373562475n,
|
||||
18014862372307051n,
|
||||
22799692160172081n,
|
||||
34058940340699235n,
|
||||
30962724186095721n,
|
||||
27303523720101991n,
|
||||
27303523720101998n,
|
||||
31244139033526382n,
|
||||
28992395054481524n,
|
||||
]
|
||||
|
||||
const teaDecrypt = (data, key) => {
|
||||
const length = data.length
|
||||
const lengthBitint = BigInt(length)
|
||||
if (length >= 1) {
|
||||
// let j = data[data.length - 1];
|
||||
let j2 = data[0]
|
||||
let j3 = toLong((6n + (52n / lengthBitint)) * DELTA)
|
||||
while (true) {
|
||||
let j4 = j3
|
||||
if (j4 == 0n) break
|
||||
let j5 = toLong(3n & toLong(j4 >> 2n))
|
||||
let j6 = lengthBitint
|
||||
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)))))
|
||||
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)))))
|
||||
data[0] = j2
|
||||
j3 = toLong(j4 - DELTA)
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
const longArrToString = (data) => {
|
||||
const arrayList = []
|
||||
for (const j of data) arrayList.push(longToBytes(j).toString('utf16le'))
|
||||
return arrayList.join('')
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/29132118
|
||||
const longToBytes = (l) => {
|
||||
const result = Buffer.alloc(8)
|
||||
for (let i = 0; i < 8; i++) {
|
||||
result[i] = parseInt(l & 0xFFn)
|
||||
l >>= 8n
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
const toBigintArray = (data) => {
|
||||
const length = Math.floor(data.length / 16)
|
||||
const jArr = Array(length)
|
||||
for (let i = 0; i < length; i++) {
|
||||
jArr[i] = toLong(data.substring(i * 16, (i * 16) + 16))
|
||||
}
|
||||
return jArr
|
||||
}
|
||||
|
||||
// https://github.com/lyswhut/lx-music-desktop/issues/445#issuecomment-1139338682
|
||||
const MAX = 9223372036854775807n
|
||||
const MIN = -9223372036854775808n
|
||||
const toLong = str => {
|
||||
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
|
||||
}
|
||||
|
||||
const mrcDecrypt = (data) => {
|
||||
// console.log(data.length)
|
||||
// -3551594764563790630
|
||||
// console.log(toLongArrayFromArr(Buffer.from(key)))
|
||||
// console.log(teaDecrypt(toBigintArray(data), keyArr))
|
||||
// console.log(longArrToString(teaDecrypt(toBigintArray(data), keyArr)))
|
||||
// console.log(toByteArray(teaDecrypt(toBigintArray(data), keyArr)))
|
||||
return (data == null || data.length < MIN_LENGTH)
|
||||
? data
|
||||
: longArrToString(teaDecrypt(toBigintArray(data), keyArr))
|
||||
}
|
||||
|
||||
// console.log(14895149309145760986n - )
|
||||
// console.log(toLong('14895149309145760986'))
|
||||
// console.log(mrcDecrypt(str))
|
||||
// console.log(mrcDecrypt(str))
|
||||
// console.log(toByteArray([6048138644744000495n]))
|
||||
// console.log(toByteArray([16325999628386395n]))
|
||||
// console.log(toLong(90994076459972177136n))
|
||||
|
||||
const mrcTools = {
|
||||
rxps: {
|
||||
@ -63,7 +164,7 @@ const mrcTools = {
|
||||
},
|
||||
getMrc(url) {
|
||||
return this.getText(url).then(text => {
|
||||
return this.parseLyric(decrypt(text))
|
||||
return this.parseLyric(mrcDecrypt(text))
|
||||
})
|
||||
},
|
||||
getLrc(url) {
|
||||
|
||||
@ -1,104 +0,0 @@
|
||||
|
||||
// const key = 'karakal@123Qcomyidongtiantianhaoting'
|
||||
const DELTA = 2654435769n
|
||||
const MIN_LENGTH = 32
|
||||
// const SPECIAL_CHAR = '0'
|
||||
const keyArr = [
|
||||
27303562373562475n,
|
||||
18014862372307051n,
|
||||
22799692160172081n,
|
||||
34058940340699235n,
|
||||
30962724186095721n,
|
||||
27303523720101991n,
|
||||
27303523720101998n,
|
||||
31244139033526382n,
|
||||
28992395054481524n,
|
||||
]
|
||||
|
||||
|
||||
const teaDecrypt = (data, key) => {
|
||||
const length = data.length
|
||||
const lengthBitint = BigInt(length)
|
||||
if (length >= 1) {
|
||||
// let j = data[data.length - 1];
|
||||
let j2 = data[0]
|
||||
let j3 = toLong((6n + (52n / lengthBitint)) * DELTA)
|
||||
while (true) {
|
||||
let j4 = j3
|
||||
if (j4 == 0n) break
|
||||
let j5 = toLong(3n & toLong(j4 >> 2n))
|
||||
let j6 = lengthBitint
|
||||
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)))))
|
||||
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)))))
|
||||
data[0] = j2
|
||||
j3 = toLong(j4 - DELTA)
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
const longArrToString = (data) => {
|
||||
const arrayList = []
|
||||
for (const j of data) arrayList.push(longToBytes(j).toString('utf16le'))
|
||||
return arrayList.join('')
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/29132118
|
||||
const longToBytes = (l) => {
|
||||
const result = Buffer.alloc(8)
|
||||
for (let i = 0; i < 8; i++) {
|
||||
result[i] = parseInt(l & 0xFFn)
|
||||
l >>= 8n
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
const toBigintArray = (data) => {
|
||||
const length = Math.floor(data.length / 16)
|
||||
const jArr = Array(length)
|
||||
for (let i = 0; i < length; i++) {
|
||||
jArr[i] = toLong(data.substring(i * 16, (i * 16) + 16))
|
||||
}
|
||||
return jArr
|
||||
}
|
||||
|
||||
// https://github.com/lyswhut/lx-music-desktop/issues/445#issuecomment-1139338682
|
||||
const MAX = 9223372036854775807n
|
||||
const MIN = -9223372036854775808n
|
||||
const toLong = str => {
|
||||
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) => {
|
||||
// console.log(data.length)
|
||||
// -3551594764563790630
|
||||
// console.log(toLongArrayFromArr(Buffer.from(key)))
|
||||
// console.log(teaDecrypt(toBigintArray(data), keyArr))
|
||||
// console.log(longArrToString(teaDecrypt(toBigintArray(data), keyArr)))
|
||||
// console.log(toByteArray(teaDecrypt(toBigintArray(data), keyArr)))
|
||||
return (data == null || data.length < MIN_LENGTH)
|
||||
? data
|
||||
: longArrToString(teaDecrypt(toBigintArray(data), keyArr))
|
||||
}
|
||||
|
||||
// console.log(14895149309145760986n - )
|
||||
// console.log(toLong('14895149309145760986'))
|
||||
// console.log(decrypt(str))
|
||||
// console.log(decrypt(str))
|
||||
// console.log(toByteArray([6048138644744000495n]))
|
||||
// console.log(toByteArray([16325999628386395n]))
|
||||
// console.log(toLong(90994076459972177136n))
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { httpFetch } from '../../request'
|
||||
import { formatPlayTime } from '../../index'
|
||||
import { httpFetch } from '../../../request'
|
||||
import { formatPlayTime } from '../../../index'
|
||||
// import { sizeFormate } from '../../index'
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user