修改桌面歌词为逐字播放

pull/459/head
lyswhut 2021-03-02 18:10:12 +08:00
parent 040fcfba4f
commit aef0ffa506
6 changed files with 152 additions and 53 deletions

14
package-lock.json generated
View File

@ -5084,7 +5084,7 @@
}, },
"buffer-crc32": { "buffer-crc32": {
"version": "0.2.13", "version": "0.2.13",
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "resolved": "https://registry.npm.taobao.org/buffer-crc32/download/buffer-crc32-0.2.13.tgz",
"integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
"dev": true "dev": true
}, },
@ -8736,7 +8736,7 @@
}, },
"fd-slicer": { "fd-slicer": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "resolved": "https://registry.npm.taobao.org/fd-slicer/download/fd-slicer-1.1.0.tgz",
"integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
"dev": true, "dev": true,
"requires": { "requires": {
@ -12191,7 +12191,7 @@
}, },
"pend": { "pend": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "resolved": "https://registry.npm.taobao.org/pend/download/pend-1.2.0.tgz",
"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
"dev": true "dev": true
}, },
@ -12208,7 +12208,7 @@
}, },
"pify": { "pify": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "resolved": "https://registry.npm.taobao.org/pify/download/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"dev": true, "dev": true,
"optional": true "optional": true
@ -13076,7 +13076,7 @@
}, },
"proto-list": { "proto-list": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", "resolved": "https://registry.npm.taobao.org/proto-list/download/proto-list-1.2.4.tgz",
"integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=",
"dev": true, "dev": true,
"optional": true "optional": true
@ -14095,7 +14095,7 @@
}, },
"semver-compare": { "semver-compare": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", "resolved": "https://registry.npm.taobao.org/semver-compare/download/semver-compare-1.0.0.tgz",
"integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=",
"dev": true, "dev": true,
"optional": true "optional": true
@ -17808,7 +17808,7 @@
}, },
"yauzl": { "yauzl": {
"version": "2.10.0", "version": "2.10.0",
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "resolved": "https://registry.npm.taobao.org/yauzl/download/yauzl-2.10.0.tgz",
"integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
"dev": true, "dev": true,
"requires": { "requires": {

View File

@ -1,7 +1,8 @@
<template lang="pug"> <template lang="pug">
div(:class="[$style.lyric, lyricEvent.isMsDown ? $style.draging : null]" :style="lrcStyles" @wheel="handleWheel" @mousedown="handleLyricMouseDown" ref="dom_lyric") div(:class="[$style.lyric, lyricEvent.isMsDown ? $style.draging : null]" :style="lrcStyles" @wheel="handleWheel" @mousedown="handleLyricMouseDown" ref="dom_lyric")
div(:class="$style.lyricSpace") 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]") div(:class="[$style.lyricText]" ref="dom_lyric_text")
//- 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}} p(:class="$style.lrcLine") {{info.text}}
div(:class="$style.lyricSpace") div(:class="$style.lyricSpace")
</template> </template>
@ -9,7 +10,7 @@ div(:class="[$style.lyric, lyricEvent.isMsDown ? $style.draging : null]" :style=
<script> <script>
import { rendererOn, rendererSend, NAMES } from '../../../common/ipc' import { rendererOn, rendererSend, NAMES } from '../../../common/ipc'
import { scrollTo } from '../../../renderer/utils' import { scrollTo } from '../../../renderer/utils'
import Lyric from 'lrc-file-parser' import Lyric from '@renderer/utils/lyric-font-player'
let cancelScrollFn = null let cancelScrollFn = null
@ -65,6 +66,7 @@ export default {
lyrics: { lyrics: {
lyric: '', lyric: '',
tlyric: '', tlyric: '',
lxlyric: '',
}, },
} }
}, },
@ -85,7 +87,7 @@ export default {
if (n.length) { if (n.length) {
this.lyricLines = n this.lyricLines = n
this.$nextTick(() => { this.$nextTick(() => {
this.dom_lines = this.$refs.dom_lyric.querySelectorAll('p') this.dom_lines = this.$refs.dom_lyric.querySelectorAll('.lrc-content')
this.handleScrollLrc() this.handleScrollLrc()
}) })
} else { } else {
@ -97,7 +99,7 @@ export default {
if (this.lyricLines === this._lyricLines && this._lyricLines.length) return if (this.lyricLines === this._lyricLines && this._lyricLines.length) return
this.lyricLines = this._lyricLines this.lyricLines = this._lyricLines
this.$nextTick(() => { this.$nextTick(() => {
this.dom_lines = this.$refs.dom_lyric.querySelectorAll('p') this.dom_lines = this.$refs.dom_lyric.querySelectorAll('.lrc-content')
this.handleScrollLrc() this.handleScrollLrc()
}) })
}, 50) }, 50)
@ -105,7 +107,7 @@ export default {
} else { } else {
this.lyricLines = n this.lyricLines = n
this.$nextTick(() => { this.$nextTick(() => {
this.dom_lines = this.$refs.dom_lyric.querySelectorAll('p') this.dom_lines = this.$refs.dom_lyric.querySelectorAll('.lrc-content')
this.handleScrollLrc() this.handleScrollLrc()
}) })
} }
@ -129,6 +131,10 @@ export default {
created() { created() {
rendererOn(NAMES.winLyric.set_lyric_info, (event, data) => this.handleSetInfo(data)) rendererOn(NAMES.winLyric.set_lyric_info, (event, data) => this.handleSetInfo(data))
window.lrc = new Lyric({ window.lrc = new Lyric({
className: 'lrc-content',
shadowClassName: 'shadow',
shadowContent: true,
activeLineClassName: 'active',
onPlay: (line, text) => { onPlay: (line, text) => {
this.lyric.text = text this.lyric.text = text
this.lyric.line = line this.lyric.line = line
@ -136,6 +142,12 @@ export default {
}, },
onSetLyric: lines => { // listening lyrics seting event onSetLyric: lines => { // listening lyrics seting event
// console.log(lines) // lines is array of all lyric text // console.log(lines) // lines is array of all lyric text
this.$refs.dom_lyric_text.textContent = ''
const dom_lines = document.createDocumentFragment()
for (const line of lines) {
dom_lines.appendChild(line.dom_line)
}
this.$refs.dom_lyric_text.appendChild(dom_lines)
this.lyric.lines = lines this.lyric.lines = lines
this.lyric.line = 0 this.lyric.line = 0
}, },
@ -159,6 +171,7 @@ export default {
case 'lyric': case 'lyric':
this.lyrics.lyric = data.lrc this.lyrics.lyric = data.lrc
this.lyrics.tlyric = data.tlrc this.lyrics.tlyric = data.tlrc
this.lyrics.lxlyric = data.lxlrc
this.setLyric() this.setLyric()
break break
case 'play': case 'play':
@ -171,8 +184,9 @@ export default {
break break
case 'info': case 'info':
// console.log('info', data) // console.log('info', data)
this.lyrics.lyric = data.lyric this.lyrics.lyric = data.lrc
this.lyrics.tlyric = data.tlyric this.lyrics.tlyric = data.tlrc
this.lyrics.lxlyric = data.lxlrc
this.setLyric() this.setLyric()
this.$nextTick(() => { this.$nextTick(() => {
this.lyric.line = data.line this.lyric.line = data.line
@ -279,7 +293,10 @@ export default {
rendererSend(NAMES.winLyric.close) rendererSend(NAMES.winLyric.close)
}, },
setLyric() { setLyric() {
window.lrc.setLyric((this.isShowLyricTransition && this.lyrics.tlyric ? (this.lyrics.tlyric + '\n') : '') + (this.lyrics.lyric || '')) window.lrc.setLyric(
this.lyrics.lxlyric ? this.lyrics.lxlyric : this.lyrics.lyric,
// (this.isShowLyricTransition && this.lyrics.tlyric ? (this.lyrics.tlyric + '\n') : '') + (this.lyrics.lyric || ''),
)
}, },
}, },
} }
@ -292,34 +309,77 @@ export default {
text-align: center; text-align: center;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
font-size: 68px; font-size: 16px;
padding: 0 5px; cursor: grab;
opacity: .6; color: @color-theme-lyric;
transition: opacity @transition-theme;
&.draging { &.draging {
.lrc-line { cursor: grabbing;
cursor: grabbing; }
:global {
.lrc-content {
line-height: 1.2;
margin: 16px 0;
overflow-wrap: break-word;
.line {
transition-property: font-size, color !important;
background: none !important;
-webkit-text-fill-color: unset;
// -webkit-text-fill-color: none !important;
}
&.active {
.line {
color: @color-theme;
}
span {
// color: @color-theme;
font-size: 1.2em;
}
}
span {
transition: @transition-theme !important;
transition-property: font-size !important;
font-size: 1em;
background-repeat: no-repeat;
background-color: @color-theme-lyric;
background-image: -webkit-linear-gradient(top, @color-theme, @color-theme);
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
background-size: 0 100%;
}
}
.shadow {
text-shadow: 1px 1px 2px rgb(32, 32, 32);
} }
} }
// p {
// padding: 8px 0;
// line-height: 1.2;
// overflow-wrap: break-word;
// transition: @transition-theme !important;
// transition-property: color, font-size;
// }
} }
.lrc-line { // .lrc-line {
display: inline-block; // display: inline-block;
padding: 8px 0; // padding: 8px 0;
line-height: 1.2; // line-height: 1.2;
overflow-wrap: break-word; // overflow-wrap: break-word;
transition: @transition-theme; // transition: @transition-theme;
transition-property: color, font-size, text-shadow; // transition-property: color, font-size, text-shadow;
cursor: grab; // cursor: grab;
// font-weight: bold; // // font-weight: bold;
// background-clip: text; // // background-clip: text;
color: @color-theme-lyric; // color: @color-theme-lyric;
text-shadow: 1px 1px 2px #000; // text-shadow: 1px 1px 2px #000;
// background: linear-gradient(@color-theme-lyric, @color-theme-lyric); // // background: linear-gradient(@color-theme-lyric, @color-theme-lyric);
// background-clip: text; // // background-clip: text;
// -webkit-background-clip: text; // // -webkit-background-clip: text;
// -webkit-text-fill-color: #fff; // // -webkit-text-fill-color: #fff;
// -webkit-text-stroke: thin #124628; // // -webkit-text-stroke: thin #124628;
} // }
.lyric-space { .lyric-space {
height: 70%; height: 70%;
} }
@ -348,14 +408,30 @@ export default {
each(@themes, { each(@themes, {
:global(#container.@{value}) { :global(#container.@{value}) {
.lrc-line { // .lrc-line {
color: ~'@{color-@{value}-theme-lyric}'; // color: ~'@{color-@{value}-theme-lyric}';
} // }
.lrc-active, .lrc-active-zoom { .lrc-active, .lrc-active-zoom {
.lrc-line { .lrc-line {
color: ~'@{color-@{value}-theme-lyric_2}'; color: ~'@{color-@{value}-theme-lyric_2}';
} }
} }
.lyric {
color: ~'@{color-@{value}-theme-lyric}';
:global {
.lrc-content {
&.active {
.line {
color: ~'@{color-@{value}-theme}';
}
}
span {
// background-color: ~'@{color-@{value}-theme_2-font}';
background-image: -webkit-linear-gradient(top, ~'@{color-@{value}-theme}', ~'@{color-@{value}-theme}');
}
}
}
}
} }
}) })

View File

@ -215,8 +215,9 @@ export default {
singer: this.musicInfo.singer, singer: this.musicInfo.singer,
name: this.musicInfo.name, name: this.musicInfo.name,
album: this.musicInfo.album, album: this.musicInfo.album,
lyric: this.musicInfo.lrc, lrc: this.musicInfo.lrc,
tlyric: this.musicInfo.tlrc, tlrc: this.musicInfo.tlrc,
lxlrc: this.musicInfo.lxlrc,
isPlay: this.isPlay, isPlay: this.isPlay,
line: this.lyric.line, line: this.lyric.line,
played_time: audio.currentTime * 1000, played_time: audio.currentTime * 1000,
@ -648,7 +649,7 @@ export default {
}).catch(() => { }).catch(() => {
this.status = this.statusText = this.$t('core.player.lyric_error') this.status = this.statusText = this.$t('core.player.lyric_error')
}).finally(() => { }).finally(() => {
this.handleUpdateWinLyricInfo('lyric', { lrc: this.musicInfo.lrc, tlrc: this.musicInfo.tlrc }) this.handleUpdateWinLyricInfo('lyric', { lrc: this.musicInfo.lrc, tlrc: this.musicInfo.tlrc, lxlrc: this.musicInfo.lxlrc })
this.setLyric() this.setLyric()
}) })
}, },

View File

@ -579,16 +579,26 @@ export default {
overflow: hidden; overflow: hidden;
font-size: 16px; font-size: 16px;
cursor: grab; cursor: grab;
color: @color-theme_2-font;
&.draging { &.draging {
cursor: grabbing; cursor: grabbing;
} }
:global { :global {
.lrc-content { .lrc-content {
line-height: 1.2; line-height: 1.2;
padding: 8px 0; margin: 16px 0;
overflow-wrap: break-word; overflow-wrap: break-word;
.line {
transition-property: font-size, color !important;
background: none !important;
-webkit-text-fill-color: unset;
// -webkit-text-fill-color: none !important;
}
&.active { &.active {
.line {
color: @color-theme;
}
span { span {
// color: @color-theme; // color: @color-theme;
font-size: 1.2em; font-size: 1.2em;
@ -597,7 +607,7 @@ export default {
span { span {
transition: @transition-theme !important; transition: @transition-theme !important;
transition-property: font-size; transition-property: font-size !important;
font-size: 1em; font-size: 1em;
background-repeat: no-repeat; background-repeat: no-repeat;
background-color: rgba(77, 77, 77, 0.9); background-color: rgba(77, 77, 77, 0.9);
@ -810,11 +820,18 @@ each(@themes, {
box-shadow: 0 0 4px ~'@{color-@{value}-theme-hover}'; box-shadow: 0 0 4px ~'@{color-@{value}-theme-hover}';
// border-color: ~'@{color-@{value}-theme-hover}'; // border-color: ~'@{color-@{value}-theme-hover}';
} }
:global { .lyric {
.lrc-content { :global {
span { .lrc-content {
// background-color: ~'@{color-@{value}-theme_2-font}'; &.active {
background-image: -webkit-linear-gradient(top, ~'@{color-@{value}-theme}', ~'@{color-@{value}-theme}'); .line {
color: ~'@{color-@{value}-theme}';
}
}
span {
// background-color: ~'@{color-@{value}-theme_2-font}';
background-image: -webkit-linear-gradient(top, ~'@{color-@{value}-theme}', ~'@{color-@{value}-theme}');
}
} }
} }
} }

View File

@ -20,10 +20,11 @@ const createAnimation = (dom, duration) => new window.Animation(new window.Keyfr
// https://jsfiddle.net/ceqpnbky/1/ // https://jsfiddle.net/ceqpnbky/1/
module.exports = class FontPlayer { module.exports = class FontPlayer {
constructor({ lyric = '', className = '', shadowContent = false, shadowClassName = '' }) { constructor({ lyric = '', className = '', lineModeClassName = '', shadowContent = false, shadowClassName = '' }) {
this.lyric = lyric this.lyric = lyric
this.className = className this.className = className
this.lineModeClassName = lineModeClassName
this.shadowContent = shadowContent this.shadowContent = shadowContent
this.shadowClassName = shadowClassName this.shadowClassName = shadowClassName
@ -100,6 +101,7 @@ module.exports = class FontPlayer {
this.isLineMode = true this.isLineMode = true
const dom = document.createElement('span') const dom = document.createElement('span')
let shadowDom let shadowDom
dom.classList.add(this.lineModeClassName)
dom.textContent = this.lyric dom.textContent = this.lyric
if (this.shadowContent) { if (this.shadowContent) {
shadowDom = document.createElement('span') shadowDom = document.createElement('span')

View File

@ -9,6 +9,7 @@ module.exports = class Lyric {
offset = 150, offset = 150,
className = '', className = '',
activeLineClassName = 'active', activeLineClassName = 'active',
lineModeClassName = 'line',
shadowClassName = '', shadowClassName = '',
shadowContent = false, shadowContent = false,
onPlay = function() { }, onPlay = function() { },
@ -21,6 +22,7 @@ module.exports = class Lyric {
this.className = className this.className = className
this.activeLineClassName = activeLineClassName this.activeLineClassName = activeLineClassName
this.lineModeClassName = lineModeClassName
this.shadowClassName = shadowClassName this.shadowClassName = shadowClassName
this.shadowContent = shadowContent this.shadowContent = shadowContent
@ -98,6 +100,7 @@ module.exports = class Lyric {
const fontPlayer = new FontPlayer({ const fontPlayer = new FontPlayer({
lyric: line.text, lyric: line.text,
className: this.className, className: this.className,
lineModeClassName: this.lineModeClassName,
shadowClassName: this.shadowClassName, shadowClassName: this.shadowClassName,
shadowContent: this.shadowContent, shadowContent: this.shadowContent,
}) })