完成ktv歌词功能
parent
8992e316d0
commit
bae28fac35
File diff suppressed because one or more lines are too long
|
@ -223,11 +223,10 @@ table {overflow:auto;display:table;width:100%;line-height:2.5rem;
|
|||
|
||||
section {flex:1;display:flex;
|
||||
|
||||
&.left {justify-content:flex-start;
|
||||
|
||||
span {background: linear-gradient(to right, #ff0 25%, #fff 25%);;background-clip:text;color:transparent;}
|
||||
}
|
||||
&.left {justify-content:flex-start;}
|
||||
&.right {justify-content:flex-end}
|
||||
|
||||
span {background-clip:text!important;color:transparent;}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -124,10 +124,10 @@
|
|||
|
||||
<div class="lrc-box">
|
||||
<section class="left">
|
||||
<span>我有句话悄悄想对你说</span>
|
||||
<span :text="lrc.l.txt" :css="{background: lrc.l.bg}"></span>
|
||||
</section>
|
||||
<section class="right">
|
||||
<span>想着你成为我一种坏习惯</span>
|
||||
<span :text="lrc.r.txt" :css="{background: lrc.r.bg}"></span>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
|
27
js/app.js
27
js/app.js
|
@ -8,6 +8,7 @@ import '/lib/anot.next.js'
|
|||
import layer from '/lib/layer/index.js'
|
||||
import store from '/lib/store/index.js'
|
||||
import AudioPlayer from '/lib/audio/index.js'
|
||||
import Lyrics from '/lib/lyrics/index.js'
|
||||
|
||||
import Api from '/js/api.js'
|
||||
|
||||
|
@ -54,6 +55,7 @@ window.LS = store.collection('local')
|
|||
window.TS = store.collection('temp')
|
||||
// 音乐播放器
|
||||
window.SONIST = new AudioPlayer()
|
||||
window.LYRICS = new Lyrics()
|
||||
|
||||
let appInit = fs.cat(APP_INI_PATH)
|
||||
|
||||
|
@ -80,6 +82,11 @@ Anot({
|
|||
album: '',
|
||||
time: 0,
|
||||
duration: 0
|
||||
},
|
||||
ctrlLrc: '暂无歌词...',
|
||||
lrc: {
|
||||
l: { bg: '', txt: '' },
|
||||
r: { bg: '', txt: '' }
|
||||
}
|
||||
},
|
||||
skip: [],
|
||||
|
@ -136,6 +143,7 @@ Anot({
|
|||
let pp = (ax - 124) / (aw - 124)
|
||||
this.curr.time = pp * this.curr.duration
|
||||
SONIST.seek(this.curr.time)
|
||||
LYRICS.seek(this.curr.time)
|
||||
if (!this.isPlaying) {
|
||||
this.draw()
|
||||
}
|
||||
|
@ -150,12 +158,23 @@ Anot({
|
|||
|
||||
SONIST.on('play', time => {
|
||||
this.curr.time = time
|
||||
LYRICS.update(time)
|
||||
})
|
||||
|
||||
SONIST.on('end', time => {
|
||||
this.nextSong(1)
|
||||
})
|
||||
|
||||
// 控制条的单行歌词
|
||||
LYRICS.on('ctrl-lrc', lrc => {
|
||||
this.ctrlLrc = lrc
|
||||
})
|
||||
|
||||
// ktv模式的歌词
|
||||
LYRICS.on('ktv-lrc', lrc => {
|
||||
this.lrc = lrc
|
||||
})
|
||||
|
||||
this.activeModule(this.mod)
|
||||
|
||||
remote.app.on('browser-window-focus', _ => {
|
||||
|
@ -239,6 +258,7 @@ Anot({
|
|||
let wl = this.__HEIGHT__ + 180 // 文字的坐标X
|
||||
|
||||
let { time, duration, title, artist } = this.curr
|
||||
let lrc = this.ctrlLrc
|
||||
let pp = time / duration // 进度百分比
|
||||
time = Anot.filters.time(time)
|
||||
duration = Anot.filters.time(duration)
|
||||
|
@ -282,7 +302,7 @@ Anot({
|
|||
// 歌词
|
||||
this.__CTX__.fillStyle = COLORS[this.ktvMode].lrc
|
||||
this.__CTX__.font = '48px' + FONTS_NAME
|
||||
this.__CTX__.fillText(`暂无歌词...`, wl, 180)
|
||||
this.__CTX__.fillText(lrc, wl, 180)
|
||||
|
||||
// 进度条
|
||||
this.__CTX__.fillStyle = COLORS[this.ktvMode].bar1
|
||||
|
@ -361,9 +381,11 @@ Anot({
|
|||
// 此时仅更新播放控制条的信息即可
|
||||
if (song) {
|
||||
song.time = 0
|
||||
this.ctrlLrc = '暂无歌词...'
|
||||
this.updateCurr(song)
|
||||
this.isPlaying = true
|
||||
this.draw(true)
|
||||
LYRICS.__init__(song.lyrics)
|
||||
} else {
|
||||
if (SONIST.stat === 'ready') {
|
||||
let played = this.isPlaying
|
||||
|
@ -379,9 +401,12 @@ Anot({
|
|||
let lastPlay = Anot.ls('last-play') || 0
|
||||
SONIST.play(lastPlay).then(it => {
|
||||
it.time = 0
|
||||
this.ctrlLrc = '暂无歌词...'
|
||||
this.updateCurr(it)
|
||||
this.draw(true)
|
||||
// this.ktvMode = 1
|
||||
|
||||
LYRICS.__init__(it.lyrics)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
/**
|
||||
* 歌词模块
|
||||
* @author yutent<yutent@doui.cc>
|
||||
* @date 2019/01/04 16:25:25
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const log = console.log
|
||||
const fs = require('iofs')
|
||||
const { EventEmitter } = require('events')
|
||||
const util = require('util')
|
||||
|
||||
class Lyrics {
|
||||
__init__(lrcFile) {
|
||||
this.lib = []
|
||||
this.curr = []
|
||||
this.lrc = {
|
||||
l: { bg: '', txt: '' },
|
||||
r: { bg: '', txt: '' }
|
||||
}
|
||||
|
||||
if (!lrcFile || !fs.exists(lrcFile)) {
|
||||
return false
|
||||
}
|
||||
|
||||
let lrc = fs
|
||||
.cat(lrcFile)
|
||||
.toString('utf8')
|
||||
.split('\n')
|
||||
|
||||
this.lib = lrc
|
||||
.map(it => {
|
||||
if (it) {
|
||||
let matches = it.match(/^\[([0-9\.\:]+)\](.+)/)
|
||||
let time = matches[1]
|
||||
let txt = matches[2]
|
||||
time = time.split(/[:\.]/).map(t => +t)
|
||||
let start = time[0] * 60 + time[1] + time[2] / 100
|
||||
return { start, txt }
|
||||
}
|
||||
return
|
||||
})
|
||||
.filter(it => it)
|
||||
|
||||
for (let i = 0, it; (it = this.lib[i++]); ) {
|
||||
if (this.lib[i]) {
|
||||
it.duration = +(this.lib[i].start - it.start).toFixed(2)
|
||||
it.end = this.lib[i].start
|
||||
} else {
|
||||
it.duration = 3
|
||||
it.end = it.start + 3
|
||||
}
|
||||
}
|
||||
this.tmpLib = this.lib.concat()
|
||||
|
||||
return this.lib.length > 0
|
||||
}
|
||||
|
||||
seek(time) {
|
||||
this.tmpLib = []
|
||||
for (let it of this.lib) {
|
||||
if (it.start > time) {
|
||||
this.tmpLib.push(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update(time) {
|
||||
if (!this.curr.length && this.tmpLib.length) {
|
||||
this.curr = this.tmpLib.splice(0, 2)
|
||||
}
|
||||
let stat = 0
|
||||
|
||||
// 当前时间小于第1句的结束时间
|
||||
if (time <= this.curr[0].end) {
|
||||
// 如果第2句比第1句的时间要小,需要补新
|
||||
if (this.curr[1].start < this.curr[0].start && time > this.curr[1].end) {
|
||||
if (this.tmpLib.length) {
|
||||
this.curr[1] = this.tmpLib.shift()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (time < this.curr[1].end) {
|
||||
// 如果第1句比第2句的时间要小,需要补新
|
||||
if (this.curr[0].start < this.curr[1].start) {
|
||||
if (this.tmpLib.length) {
|
||||
this.curr[0] = this.tmpLib.shift()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.tmpLib.length) {
|
||||
this.curr = this.tmpLib.splice(0, 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stat = (this.curr[0].start < this.curr[1].start) ^ 1
|
||||
|
||||
this.lrc.l.txt = this.curr[0].txt
|
||||
this.lrc.r.txt = this.curr[1].txt
|
||||
|
||||
if (stat === 0) {
|
||||
let pp = (
|
||||
((time - this.curr[0].start) / this.curr[0].duration) *
|
||||
100
|
||||
).toFixed(2)
|
||||
this.lrc.l.bg = `linear-gradient(to right, #ff5061 ${pp}%, #fff ${pp}%)`
|
||||
this.lrc.r.bg = '#fff'
|
||||
this.emit('ctrl-lrc', this.lrc.l.txt)
|
||||
} else {
|
||||
let pp = (
|
||||
((time - this.curr[1].start) / this.curr[1].duration) *
|
||||
100
|
||||
).toFixed(2)
|
||||
this.lrc.l.bg = '#fff'
|
||||
this.lrc.r.bg = `linear-gradient(to right, #ff5061 ${pp}%, #fff ${pp}%)`
|
||||
this.emit('ctrl-lrc', this.lrc.r.txt)
|
||||
}
|
||||
|
||||
this.emit('ktv-lrc', this.lrc)
|
||||
}
|
||||
}
|
||||
|
||||
util.inherits(Lyrics, EventEmitter)
|
||||
|
||||
export default Lyrics
|
Reference in New Issue