新增对kw源卡拉OK歌词的支持
parent
1fd3e6c9fa
commit
545ba6521b
|
@ -4,6 +4,7 @@
|
||||||
- 新增播放详情页通过歌词调整播放进度,默认关闭,需要到设置-播放详情页设置开启,开启后在播放详情页拖动歌词时将会出现跳转当前行歌词播放的按钮
|
- 新增播放详情页通过歌词调整播放进度,默认关闭,需要到设置-播放详情页设置开启,开启后在播放详情页拖动歌词时将会出现跳转当前行歌词播放的按钮
|
||||||
- 新增全屏状态,按F11可以进入、退出全屏状态,由于全屏时会隐藏控制栏按钮,所以需要使用鼠标右键双击(详情页的任意地方都可以)来关闭播放详情页
|
- 新增全屏状态,按F11可以进入、退出全屏状态,由于全屏时会隐藏控制栏按钮,所以需要使用鼠标右键双击(详情页的任意地方都可以)来关闭播放详情页
|
||||||
- 新增动态主题“道法自然”,你可以预先设置一个亮色主题及暗色主题,此后将根据系统的亮、暗主题色自动切换为你预先设置的相应主题。注:鼠标 右击 此主题项即可打开亮、暗色主题设置窗口。
|
- 新增动态主题“道法自然”,你可以预先设置一个亮色主题及暗色主题,此后将根据系统的亮、暗主题色自动切换为你预先设置的相应主题。注:鼠标 右击 此主题项即可打开亮、暗色主题设置窗口。
|
||||||
|
- 新增对kw源卡拉OK歌词的支持
|
||||||
|
|
||||||
### 优化
|
### 优化
|
||||||
|
|
||||||
|
|
|
@ -188,6 +188,7 @@ const actions = {
|
||||||
},
|
},
|
||||||
async getLrc({ commit, state }, musicInfo) {
|
async getLrc({ commit, state }, musicInfo) {
|
||||||
const lrcInfo = await getStoreLyric(musicInfo)
|
const lrcInfo = await getStoreLyric(musicInfo)
|
||||||
|
// lrcInfo = {}
|
||||||
// if (lrcRequest && lrcRequest.cancelHttp) lrcRequest.cancelHttp()
|
// if (lrcRequest && lrcRequest.cancelHttp) lrcRequest.cancelHttp()
|
||||||
if (lrcInfo.lyric && lrcInfo.tlyric != null) {
|
if (lrcInfo.lyric && lrcInfo.tlyric != null) {
|
||||||
// if (musicInfo.lrc.startsWith('\ufeff[id:$00000000]')) {
|
// if (musicInfo.lrc.startsWith('\ufeff[id:$00000000]')) {
|
||||||
|
@ -198,7 +199,15 @@ const actions = {
|
||||||
// commit('setLrc', { musicInfo, lyric: str, tlyric: musicInfo.tlrc, lxlyric: musicInfo.tlrc })
|
// commit('setLrc', { musicInfo, lyric: str, tlyric: musicInfo.tlrc, lxlyric: musicInfo.tlrc })
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if ((lrcInfo.lxlyric == null && musicInfo.source != 'kg') || lrcInfo.lxlyric != null) return lrcInfo
|
if (lrcInfo.lxlyric == null) {
|
||||||
|
switch (musicInfo.source) {
|
||||||
|
case 'kg':
|
||||||
|
case 'kw':
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return lrcInfo
|
||||||
|
}
|
||||||
|
} else return lrcInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// lrcRequest = music[musicInfo.source].getLyric(musicInfo)
|
// lrcRequest = music[musicInfo.source].getLyric(musicInfo)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { httpFetch } from '../../request'
|
import { httpFetch } from '../../request'
|
||||||
import { decodeLyric } from './util'
|
import { decodeLyric, lrcTools } from './util'
|
||||||
import { decodeName } from '../../index'
|
import { decodeName } from '../../index'
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -99,6 +99,7 @@ export default {
|
||||||
|
|
||||||
for (const item of arr) {
|
for (const item of arr) {
|
||||||
if (lrcSet.has(item.time)) {
|
if (lrcSet.has(item.time)) {
|
||||||
|
if (lrc.length < 2) continue
|
||||||
const tItem = lrc.pop()
|
const tItem = lrc.pop()
|
||||||
tItem.time = lrc[lrc.length - 1].time
|
tItem.time = lrc[lrc.length - 1].time
|
||||||
lrcT.push(tItem)
|
lrcT.push(tItem)
|
||||||
|
@ -120,11 +121,12 @@ export default {
|
||||||
lrcT,
|
lrcT,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
transformLrc(songinfo, lrclist) {
|
transformLrc(tags, lrclist) {
|
||||||
return `[ti:${songinfo.name ?? ''}]\n[ar:${songinfo.singer ?? ''}]\n[al:${songinfo.albumName ?? ''}]\n[by:]\n[offset:0]\n${lrclist ? lrclist.map(l => `[${l.time}]${l.text}\n`).join('') : '暂无歌词'}`
|
return `${tags.join('\n')}\n${lrclist ? lrclist.map(l => `[${l.time}]${l.text}\n`).join('') : '暂无歌词'}`
|
||||||
},
|
},
|
||||||
parseLrc(musicInfo, lrc) {
|
parseLrc(lrc) {
|
||||||
const lines = lrc.split(/\r\n|\r|\n/)
|
const lines = lrc.split(/\r\n|\r|\n/)
|
||||||
|
let tags = []
|
||||||
let lrcArr = []
|
let lrcArr = []
|
||||||
for (let i = 0; i < lines.length; i++) {
|
for (let i = 0; i < lines.length; i++) {
|
||||||
const line = lines[i].trim()
|
const line = lines[i].trim()
|
||||||
|
@ -135,26 +137,66 @@ export default {
|
||||||
time: RegExp.$1,
|
time: RegExp.$1,
|
||||||
text,
|
text,
|
||||||
})
|
})
|
||||||
|
} else if (lrcTools.rxps.tagLine.test(line)) {
|
||||||
|
tags.push(line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const lrcInfo = this.sortLrcArr(lrcArr)
|
const lrcInfo = this.sortLrcArr(lrcArr)
|
||||||
return {
|
return {
|
||||||
lyric: decodeName(this.transformLrc(musicInfo, lrcInfo.lrc)),
|
lyric: decodeName(this.transformLrc(tags, lrcInfo.lrc)),
|
||||||
tlyric: lrcInfo.lrcT.length ? decodeName(this.transformLrc(musicInfo, lrcInfo.lrcT)) : '',
|
tlyric: lrcInfo.lrcT.length ? decodeName(this.transformLrc(tags, lrcInfo.lrcT)) : '',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getLyric(musicInfo, isGetLyricx = false) {
|
// 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)}`)
|
const requestObj = httpFetch(`http://newlyric.kuwo.cn/newlyric.lrc?${buildParams(musicInfo.songmid, isGetLyricx)}`)
|
||||||
requestObj.promise = requestObj.promise.then(({ statusCode, body, raw }) => {
|
requestObj.promise = requestObj.promise.then(({ statusCode, body, raw }) => {
|
||||||
if (statusCode != 200) return Promise.reject(new Error(JSON.stringify(body)))
|
if (statusCode != 200) return Promise.reject(new Error(JSON.stringify(body)))
|
||||||
return decodeLyric({ lrcBase64: raw.toString('base64'), isGetLyricx }).then(base64Data => {
|
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
|
let lrcInfo
|
||||||
|
// console.log(Buffer.from(base64Data, 'base64').toString())
|
||||||
try {
|
try {
|
||||||
lrcInfo = this.parseLrc(musicInfo, Buffer.from(base64Data, 'base64').toString())
|
lrcInfo = this.parseLrc(Buffer.from(base64Data, 'base64').toString())
|
||||||
} catch {
|
} catch (err) {
|
||||||
return Promise.reject(new Error('Get lyric failed'))
|
return Promise.reject(new Error('Get lyric failed'))
|
||||||
}
|
}
|
||||||
// console.log(lrcInfo)
|
// console.log(lrcInfo)
|
||||||
|
if (lrcInfo.tlyric) lrcInfo.tlyric = lrcInfo.tlyric.replace(lrcTools.rxps.wordTimeAll, '')
|
||||||
|
try {
|
||||||
|
lrcInfo.lxlyric = lrcTools.parse(lrcInfo.lyric)
|
||||||
|
} catch {
|
||||||
|
lrcInfo.lxlyric = ''
|
||||||
|
}
|
||||||
|
if (lrcInfo.lxlyric) lrcInfo.lyric = lrcInfo.lyric.replace(lrcTools.rxps.wordTimeAll, '')
|
||||||
|
// console.log(lrcInfo.lxlyric)
|
||||||
return lrcInfo
|
return lrcInfo
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -76,3 +76,81 @@ export const tokenRequest = async(url, options = {}) => {
|
||||||
})
|
})
|
||||||
return requestObj
|
return requestObj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const lrcTools = {
|
||||||
|
rxps: {
|
||||||
|
wordLine: /^(\[\d{1,2}:.*\d{1,4}\])\s*(\S+(?:\s+\S+)*)?\s*/,
|
||||||
|
tagLine: /\[(ver|ti|ar|al|by|kuwo):\s*(\S+(?:\s+\S+)*)\s*\]/,
|
||||||
|
wordTimeAll: /<(-?\d+),(-?\d+)(?:,-?\d+)?>/g,
|
||||||
|
wordTime: /<(-?\d+),(-?\d+)(?:,-?\d+)?>/,
|
||||||
|
},
|
||||||
|
offset: 1,
|
||||||
|
offset2: 1,
|
||||||
|
isOK: false,
|
||||||
|
lines: [],
|
||||||
|
getWordInfo(str, str2) {
|
||||||
|
const offset = parseInt(str)
|
||||||
|
const offset2 = parseInt(str2)
|
||||||
|
const startTime = Math.floor((offset + offset2) / (this.offset * 2))
|
||||||
|
const timeLength = Math.floor((offset - offset2) / (this.offset2 * 2))
|
||||||
|
return {
|
||||||
|
startTime,
|
||||||
|
timeLength,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
parseLine(line) {
|
||||||
|
if (line.length < 6) return
|
||||||
|
let result = this.rxps.wordLine.exec(line)
|
||||||
|
if (result) {
|
||||||
|
const time = result[1]
|
||||||
|
let words = result[2]
|
||||||
|
if (words == null) {
|
||||||
|
words = ''
|
||||||
|
}
|
||||||
|
const wordTimes = words.match(this.rxps.wordTimeAll)
|
||||||
|
if (!wordTimes) {
|
||||||
|
this.isOK = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// console.log(wordTimes)
|
||||||
|
for (const timeStr of wordTimes) {
|
||||||
|
const result = this.rxps.wordTime.exec(timeStr)
|
||||||
|
const wordInfo = this.getWordInfo(result[1], result[2])
|
||||||
|
words = words.replace(timeStr, `<${wordInfo.startTime},${wordInfo.timeLength}>`)
|
||||||
|
}
|
||||||
|
this.lines.push(time + words)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result = this.rxps.tagLine.exec(line)
|
||||||
|
if (!result) return
|
||||||
|
if (result[1] == 'kuwo') {
|
||||||
|
let content = result[2]
|
||||||
|
if (content != null && content.includes('][')) {
|
||||||
|
content = content.substring(0, content.indexOf(']['))
|
||||||
|
}
|
||||||
|
const valueOf = parseInt(content, 8)
|
||||||
|
this.offset = Math.floor(valueOf / 10)
|
||||||
|
this.offset2 = Math.floor(valueOf % 10)
|
||||||
|
if (this.offset == 0 || Number.isNaN(this.offset) || this.offset2 == 0 || Number.isNaN(this.offset2)) {
|
||||||
|
this.isOK = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.lines.push(line)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
parse(lrc) {
|
||||||
|
const lines = lrc.split(/\r\n|\r|\n/)
|
||||||
|
const tools = Object.create(this)
|
||||||
|
tools.isOK = true
|
||||||
|
tools.offset = 1
|
||||||
|
tools.offset2 = 1
|
||||||
|
tools.lines = []
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
if (!tools.isOK) return ''
|
||||||
|
tools.parseLine(line)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tools.lines.length ? tools.lines.join('\n') : ''
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue