mirror of
https://github.com/imsyy/home.git
synced 2025-05-21 13:40:15 +09:00
进行一些改进
1.修复 pinia 无法重置变量的问题。 2.修复 weather.vue 中的某些错误。 3.补全遗漏的语音提示。 4.逐字样式修改,添加逐字上色增强效果,但默认不开启,因为这坨山还有 N 个 BUG 要修,仅仅能跑,一点不稳定。 5.修复(?)歌词解析时因 API 返回玄学内容造成的异常。 6.逐字解析逻辑修改。 ... More fixes needed
This commit is contained in:
parent
dd81d31748
commit
7d02b4da23
24
package.json
24
package.json
@ -18,15 +18,15 @@
|
||||
"aplayer": "^1.10.1",
|
||||
"axios": "^1.7.7",
|
||||
"dayjs": "^1.11.13",
|
||||
"element-plus": "^2.8.7",
|
||||
"element-plus": "^2.8.8",
|
||||
"fetch-jsonp": "^1.3.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"pinia": "^2.2.5",
|
||||
"pinia-plugin-persistedstate": "^4.1.2",
|
||||
"pinia-plugin-persistedstate-2": "^2.0.24",
|
||||
"swiper": "^11.1.14",
|
||||
"pinia": "^2.2.6",
|
||||
"pinia-plugin-persistedstate": "^4.1.3",
|
||||
"pinia-plugin-persistedstate-2": "^2.0.27",
|
||||
"swiper": "^11.1.15",
|
||||
"three": "^0.170.0",
|
||||
"vue": "^3.5.12"
|
||||
"vue": "^3.5.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@icon-park/vue-next": "^1.4.2",
|
||||
@ -36,15 +36,15 @@
|
||||
"@vicons/material": "^0.12.0",
|
||||
"@vicons/tabler": "^0.12.0",
|
||||
"@vicons/utils": "^0.1.4",
|
||||
"@vitejs/plugin-vue": "^5.1.4",
|
||||
"eslint": "^9.14.0",
|
||||
"eslint-plugin-vue": "^9.30.0",
|
||||
"@vitejs/plugin-vue": "^5.2.0",
|
||||
"eslint": "^9.15.0",
|
||||
"eslint-plugin-vue": "^9.31.0",
|
||||
"prettier": "^3.3.3",
|
||||
"sass": "^1.80.6",
|
||||
"sass": "^1.81.0",
|
||||
"terser": "^5.36.0",
|
||||
"unplugin-auto-import": "^0.18.3",
|
||||
"unplugin-auto-import": "^0.18.5",
|
||||
"unplugin-vue-components": "^0.27.4",
|
||||
"vite": "^5.4.10",
|
||||
"vite": "^5.4.11",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-pwa": "^0.20.5"
|
||||
}
|
||||
|
1008
pnpm-lock.yaml
generated
1008
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -47,7 +47,7 @@ const changeBg = (type) => {
|
||||
bgUrl.value = "https://api.vvhan.com/api/wallpaper/views";
|
||||
} else if (type == 3) {
|
||||
bgUrl.value = "https://api.vvhan.com/api/wallpaper/acg";
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 图片加载完成
|
||||
|
@ -41,7 +41,11 @@
|
||||
:key="store.playerLrc.length != 0 ? `lrc-line-${store.playerLrc[0][2]}` : `lrc-line-null`">
|
||||
<music-one theme="filled" size="18" fill="#efefef" />
|
||||
<span class="yrc-box">
|
||||
<span class="yrc-1 lrc-text text-hidden">
|
||||
<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>
|
||||
<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]}`"
|
||||
:style="`opacity: ${i[1] ? '1' : '0.6'}`"
|
||||
:class="`yrc-char ${i[0] ? 'fade-in' : 'fade-in-start'} ${i[0] > 1.5 ? 'long-tone' : 'fade-in-start'}`"
|
||||
@ -87,14 +91,14 @@ const siteUrl = computed(() => {
|
||||
// 判断协议前缀
|
||||
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
||||
return "//" + url;
|
||||
}
|
||||
};
|
||||
return url;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 逐字模块1
|
||||
.yrc-char {
|
||||
// 逐字部分
|
||||
display: inline-block;
|
||||
opacity: 0.3;
|
||||
transform: translateY(1px);
|
||||
@ -174,8 +178,32 @@ const siteUrl = computed(() => {
|
||||
}
|
||||
}
|
||||
|
||||
// 逐字模块2
|
||||
#yrc-2-wrap>span {
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
#yrc-2-wrap {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
width: auto;
|
||||
opacity: 0.5;
|
||||
text-shadow: 0 0 4px rgba(255, 255, 255, 0.8);
|
||||
font-family: MiSans-Regular;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
transition:
|
||||
opacity 0.3s linear,
|
||||
color 0.5s linear,
|
||||
transform 0.3s linear,
|
||||
width 0.3s linear;
|
||||
}
|
||||
|
||||
// 逐行部分
|
||||
.lrc-char {
|
||||
// 逐行部分
|
||||
display: inline;
|
||||
opacity: 1;
|
||||
background-clip: text;
|
||||
@ -187,6 +215,8 @@ const siteUrl = computed(() => {
|
||||
color 0.5s linear;
|
||||
}
|
||||
|
||||
// End
|
||||
|
||||
#footer {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
@ -196,7 +226,7 @@ const siteUrl = computed(() => {
|
||||
line-height: 46px;
|
||||
text-align: center;
|
||||
z-index: 0;
|
||||
font-size: 14px;
|
||||
font-size: 16px;
|
||||
// 文字不换行
|
||||
word-break: keep-all;
|
||||
white-space: nowrap;
|
||||
@ -211,6 +241,8 @@ const siteUrl = computed(() => {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1;
|
||||
justify-content: flex-start;
|
||||
|
||||
.lrc-all {
|
||||
width: 98%;
|
||||
@ -218,6 +250,7 @@ const siteUrl = computed(() => {
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
|
||||
.lrc-text {
|
||||
margin: 0 8px;
|
||||
@ -250,9 +283,6 @@ const siteUrl = computed(() => {
|
||||
.yrc-2 {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
overflow: hidden;
|
||||
float: left;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ const siteLinksList = computed(() => {
|
||||
for (let i = 0; i < siteLinks.length; i += 6) {
|
||||
const subArr = siteLinks.slice(i, i + 6);
|
||||
result.push(subArr);
|
||||
}
|
||||
};
|
||||
return result;
|
||||
});
|
||||
|
||||
@ -78,7 +78,7 @@ const jumpLink = (data) => {
|
||||
if (typeof $openList === "function") $openList();
|
||||
} else {
|
||||
window.open(data.link, "_blank");
|
||||
}
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -47,7 +47,7 @@ const siteUrl = computed(() => {
|
||||
if (url.startsWith("http://") || url.startsWith("https://")) {
|
||||
const urlFormat = url.replace(/^(https?:\/\/)/, "");
|
||||
return urlFormat.split(".");
|
||||
}
|
||||
};
|
||||
return url.split(".");
|
||||
});
|
||||
|
||||
@ -76,7 +76,7 @@ const changeBox = () => {
|
||||
const vstyle = import.meta.env.VITE_TTS_Style;
|
||||
SpeechLocal("分辨率不足.mp3");
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 监听状态变化
|
||||
@ -95,7 +95,7 @@ watch(
|
||||
} else {
|
||||
descriptionText.hello = import.meta.env.VITE_DESC_HELLO;
|
||||
descriptionText.text = import.meta.env.VITE_DESC_TEXT;
|
||||
}
|
||||
};
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
@ -13,10 +13,8 @@ import APlayer from "@worstone/vue-aplayer";
|
||||
import { Speech, stopSpeech, SpeechLocal } from "@/utils/speech";
|
||||
import { decodeYrc } from "../utils/decodeYrc";
|
||||
|
||||
let lastTimestamp = Date.now();
|
||||
let webglRenderer;
|
||||
|
||||
const store = mainStore();
|
||||
let lastTimestamp = Date.now();
|
||||
|
||||
// 获取播放器 DOM
|
||||
const player = ref(null);
|
||||
@ -175,150 +173,198 @@ const onPause = () => {
|
||||
store.setPlayerState(player.value.audioRef.paused);
|
||||
};
|
||||
|
||||
let nowLineStart = -1
|
||||
// 音频时间更新事件
|
||||
function showYrc() {
|
||||
if (player.value == null) {
|
||||
return requestAnimationFrame(showYrc);
|
||||
}
|
||||
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) {
|
||||
// 至于为什么所有源的逐字都叫 YRC 呢...因为逐字功能本来是打算写网易云音乐独占的,但好像有些偏心了(bushi)...看了一下 qrc 和 yrc 没什么大区别,就顺带捏一起了。但是就懒得改变量名了!
|
||||
try {
|
||||
// 至于为什么要 try 呢?问得好!因为网易云接口时不时会返回一些令人费解的东西,比如没有时间轴、时间轴为负数([20720,-4200])、时间轴乱码,这些东西会造成模块直接卡死,除非刷新页面。暂时没有那么多纠错逻辑,为了防止模块死掉,就先加个 try 在这里复活自己。咕咕咕!
|
||||
if (player.value == null) {
|
||||
return requestAnimationFrame(showYrc);
|
||||
}
|
||||
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 = {
|
||||
'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;
|
||||
return;
|
||||
};
|
||||
// 接入 AMLL TTML Database
|
||||
const songIdMatch = yrcUrl.match(/netease.*?id=(.*?)&/);
|
||||
const songId = songIdMatch ? songIdMatch[1] : null;
|
||||
if (!songId) {
|
||||
return;
|
||||
};
|
||||
const amllUrl = `https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/ncm-lyrics/${songId}.yrc`;
|
||||
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 lrcUrlw = aplayer.audio[aplayer.index]["lrc"];
|
||||
const songIdMatchlrc = lrcUrlw.match(/netease.*?id=(.*?)&/);
|
||||
const songIdlrc = songIdMatchlrc ? songIdMatchlrc[1] : null;
|
||||
if (songIdlrc) {
|
||||
const amllUrllrc = `https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/ncm-lyrics/${songIdlrc}.lrc`;
|
||||
fetch(amllUrllrc)
|
||||
.then((response) => {
|
||||
if (response.status === 404 || !response.ok) {
|
||||
lrc = "歌词加载失败";
|
||||
return;
|
||||
} else {
|
||||
return response.text();
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
lrc = "歌词加载失败";
|
||||
});
|
||||
}
|
||||
} else {
|
||||
lrc = "歌词加载失败";
|
||||
});
|
||||
};
|
||||
}
|
||||
const output = [[true, 1, lyricIndex, 0, lrc]];
|
||||
if (store.playerLrc.toString() != output.toString()) {
|
||||
store.setPlayerLrc(output);
|
||||
}
|
||||
return requestAnimationFrame(showYrc);
|
||||
}
|
||||
// 逐字模块
|
||||
if (store.playerYrcShowPro) {
|
||||
if (!webglRenderer) {
|
||||
const canvas = document.getElementById("lyricsCanvas");
|
||||
webglRenderer = new WebGLLyricsRenderer(canvas);
|
||||
}
|
||||
}
|
||||
const now = player.value.audioStatus.playedTime * 1000;
|
||||
const yrcFiltered = store.yrcTemp.filter((i) => i[0] < now);
|
||||
const yrc1 = document.querySelector(".yrc-1")
|
||||
if (yrc1 == null) {
|
||||
return requestAnimationFrame(showYrc);
|
||||
}
|
||||
const yrcLyric =
|
||||
yrcFiltered.length > 0
|
||||
? yrcFiltered.splice(-1)[0][2].map((it) => {
|
||||
const [[start, duration], word, line, row] = it;
|
||||
const isCurrent = now >= start && now <= start + duration;
|
||||
const isSungLyrics = start + duration < now;
|
||||
if (!isCurrent) {
|
||||
};
|
||||
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 = {
|
||||
'netease': `https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/ncm-lyrics/${songIdlrc}.lrc`,
|
||||
'tencent': `https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/qq-lyrics/${songIdlrc}.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 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) => {
|
||||
const [[start, duration], word, line, row] = it;
|
||||
const isCurrent = now >= start && now <= start + duration;
|
||||
const isSungLyrics = start + duration < now;
|
||||
return [isCurrent, isSungLyrics, line, row, word, "auto"];
|
||||
}
|
||||
const thisDom = yrc1.querySelector(`#lrc-char-${line}-${row}`)
|
||||
if (thisDom == null) {
|
||||
return [isCurrent, isSungLyrics, line, row, word, "auto"];
|
||||
}
|
||||
const x = thisDom.offsetWidth * (now - start) / duration
|
||||
if (x == null || x == NaN) {
|
||||
return [isCurrent, isSungLyrics, line, row, word, "auto"];
|
||||
}
|
||||
return [isCurrent, isSungLyrics, line, row, word, `${x}px`]
|
||||
})
|
||||
: [[true, 1, 0, 0, `${store.playerTitle} - ${store.playerArtist}`]];
|
||||
|
||||
if (store.playerLrc.toString() != yrcLyric.toString()) {
|
||||
store.setPlayerLrc(yrcLyric);
|
||||
}
|
||||
if (store.playerYrcShowPro) {
|
||||
webglRenderer.render(yrcLyric);
|
||||
}
|
||||
requestAnimationFrame(showYrc);
|
||||
}
|
||||
})
|
||||
: [[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);
|
||||
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];
|
||||
};
|
||||
requestAnimationFrame(showYrc);
|
||||
} catch (error) {
|
||||
requestAnimationFrame(showYrc);
|
||||
};
|
||||
};
|
||||
requestAnimationFrame(showYrc);
|
||||
|
||||
// 切换播放暂停事件
|
||||
|
@ -59,7 +59,7 @@
|
||||
<el-switch v-model="playerYrcShow" inline-prompt :active-icon="CheckSmall" :inactive-icon="CloseSmall" />
|
||||
</div>
|
||||
<div v-if="playerLrcShow && playerYrcShow" class="item">
|
||||
<span class="text">逐字效果增强开关(更高的性能要求)</span>
|
||||
<span class="text">逐字效果增强开关</span>
|
||||
<el-switch v-model="playerYrcShowPro" inline-prompt :active-icon="CheckSmall" :inactive-icon="CloseSmall" />
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
|
@ -16,7 +16,7 @@
|
||||
剩余 {{ item.remaining }} {{ tag === "day" ? "小时" : "天" }}
|
||||
</span>
|
||||
</div>
|
||||
<el-progress :text-inside="true" :stroke-width="20" :percentage="parseFloat(item.percentage)" />
|
||||
<el-progress :text-inside="true" :stroke-width="20" :percentage="Number(item.percentage)" />
|
||||
</div>
|
||||
<!-- 建站日期 -->
|
||||
<div v-if="store.siteStartShow" class="capsule-item start">
|
||||
|
@ -20,6 +20,9 @@
|
||||
<script setup>
|
||||
import { getAdcode, getWeather, getOtherWeather } from "@/api";
|
||||
import { Error } from "@icon-park/vue-next";
|
||||
import { mainStore } from "@/store";
|
||||
import { Speech, stopSpeech, SpeechLocal } from "@/utils/speech";
|
||||
const store = mainStore();
|
||||
|
||||
// 高德开发者 Key
|
||||
const mainKey = import.meta.env.VITE_WEATHER_KEY;
|
||||
|
39
src/main.js
39
src/main.js
@ -1,6 +1,7 @@
|
||||
import { createApp } from "vue";
|
||||
import "@/style/style.scss";
|
||||
import App from "@/App.vue";
|
||||
import { mainStore } from "@/store";
|
||||
import { Speech, stopSpeech, SpeechLocal } from "@/utils/speech";
|
||||
// 引入 pinia
|
||||
import { createPinia } from 'pinia';
|
||||
@ -22,30 +23,32 @@ window.addEventListener("beforeunload", () => {
|
||||
// 这堆代码原本的意义是在于强制刷新这些本不需要被 pinia 缓存的变量,不知为什么这些变量只会在关闭页面重新输入域名访问才能恢复,导致刷新页面部分模块短时间内出现异常。
|
||||
// 但是貌似这堆代码也没能解决问题...罢了,先暂且留着叭()
|
||||
const store = mainStore();
|
||||
store.imgLoadStatus = false; // 壁纸加载状态
|
||||
store.innerWidth = null; // 当前窗口宽度
|
||||
store.musicIsOk = false; // 音乐是否加载完成
|
||||
store.musicOpenState = false; // 音乐面板开启状态
|
||||
store.backgroundShow = false; // 壁纸展示状态
|
||||
store.boxOpenState = false; // 盒子开启状态
|
||||
store.mobileOpenState = false; // 移动端开启状态
|
||||
store.mobileFuncState = false; // 移动端功能区开启状态
|
||||
store.setOpenState = false; // 设置页面开启状态
|
||||
store.playerState = false; // 当前播放状态
|
||||
store.playerTitle = null; // 当前播放歌曲名
|
||||
store.playerArtist = null; // 当前播放歌手名
|
||||
store.playerLrc = [[true, "猫猫正在翻找歌词..."]]; // 当前播放歌词
|
||||
store.yrcIndex = -1; // 逐字歌词进度存储
|
||||
store.yrcTemp = []; // 逐字歌词缓存
|
||||
store.yrcEnable = true;
|
||||
store.yrcLoading = false;
|
||||
Object.assign(store, {
|
||||
imgLoadStatus: false, // 壁纸加载状态
|
||||
innerWidth: null, // 当前窗口宽度
|
||||
musicIsOk: false, // 音乐是否加载完成
|
||||
musicOpenState: false, // 音乐面板开启状态
|
||||
backgroundShow: false, // 壁纸展示状态
|
||||
boxOpenState: false, // 盒子开启状态
|
||||
mobileOpenState: false, // 移动端开启状态
|
||||
mobileFuncState: false, // 移动端功能区开启状态
|
||||
setOpenState: false, // 设置页面开启状态
|
||||
playerState: false, // 当前播放状态
|
||||
playerTitle: null, // 当前播放歌曲名
|
||||
playerArtist: null, // 当前播放歌手名
|
||||
playerLrc: [[true, "歌词加载中..."]], // 当前播放歌词
|
||||
yrcIndex: -1, // 逐字歌词进度存储
|
||||
yrcTemp: [], // 逐字歌词缓存
|
||||
yrcEnable: true,
|
||||
yrcLoading: false,
|
||||
});
|
||||
});
|
||||
|
||||
app.use(pinia);
|
||||
app.mount("#app");
|
||||
|
||||
// PWA
|
||||
navigator.serviceWorker.addEventListener("controllerchange", () => {
|
||||
navigator.serviceWorker.addEventListener("controllerchange", async () => {
|
||||
// 弹出更新提醒
|
||||
console.log("站点已更新,刷新后生效");
|
||||
ElMessage("站点已更新,刷新后生效");
|
||||
|
@ -24,10 +24,10 @@ export const mainStore = defineStore("main", {
|
||||
playerAutoplay: true, // 是否自动播放
|
||||
playerLoop: "all", // 循环播放 "all", "one", "none"
|
||||
playerOrder: "random", // 循环顺序 "list", "random"
|
||||
webSpeech: false, // 网页语音交互总开关(包含播报歌名功能)
|
||||
webSpeech: true, // 网页语音交互总开关(包含播报歌名功能)
|
||||
playerSpeechName: true, // 播报歌名
|
||||
playerYrcShow: true, // 逐字歌词解析总开关
|
||||
playerYrcShowPro: false, // 逐字效果增强开关(更高的性能要求)
|
||||
playerYrcShowPro: false, // 逐字效果增强开关
|
||||
playerYrcATDB: true, // 允许接入 AMLL TTML Database
|
||||
yrcIndex: -1, // 逐字歌词进度存储
|
||||
yrcTemp: [], // 逐字歌词缓存
|
||||
|
@ -110,7 +110,7 @@ export function stopSpeech() {
|
||||
}
|
||||
|
||||
export function SpeechLocal(fileName) {
|
||||
// 考虑到生成延迟,所以加了这个,仅必要模块调用 api 实时生成,其它模块使用预先生成好的音频
|
||||
// 考虑到生成延迟,所以加了这个,仅必要模块调用 api 实时生成,其它模块使用预先生成好的音频。记得根据需求更换自己的音频文件哇!
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!fileName) {
|
||||
reject(new Error("No file name provided"));
|
||||
|
Loading…
Reference in New Issue
Block a user