mirror of
https://github.com/imsyy/home.git
synced 2025-06-01 03:10:17 +09:00
fix(yrc): 移动位置并改为使用watch实现
又是手欠点了格式化的一天
This commit is contained in:
parent
33b21b3be7
commit
2d5a4fdfe3
@ -51,21 +51,27 @@
|
||||
<paw />
|
||||
</Icon> -->
|
||||
<span class="yrc-box">
|
||||
<span class="yrc-2 lrc-text text-hidden" id="yrc-2-wrap">
|
||||
<span v-for="i in store.playerLrc" :key="`lrc-over-char-${i[2]}-${i[3]}`" v-html="i[4]">
|
||||
</span>
|
||||
<span class="yrc-2 lrc-text text-hidden" id="yrc-2-wrap">
|
||||
<span v-for="i in store.playerLrc" :key="`lrc-over-char-${i[2]}-${i[3]}`" v-html="i[4]">
|
||||
</span>
|
||||
<span class="yrc-1 lrc-text text-hidden" id="yrc-1-wrap">
|
||||
<span v-for="i in store.playerLrc" :key="`lrc-char-${i[2]}-${i[3]}`" :class="[
|
||||
'yrc-char',
|
||||
i[0] && Number(i[6]) > 0 ? 'fade-in' : 'fade-in-start',
|
||||
i[0] && Number(i[5]) > 1019 && Number(i[6]) > 0 ? 'long-tone' : 'fade-in-start',
|
||||
i[0] && Number(i[6]) <= 0 ? 'fade-out' : '',
|
||||
i[1] ? 'yrc-style-s2' : 'yrc-style-s1'
|
||||
]" :id="`lrc-char-${i[2]}-${i[3]}`" v-html="i[4]">
|
||||
</span>
|
||||
</span>
|
||||
<span class="yrc-1 lrc-text text-hidden" id="yrc-1-wrap">
|
||||
<span v-for="i in store.playerLrc" :key="`lrc-char-${i[2]}-${i[3]}`" :class="[
|
||||
'yrc-char',
|
||||
i[0] && Number(i[6]) > 0 ? 'fade-in' : 'fade-in-start',
|
||||
i[0] && Number(i[5]) > 1019 && Number(i[6]) > 0 ? 'long-tone' : 'fade-in-start',
|
||||
i[0] && Number(i[6]) <= 0 ? 'fade-out' : '',
|
||||
i[1] ? 'yrc-style-s2' : 'yrc-style-s1'
|
||||
]" :id="`lrc-char-${i[2]}-${i[3]}`" v-html="i[4]">
|
||||
</span>
|
||||
</span>
|
||||
<!-- <span class="yrc-2 lrc-text text-hidden" id="yrc-2-wrap">
|
||||
<span v-for="i in store.playerLrc" :key="`lrc-over-char-${i[2]}-${i[3]}`" v-html="i[4]" />
|
||||
</span>
|
||||
<span class="yrc-1 lrc-text text-hidden" id="yrc-1-wrap">
|
||||
<span v-for="i in store.playerLrc" :key="`lrc-char-${i[2]}-${i[3]}`" v-html="i[4]" />
|
||||
</span> -->
|
||||
</span>
|
||||
<!-- <Icon size="20" style="transform: rotate(18deg);" class="paws-2">
|
||||
<paw />
|
||||
</Icon> -->
|
||||
@ -96,17 +102,18 @@
|
||||
|
||||
<script setup>
|
||||
import { MusicOne } from "@icon-park/vue-next";
|
||||
import { Icon } from "@vicons/utils";
|
||||
import { Paw } from "@vicons/ionicons5";
|
||||
// import { Icon } from "@vicons/utils";
|
||||
// import { Paw } from "@vicons/ionicons5";
|
||||
import { mainStore } from "@/store";
|
||||
import config from "@/../package.json";
|
||||
import { ref, watch, computed, onMounted, nextTick } from "vue";
|
||||
import { ref, watch, computed, onMounted, nextTick, onUpdated } from "vue";
|
||||
|
||||
const store = mainStore();
|
||||
|
||||
const fullYear = new Date().getFullYear();
|
||||
const lrcContainer = ref(null);
|
||||
const scrollPosition = ref(0);
|
||||
const currentLine = ref(0);
|
||||
// const lrcContainer = ref(null);
|
||||
// const scrollPosition = ref(0);
|
||||
// const currentLine = ref(0);
|
||||
const showProgressIcon = ref(false);
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
@ -191,6 +198,75 @@ const progressBarWidth = computed(() => {
|
||||
if (!store.playerState) return 0;
|
||||
return (store.playerCurrentTime / store.playerDuration) * 100;
|
||||
});
|
||||
|
||||
// yrc part
|
||||
watch(() => store.getPlayerLrc, (_new,_old) => {
|
||||
const isLineByLine = !store.yrcEnable || store.yrcTemp.length == 0 || store.yrcLoading
|
||||
if (!store.playerYrcShowPro || isLineByLine) {
|
||||
return
|
||||
};
|
||||
|
||||
// const now = player.value.audioStatus.playedTime * 1000;
|
||||
const audio = document.querySelector('audio')
|
||||
if (audio == undefined) {
|
||||
return
|
||||
}
|
||||
const now = audio.currentTime * 1000;
|
||||
const yrc2 = document.getElementsByClassName("yrc-box")[0];
|
||||
if (yrc2 == undefined) {
|
||||
return;
|
||||
};
|
||||
const outputDom = yrc2.querySelectorAll("#yrc-2-wrap span");
|
||||
const inputDom = yrc2.querySelectorAll("#yrc-1-wrap span");
|
||||
if (inputDom.length == 0 || outputDom.length == 0) {
|
||||
return;
|
||||
};
|
||||
// console.log(store.yrcTemp[0][0])
|
||||
const yrcFiltered = store.yrcTemp.filter((i) => i[0] < now && now < i[0] + i[1]);
|
||||
if (yrcFiltered.length == 0) {
|
||||
// console.log('h')
|
||||
return;
|
||||
};
|
||||
const nowLine = yrcFiltered[yrcFiltered.length - 1][2]
|
||||
// console.log(nowLine)
|
||||
for (let i = 0; i < nowLine.length; i++) {
|
||||
// console.log(JSON.stringify(nowLine[i]))
|
||||
const [[start, duration], _a, _b, _c] = nowLine[i];
|
||||
const inputItem = inputDom[i];
|
||||
if (!inputItem || inputItem.hasAttribute('data-start')) {
|
||||
return;
|
||||
};
|
||||
const computedStyle = window.getComputedStyle(inputItem);
|
||||
const width = parseFloat(computedStyle.width);
|
||||
if (isNaN(width)) {
|
||||
inputItem.removeAttribute('data-start');
|
||||
return;
|
||||
};
|
||||
const outputItem = outputDom[i];
|
||||
const animateOptions = {
|
||||
delay: Math.max(0, start - now),
|
||||
duration: duration,
|
||||
fill: "forwards",
|
||||
easing: "linear",
|
||||
};
|
||||
outputItem.style.transform = "translateY(-1px)"
|
||||
const outputAnimate = outputItem.animate(
|
||||
[
|
||||
{ width: 0 },
|
||||
{ width: `${width}px` },
|
||||
],
|
||||
animateOptions,
|
||||
);
|
||||
// animationTmp.push(outputAnimate);
|
||||
outputAnimate.onfinish = () => {
|
||||
outputItem.style.transform = "translateY(1px)";
|
||||
// animationTmp = animationTmp.filter(a => a !== outputAnimate);
|
||||
};
|
||||
inputItem.setAttribute("data-start",true)
|
||||
};
|
||||
})
|
||||
|
||||
// setInterval(yrcPro, 50);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -1,8 +1,24 @@
|
||||
<template>
|
||||
<APlayer v-if="playList[0]" ref="player" :audio="playList" :autoplay="store.playerAutoplay" :theme="theme"
|
||||
:autoSwitch="false" :loop="store.playerLoop" :order="store.playerOrder" :volume="volume" :showLrc="true"
|
||||
:listFolded="listFolded" :listMaxHeight="listMaxHeight" :noticeSwitch="false" @play="onPlay" @pause="onPause"
|
||||
@timeupdate="onTimeUp" @error="loadMusicError" />
|
||||
<APlayer
|
||||
v-if="playList[0]"
|
||||
ref="player"
|
||||
:audio="playList"
|
||||
:autoplay="store.playerAutoplay"
|
||||
:theme="theme"
|
||||
:autoSwitch="false"
|
||||
:loop="store.playerLoop"
|
||||
:order="store.playerOrder"
|
||||
:volume="volume"
|
||||
:showLrc="true"
|
||||
:listFolded="listFolded"
|
||||
:listMaxHeight="listMaxHeight"
|
||||
:noticeSwitch="false"
|
||||
@play="onPlay"
|
||||
@pause="onPause"
|
||||
@timeupdate="onTimeUp"
|
||||
@error="loadMusicError"
|
||||
@loadstart="onLoadStart"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@ -96,7 +112,7 @@ onMounted(() => {
|
||||
navigator.mediaSession.setActionHandler("previoustrack", () => {
|
||||
changeSong(0); // 0 表示上一首
|
||||
});
|
||||
};
|
||||
}
|
||||
console.log("音乐加载完成");
|
||||
});
|
||||
} catch (err) {
|
||||
@ -115,11 +131,82 @@ onMounted(() => {
|
||||
const voice = import.meta.env.VITE_TTS_Voice;
|
||||
const vstyle = import.meta.env.VITE_TTS_Style;
|
||||
SpeechLocal("播放器加载失败.mp3");
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const fetchYrc = async (yrcUrl) => {
|
||||
const yrcSource = await fetch(yrcUrl);
|
||||
const yrcText = await yrcSource.text();
|
||||
store.yrcIndex = playIndex.value;
|
||||
if (yrcText.startsWith("[ch:0]")) {
|
||||
store.yrcEnable = true;
|
||||
store.yrcTemp = decodeYrc(yrcText);
|
||||
store.yrcLoading = false;
|
||||
return;
|
||||
} else if (!store.playerYrcATDB) {
|
||||
store.yrcEnable = false;
|
||||
store.yrcTemp = [];
|
||||
store.yrcLoading = false;
|
||||
return;
|
||||
}
|
||||
// 接入 AMLL TTML Database
|
||||
const songUrlInf = new URLSearchParams(new URL(yrcUrl).search);
|
||||
const songId = songUrlInf.get("id");
|
||||
const songServer = songUrlInf.get("server");
|
||||
if (!songId) {
|
||||
return;
|
||||
}
|
||||
const songUrlInfUrl = store.playerYrcATDBF
|
||||
? {
|
||||
netease: `https://ghp.ci/https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/ncm-lyrics/${songId}.yrc`,
|
||||
tencent: `https://ghp.ci/https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/qq-lyrics/${songId}.qrc`,
|
||||
}
|
||||
: {
|
||||
netease: `https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/ncm-lyrics/${songId}.yrc`,
|
||||
tencent: `https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/qq-lyrics/${songId}.qrc`,
|
||||
};
|
||||
if (!["netease", "tencent"].includes(songServer)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const amllUrl = songUrlInfUrl[songServer].replace("${songIdlrc}", songId);
|
||||
const amllSource = await fetch(amllUrl);
|
||||
const amllText = await amllSource.text();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
store.yrcEnable = true;
|
||||
store.yrcTemp = decodeYrc(amllText);
|
||||
store.yrcLoading = false;
|
||||
}
|
||||
};
|
||||
|
||||
function onLoadStart() {
|
||||
try {
|
||||
const aplayer = player.value.aplayer;
|
||||
const lyrics = aplayer.lyrics[playIndex.value];
|
||||
if (store.playerYrcShow != true) {
|
||||
store.yrcEnable = false;
|
||||
store.yrcTemp = [];
|
||||
store.yrcLoading = false;
|
||||
return;
|
||||
}
|
||||
if (store.yrcIndex == playIndex.value) {
|
||||
return;
|
||||
}
|
||||
const yrcUrl = aplayer.audio[aplayer.index]["lrc"] + "&yrc=true";
|
||||
store.yrcIndex = playIndex.value;
|
||||
store.yrcLoading = true;
|
||||
fetchYrc(yrcUrl);
|
||||
} catch (error) {
|
||||
store.yrcEnable = false;
|
||||
store.yrcTemp = [];
|
||||
store.yrcLoading = false;
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 播放
|
||||
const onPlay = () => {
|
||||
console.log("播放");
|
||||
@ -150,7 +237,7 @@ const onPlay = () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
if (store.webSpeech) {
|
||||
if (store.playerSpeechName) {
|
||||
@ -159,15 +246,15 @@ const onPlay = () => {
|
||||
const vstyle = import.meta.env.VITE_TTS_Style;
|
||||
Speech(
|
||||
"正在播放,“" +
|
||||
store.getPlayerData.artist +
|
||||
"”的歌曲,《" +
|
||||
store.getPlayerData.name +
|
||||
"》。",
|
||||
store.getPlayerData.artist +
|
||||
"”的歌曲,《" +
|
||||
store.getPlayerData.name +
|
||||
"》。",
|
||||
voice,
|
||||
vstyle,
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 暂停
|
||||
@ -175,227 +262,102 @@ const onPause = () => {
|
||||
store.setPlayerState(player.value.audioRef.paused);
|
||||
};
|
||||
|
||||
// 音频时间更新事件
|
||||
function showYrc() {
|
||||
// 至于为什么所有源的逐字都叫 YRC 呢...因为逐字功能本来是打算写网易云音乐独占的,但好像有些偏心了(bushi)...看了一下 qrc 和 yrc 没什么大区别,就顺带捏一起了。但是就懒得改变量名了!
|
||||
showYrcRunning = 1;
|
||||
try {
|
||||
// 至于为什么要 try 呢?问得好!因为网易云接口时不时会返回一些令人费解的东西,比如没有时间轴、时间轴为负数([20720,-4200])、时间轴乱码,这些东西会造成模块直接卡死,除非刷新页面。暂时没有那么多纠错逻辑,为了防止模块死掉,就先加个 try 在这里复活自己。咕咕咕!
|
||||
if (player.value == null) {
|
||||
return requestAnimationFrame(showYrc);
|
||||
function doLrcSync(lrc) {
|
||||
const playerLyricIndex = player.value.aplayer.lyricIndex;
|
||||
const output = [[true, 1, playerLyricIndex, 0, lrc]];
|
||||
if (store.playerLrc.toString() != output.toString()) {
|
||||
store.setPlayerLrc(output);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function syncLrc() {
|
||||
// 逐行模块
|
||||
const aplayer = player.value.aplayer;
|
||||
// console.log(playIndex.value)
|
||||
const lyrics = aplayer.lyrics[playIndex.value];
|
||||
const playerLyricIndex = player.value.aplayer.lyricIndex;
|
||||
if (lyrics === undefined || lyrics[playerLyricIndex] === undefined) {
|
||||
return doLrcSync("歌词加载中...");
|
||||
}
|
||||
let lrc = lyrics[playerLyricIndex][1];
|
||||
if (lrc === "Loading") {
|
||||
return doLrcSync("歌词加载中...");
|
||||
} else if (lrc === "Not available" && !store.playerYrcATDB) {
|
||||
return doLrcSync("歌词加载失败");
|
||||
} else if (lrc === "Not availible") {
|
||||
// 哈哈哈又是你()
|
||||
const songUrlInfw = new URLSearchParams(new URL(yrcUrl).search);
|
||||
const songIdlrc = songUrlInfw.get("id");
|
||||
const songServerlrc = songUrlInfw.get("server");
|
||||
if (!songIdlrc) {
|
||||
return doLrcSync("歌词加载失败");
|
||||
}
|
||||
const aplayer = player.value.aplayer;
|
||||
const lyrics = aplayer.lyrics[playIndex.value];
|
||||
if (store.playerYrcShow != true) {
|
||||
store.yrcEnable = false;
|
||||
store.yrcTemp = [];
|
||||
store.yrcLoading = false;
|
||||
}
|
||||
else {
|
||||
if (store.yrcIndex != playIndex.value) {
|
||||
const yrcUrl = aplayer.audio[aplayer.index]["lrc"] + "&yrc=true";
|
||||
store.yrcIndex = playIndex.value;
|
||||
store.yrcLoading = true;
|
||||
fetch(yrcUrl)
|
||||
.then((i) => {
|
||||
if (i.status < 200 || i.status >= 400) {
|
||||
throw i.text();
|
||||
};
|
||||
return i.text();
|
||||
})
|
||||
.then((i) => {
|
||||
store.yrcIndex = playIndex.value;
|
||||
if (i.startsWith("[ch:0]")) {
|
||||
store.yrcEnable = true;
|
||||
store.yrcTemp = decodeYrc(i);
|
||||
store.yrcLoading = false;
|
||||
return;
|
||||
} else if (!store.playerYrcATDB) {
|
||||
store.yrcEnable = false;
|
||||
store.yrcTemp = [];
|
||||
store.yrcLoading = false;
|
||||
return;
|
||||
};
|
||||
// 接入 AMLL TTML Database
|
||||
const songUrlInf = new URLSearchParams(new URL(yrcUrl).search)
|
||||
const songId = songUrlInf.get('id')
|
||||
const songServer = songUrlInf.get("server");
|
||||
if (!songId) {
|
||||
return;
|
||||
};
|
||||
const songUrlInfUrl = store.playerYrcATDBF
|
||||
? {
|
||||
'netease': `https://ghp.ci/https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/ncm-lyrics/${songId}.yrc`,
|
||||
'tencent': `https://ghp.ci/https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/qq-lyrics/${songId}.qrc`
|
||||
}
|
||||
: {
|
||||
'netease': `https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/ncm-lyrics/${songId}.yrc`,
|
||||
'tencent': `https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/qq-lyrics/${songId}.qrc`
|
||||
};
|
||||
if (!['netease', 'tencent'].includes(songServer)) {
|
||||
return;
|
||||
};
|
||||
const amllUrl = songUrlInfUrl[songServer]
|
||||
return fetch(amllUrl)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw response.text()
|
||||
};
|
||||
return response.text();
|
||||
}).then((amllyrcfile) => {
|
||||
store.yrcEnable = true;
|
||||
store.yrcTemp = decodeYrc(amllyrcfile);
|
||||
store.yrcLoading = false;
|
||||
});
|
||||
}).catch(() => {
|
||||
store.yrcEnable = false;
|
||||
store.yrcTemp = [];
|
||||
store.yrcLoading = false;
|
||||
});
|
||||
};
|
||||
};
|
||||
if (!store.yrcEnable || store.yrcTemp.length == 0 || store.yrcLoading) {
|
||||
// 逐行模块
|
||||
let lyricIndex = player.value.aplayer.lyricIndex;
|
||||
if (lyrics === undefined || lyrics[lyricIndex] === undefined) {
|
||||
return requestAnimationFrame(showYrc);
|
||||
}
|
||||
let lrc = lyrics[lyricIndex][1];
|
||||
if (lrc === "Loading") {
|
||||
lrc = "歌词加载中...";
|
||||
} else if (lrc === "Not available") {
|
||||
if (store.playerYrcATDB) {
|
||||
// 哈哈哈又是你()
|
||||
const songUrlInfw = new URLSearchParams(new URL(yrcUrl).search)
|
||||
const songIdlrc = songUrlInfw.get('id')
|
||||
const songServerlrc = songUrlInfw.get("server");
|
||||
if (songIdlrc) {
|
||||
const songUrlInfwurl = store.playerYrcATDBF
|
||||
? {
|
||||
'netease': `https://ghp.ci/https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/ncm-lyrics/${songId}.lrc`,
|
||||
'tencent': `https://ghp.ci/https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/qq-lyrics/${songId}.lrc`
|
||||
}
|
||||
: {
|
||||
'netease': `https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/ncm-lyrics/${songId}.lrc`,
|
||||
'tencent': `https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/qq-lyrics/${songId}.lrc`
|
||||
};
|
||||
if (!['netease', 'tencent'].includes(songServerlrc)) {
|
||||
return;
|
||||
};
|
||||
const amllUrllrc = songUrlInfwurl[songServerlrc].replace('${songIdlrc}', songIdlrc);
|
||||
fetch(amllUrllrc)
|
||||
.then((response) => {
|
||||
if (response.status === 404 || !response.ok) {
|
||||
lrc = "歌词加载失败";
|
||||
return;
|
||||
} else {
|
||||
return response.text();
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
lrc = "歌词加载失败";
|
||||
});
|
||||
}
|
||||
} else {
|
||||
lrc = "歌词加载失败";
|
||||
const songUrlInfwurl = store.playerYrcATDBF
|
||||
? {
|
||||
netease: `https://ghp.ci/https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/ncm-lyrics/${songId}.lrc`,
|
||||
tencent: `https://ghp.ci/https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/qq-lyrics/${songId}.lrc`,
|
||||
}
|
||||
: {
|
||||
netease: `https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/ncm-lyrics/${songId}.lrc`,
|
||||
tencent: `https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/qq-lyrics/${songId}.lrc`,
|
||||
};
|
||||
}
|
||||
const output = [[true, 1, lyricIndex, 0, lrc]];
|
||||
if (store.playerLrc.toString() != output.toString()) {
|
||||
store.setPlayerLrc(output);
|
||||
};
|
||||
return requestAnimationFrame(showYrc);
|
||||
};
|
||||
// 逐字模块
|
||||
const now = player.value.audioStatus.playedTime * 1000;
|
||||
const yrcFiltered = store.yrcTemp.filter((i) => i[0] < now);
|
||||
let animationTmp = [];
|
||||
const yrcLyric =
|
||||
yrcFiltered.length > 0
|
||||
? yrcFiltered.slice(-1)[0][2].map((it) => {
|
||||
if (!["netease", "tencent"].includes(songServerlrc)) {
|
||||
return doLrcSync("歌词加载失败");
|
||||
}
|
||||
const amllUrllrc = songUrlInfwurl[songServerlrc].replace("${songIdlrc}", songIdlrc);
|
||||
fetch(amllUrllrc)
|
||||
.then((response) => response.text())
|
||||
.catch(() => {
|
||||
doLrcSync("歌词加载失败");
|
||||
});
|
||||
return doLrcSync("歌词加载中...");
|
||||
}
|
||||
doLrcSync(lrc);
|
||||
}
|
||||
|
||||
function syncYrc() {
|
||||
const now = player.value.audioStatus.playedTime * 1000;
|
||||
const yrcFiltered = store.yrcTemp.filter((i) => i[0] < now);
|
||||
const yrcLyric =
|
||||
yrcFiltered.length > 0
|
||||
? yrcFiltered.slice(-1)[0][2].map((it) => {
|
||||
const [[start, duration], word, line, row] = it;
|
||||
const isCurrent = now >= start && now <= start + duration;
|
||||
const isSungLyrics = start + duration < now;
|
||||
const lessdur = start + duration - now;
|
||||
return [isCurrent, isSungLyrics, line, row, word, duration, lessdur, "auto"];
|
||||
})
|
||||
: [[true, 1, 0, 0, `${store.playerTitle} - ${store.playerArtist}`]];
|
||||
if (store.playerLrc.toString() != yrcLyric.toString()) {
|
||||
store.setPlayerLrc(yrcLyric);
|
||||
};
|
||||
if (store.playerYrcShowPro) {
|
||||
// 这个增强模块虽然能跑,但还有 N 个漏洞要修。对于这些概率性事件,还毫无头绪()
|
||||
if (yrcFiltered.length === 0) {
|
||||
return requestAnimationFrame(showYrc);
|
||||
};
|
||||
const lineStart = yrcFiltered.slice(-1)[0][0];
|
||||
if (nowLineStart == lineStart) {
|
||||
return requestAnimationFrame(showYrc);
|
||||
};
|
||||
const yrc2 = document.getElementsByClassName("yrc-box")[0];
|
||||
if (yrc2 == undefined) {
|
||||
return requestAnimationFrame(showYrc);
|
||||
};
|
||||
const outputDom = yrc2.querySelectorAll("#yrc-2-wrap span");
|
||||
const inputDom = yrc2.querySelectorAll("#yrc-1-wrap span");
|
||||
if (inputDom.length == 0 || outputDom.length == 0) {
|
||||
return requestAnimationFrame(showYrc);
|
||||
};
|
||||
const nowLineWord = yrcFiltered.slice(-1)[0][2];
|
||||
for (let i = 0; i < nowLineWord.length; i++) {
|
||||
const [[start, duration], _a, _b, _c] = nowLineWord[i];
|
||||
const intputItem = inputDom[i];
|
||||
if (!intputItem || intputItem.hasAttribute('data-start')) {
|
||||
return requestAnimationFrame(showYrc);
|
||||
};
|
||||
const computedStyle = window.getComputedStyle(intputItem);
|
||||
const width = parseFloat(computedStyle.width);
|
||||
if (isNaN(width)) {
|
||||
intputItem.removeAttribute('data-start');
|
||||
return requestAnimationFrame(showYrc);
|
||||
};
|
||||
const outputItem = outputDom[i];
|
||||
const animateOptions = {
|
||||
delay: Math.max(0, start - now),
|
||||
duration: duration,
|
||||
fill: "forwards",
|
||||
easing: "linear",
|
||||
};
|
||||
outputItem.style.transform = "translateY(-1px)"
|
||||
const outputAnimate = outputItem.animate(
|
||||
[
|
||||
{ width: 0, },
|
||||
{ width: `${width}px` },
|
||||
],
|
||||
animateOptions,
|
||||
);
|
||||
animationTmp.push(outputAnimate);
|
||||
outputAnimate.onfinish = () => {
|
||||
outputItem.style.transform = "translateY(1px)";
|
||||
animationTmp = animationTmp.filter(a => a !== outputAnimate);
|
||||
};
|
||||
};
|
||||
nowLineStart = yrcFiltered.slice(-1)[0][0];
|
||||
};
|
||||
return requestAnimationFrame(showYrc);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return requestAnimationFrame(showYrc);
|
||||
};
|
||||
};
|
||||
: [[true, 1, 0, 0, `${store.playerTitle} - ${store.playerArtist}`]];
|
||||
if (store.playerLrc.toString() != yrcLyric.toString()) {
|
||||
store.setPlayerLrc(yrcLyric);
|
||||
}
|
||||
}
|
||||
|
||||
// 音频时间更新事件
|
||||
const onTimeUp = () => {
|
||||
store.playerCurrentTime = player.value.audioStatus.playedTime;
|
||||
store.playerDuration = player.value.audioStatus.duration;
|
||||
if (showYrcRunning == 0) {
|
||||
requestAnimationFrame(showYrc);
|
||||
// 至于为什么所有源的逐字都叫 YRC 呢...因为逐字功能本来是打算写网易云音乐独占的,但好像有些偏心了(bushi)...看了一下 qrc 和 yrc 没什么大区别,就顺带捏一起了。但是就懒得改变量名了!
|
||||
showYrcRunning = 1;
|
||||
try {
|
||||
// 至于为什么要 try 呢?问得好!因为网易云接口时不时会返回一些令人费解的东西,比如没有时间轴、时间轴为负数([20720,-4200])、时间轴乱码,这些东西会造成模块直接卡死,除非刷新页面。暂时没有那么多纠错逻辑,为了防止模块死掉,就先加个 try 在这里复活自己。咕咕咕!
|
||||
if (player.value == null) {
|
||||
return;
|
||||
}
|
||||
const aplayer = player.value.aplayer;
|
||||
const isLineByLine = false;
|
||||
// const isLineByLine = !store.yrcEnable || store.yrcTemp.length == 0 || store.yrcLoading
|
||||
if (isLineByLine) {
|
||||
return syncLrc();
|
||||
} else {
|
||||
return syncYrc();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
const onLoadStart = () => {
|
||||
|
||||
};
|
||||
|
||||
// 切换播放暂停事件
|
||||
const playToggle = () => {
|
||||
player.value.toggle();
|
||||
@ -419,7 +381,6 @@ const toggleList = () => {
|
||||
player.value.toggleList();
|
||||
};
|
||||
|
||||
|
||||
// 加载音频错误
|
||||
const loadMusicError = () => {
|
||||
let notice = "";
|
||||
@ -430,7 +391,7 @@ const loadMusicError = () => {
|
||||
const voice = import.meta.env.VITE_TTS_Voice;
|
||||
const vstyle = import.meta.env.VITE_TTS_Style;
|
||||
SpeechLocal("歌曲加载失败.mp3");
|
||||
};
|
||||
}
|
||||
} else {
|
||||
notice = "播放歌曲出现错误";
|
||||
if (store.webSpeech) {
|
||||
@ -438,7 +399,7 @@ const loadMusicError = () => {
|
||||
const voice = import.meta.env.VITE_TTS_Voice;
|
||||
const vstyle = import.meta.env.VITE_TTS_Style;
|
||||
SpeechLocal("播放器未知异常.mp3");
|
||||
};
|
||||
}
|
||||
}
|
||||
ElMessage({
|
||||
message: notice,
|
||||
@ -495,14 +456,18 @@ defineExpose({ playToggle, changeVolume, changeSong, toggleList });
|
||||
text-align: left;
|
||||
margin: 7px 0 6px 6px;
|
||||
height: 44px;
|
||||
-webkit-mask: linear-gradient(#fff 15%,
|
||||
#fff 85%,
|
||||
hsla(0deg, 0%, 100%, 0.6) 90%,
|
||||
hsla(0deg, 0%, 100%, 0));
|
||||
mask: linear-gradient(#fff 15%,
|
||||
#fff 85%,
|
||||
hsla(0deg, 0%, 100%, 0.6) 90%,
|
||||
hsla(0deg, 0%, 100%, 0));
|
||||
-webkit-mask: linear-gradient(
|
||||
#fff 15%,
|
||||
#fff 85%,
|
||||
hsla(0deg, 0%, 100%, 0.6) 90%,
|
||||
hsla(0deg, 0%, 100%, 0)
|
||||
);
|
||||
mask: linear-gradient(
|
||||
#fff 15%,
|
||||
#fff 85%,
|
||||
hsla(0deg, 0%, 100%, 0.6) 90%,
|
||||
hsla(0deg, 0%, 100%, 0)
|
||||
);
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
|
Loading…
Reference in New Issue
Block a user