Files
Melo/src/renderer-lyric/components/core/Lyric.vue
T

363 lines
9.9 KiB
Vue

<template lang="pug">
div(:class="[$style.lyric, lyricEvent.isMsDown ? $style.draging : null]" :style="lrcStyles" @wheel="handleWheel" @mousedown="handleLyricMouseDown" ref="dom_lyric")
div(:class="$style.lyricSpace")
div(v-for="(info, index) in lyricLines" :key="index" :class="[$style.lineContent, lyric.line == index ? (lrcConfig.style.isZoomActiveLrc ? $style.lrcActiveZoom : $style.lrcActive) : null]")
p(:class="$style.lrcLine") {{info.text}}
div(:class="$style.lyricSpace")
</template>
<script>
import { rendererOn, rendererSend, NAMES } from '../../../common/ipc'
import { scrollTo } from '../../../renderer/utils'
import Lyric from 'lrc-file-parser'
let cancelScrollFn = null
export default {
props: {
lrcConfig: {
type: Object,
default() {
return {
style: {
fontSize: 125,
opacity: 80,
isZoomActiveLrc: true,
},
}
},
},
isShowLyricTransition: {
type: Boolean,
default: true,
},
},
data() {
return {
musicInfo: {
songmid: null,
name: '^',
singer: '^',
album: null,
},
lyric: {
line: 0,
lines: [],
},
dom_lines: [],
clickTime: 0,
lyricEvent: {
isMsDown: false,
msDownY: 0,
msDownScrollY: 0,
isStopScroll: false,
timeout: null,
},
winEvent: {
isMsDown: false,
msDownX: 0,
msDownY: 0,
},
_lyricLines: [],
lyricLines: [],
isSetedLines: false,
isPlay: false,
lyrics: {
lyric: '',
tlyric: '',
},
}
},
computed: {
lrcStyles() {
return {
fontSize: this.lrcConfig.style.fontSize / 100 + 'rem',
opacity: this.lrcConfig.style.opacity / 100,
}
},
},
watch: {
'lyric.lines': {
handler(n, o) {
this.isSetedLines = true
if (o) {
this._lyricLines = n
if (n.length) {
this.lyricLines = n
this.$nextTick(() => {
this.dom_lines = this.$refs.dom_lyric.querySelectorAll('p')
this.handleScrollLrc()
})
} else {
if (cancelScrollFn) {
cancelScrollFn()
cancelScrollFn = null
}
cancelScrollFn = scrollTo(this.$refs.dom_lyric, 0, 300, () => {
if (this.lyricLines === this._lyricLines && this._lyricLines.length) return
this.lyricLines = this._lyricLines
this.$nextTick(() => {
this.dom_lines = this.$refs.dom_lyric.querySelectorAll('p')
this.handleScrollLrc()
})
}, 50)
}
} else {
this.lyricLines = n
this.$nextTick(() => {
this.dom_lines = this.$refs.dom_lyric.querySelectorAll('p')
this.handleScrollLrc()
})
}
},
immediate: true,
},
'lyric.line': {
handler(n) {
if (n < 0) return
if (n == 0 && this.isSetedLines) return this.isSetedLines = false
this.handleScrollLrc()
},
immediate: true,
},
isShowLyricTransition(n) {
console.log(n)
this.setLyric()
rendererSend(NAMES.winLyric.get_lyric_info, 'status')
},
},
created() {
rendererOn(NAMES.winLyric.set_lyric_info, (event, data) => this.handleSetInfo(data))
window.lrc = new Lyric({
onPlay: (line, text) => {
this.lyric.text = text
this.lyric.line = line
// console.log(line, text)
},
onSetLyric: lines => { // listening lyrics seting event
// console.log(lines) // lines is array of all lyric text
this.lyric.lines = lines
this.lyric.line = 0
},
offset: 100,
})
},
mounted() {
document.addEventListener('mousemove', this.handleMouseMsMove)
document.addEventListener('mouseup', this.handleMouseMsUp)
rendererSend(NAMES.winLyric.get_lyric_info, 'info')
},
beforeDestroy() {
this.clearLyricScrollTimeout()
document.removeEventListener('mousemove', this.handleMouseMsMove)
document.removeEventListener('mouseup', this.handleMouseMsUp)
},
methods: {
handleSetInfo({ type, data }) {
// console.log(type, data)
switch (type) {
case 'lyric':
this.lyrics.lyric = data.lrc
this.lyrics.tlyric = data.tlrc
this.setLyric()
break
case 'play':
this.isPlay = true
window.lrc.play(data)
break
case 'pause':
this.isPlay = false
window.lrc.pause()
break
case 'info':
// console.log('info', data)
this.lyrics.lyric = data.lyric
this.lyrics.tlyric = data.tlyric
this.setLyric()
this.$nextTick(() => {
this.lyric.line = data.line
rendererSend(NAMES.winLyric.get_lyric_info, 'status')
})
case 'music_info':
this.musicInfo.name = data.name
this.musicInfo.songmid = data.songmid
this.musicInfo.singer = data.singer
this.musicInfo.album = data.album
break
case 'status':
// console.log('status', data)
this.isPlay = data.isPlay
this.lyric.line = data.line
if (data.isPlay) window.lrc.play(data.played_time)
break
default:
break
}
// console.log(data)
},
handleResize() {
this.setProgressWidth()
},
handleScrollLrc() {
if (!this.dom_lines.length) return
if (cancelScrollFn) {
cancelScrollFn()
cancelScrollFn = null
}
if (this.lyricEvent.isStopScroll) return
let dom_p = this.dom_lines[this.lyric.line]
cancelScrollFn = scrollTo(this.$refs.dom_lyric, dom_p ? (dom_p.offsetTop - this.$refs.dom_lyric.clientHeight * 0.5 + dom_p.clientHeight / 2) : 0)
},
handleLyricMouseDown(e) {
if (e.target.classList.contains(this.$style.lrcLine)) {
this.lyricEvent.isMsDown = true
this.lyricEvent.msDownY = e.clientY
this.lyricEvent.msDownScrollY = this.$refs.dom_lyric.scrollTop
} else {
this.winEvent.isMsDown = true
this.winEvent.msDownX = e.clientX
this.winEvent.msDownY = e.clientY
}
},
handleMouseMsUp(e) {
this.lyricEvent.isMsDown = false
this.winEvent.isMsDown = false
},
handleMouseMsMove(e) {
if (this.lyricEvent.isMsDown) {
if (!this.lyricEvent.isStopScroll) this.lyricEvent.isStopScroll = true
if (cancelScrollFn) {
cancelScrollFn()
cancelScrollFn = null
}
this.$refs.dom_lyric.scrollTop = this.lyricEvent.msDownScrollY + this.lyricEvent.msDownY - e.clientY
this.startLyricScrollTimeout()
} else if (this.winEvent.isMsDown) {
rendererSend(NAMES.winLyric.set_win_bounds, {
x: e.clientX - this.winEvent.msDownX,
y: e.clientY - this.winEvent.msDownY,
w: window.innerWidth,
h: window.innerHeight,
})
}
// if (this.volumeEvent.isMsDown) {
// let val = this.volumeEvent.msDownValue + (e.clientX - this.volumeEvent.msDownX) / 70
// this.volume = val < 0 ? 0 : val > 1 ? 1 : val
// if (this.audio) this.audio.volume = this.volume
// }
// console.log(val)
},
startLyricScrollTimeout() {
this.clearLyricScrollTimeout()
this.lyricEvent.timeout = setTimeout(() => {
this.lyricEvent.timeout = null
this.lyricEvent.isStopScroll = false
if (!this.isPlay) return
this.handleScrollLrc()
}, 3000)
},
handleWheel(event) {
// console.log(event.deltaY)
if (!this.lyricEvent.isStopScroll) this.lyricEvent.isStopScroll = true
if (cancelScrollFn) {
cancelScrollFn()
cancelScrollFn = null
}
this.$refs.dom_lyric.scrollTop = this.$refs.dom_lyric.scrollTop + event.deltaY
this.startLyricScrollTimeout()
},
clearLyricScrollTimeout() {
if (!this.lyricEvent.timeout) return
clearTimeout(this.lyricEvent.timeout)
this.lyricEvent.timeout = null
},
close() {
rendererSend(NAMES.winLyric.close)
},
setLyric() {
window.lrc.setLyric((this.isShowLyricTransition && this.lyrics.tlyric ? (this.lyrics.tlyric + '\n') : '') + (this.lyrics.lyric || ''))
},
},
}
</script>
<style lang="less" module>
@import '../../assets/styles/layout.less';
.lyric {
text-align: center;
height: 100%;
overflow: hidden;
font-size: 68px;
padding: 0 5px;
opacity: .6;
transition: opacity @transition-theme;
&.draging {
.lrc-line {
cursor: grabbing;
}
}
}
.lrc-line {
display: inline-block;
padding: 8px 0;
line-height: 1.2;
overflow-wrap: break-word;
transition: @transition-theme;
transition-property: color, font-size, text-shadow;
cursor: grab;
// font-weight: bold;
// background-clip: text;
color: @color-theme-lyric;
text-shadow: 1px 1px 2px #000;
// background: linear-gradient(@color-theme-lyric, @color-theme-lyric);
// background-clip: text;
// -webkit-background-clip: text;
// -webkit-text-fill-color: #fff;
// -webkit-text-stroke: thin #124628;
}
.lyric-space {
height: 70%;
}
.lrc-active {
.lrc-line {
color: @color-theme-lyric_2;
// background: linear-gradient(@color-theme-lyric, @color-theme-lyric_2);
// background-clip: text;
// -webkit-background-clip: text;
// -webkit-text-fill-color: @color-theme-lyric_2;
// -webkit-text-stroke: thin #124628;
}
}
.lrc-active-zoom {
.lrc-active;
font-size: 1.2em;
}
.footer {
flex: 0 0 100px;
overflow: hidden;
display: flex;
align-items: center;
}
each(@themes, {
:global(#container.@{value}) {
.lrc-line {
color: ~'@{color-@{value}-theme-lyric}';
}
.lrc-active, .lrc-active-zoom {
.lrc-line {
color: ~'@{color-@{value}-theme-lyric_2}';
}
}
}
})
</style>