进行一些改进

1.修复 pinia 无法重置变量的问题。
2.修复 weather.vue 中的某些错误。
3.补全遗漏的语音提示。
4.逐字样式修改,添加逐字上色增强效果,但默认不开启,因为这坨山还有 N 个 BUG 要修,仅仅能跑,一点不稳定。
5.修复(?)歌词解析时因 API 返回玄学内容造成的异常。
6.逐字解析逻辑修改。
...
More fixes needed
This commit is contained in:
NanoRocky 2024-11-22 21:52:05 +08:00
parent dd81d31748
commit 7d02b4da23
13 changed files with 819 additions and 649 deletions

View File

@ -18,15 +18,15 @@
"aplayer": "^1.10.1", "aplayer": "^1.10.1",
"axios": "^1.7.7", "axios": "^1.7.7",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"element-plus": "^2.8.7", "element-plus": "^2.8.8",
"fetch-jsonp": "^1.3.0", "fetch-jsonp": "^1.3.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"pinia": "^2.2.5", "pinia": "^2.2.6",
"pinia-plugin-persistedstate": "^4.1.2", "pinia-plugin-persistedstate": "^4.1.3",
"pinia-plugin-persistedstate-2": "^2.0.24", "pinia-plugin-persistedstate-2": "^2.0.27",
"swiper": "^11.1.14", "swiper": "^11.1.15",
"three": "^0.170.0", "three": "^0.170.0",
"vue": "^3.5.12" "vue": "^3.5.13"
}, },
"devDependencies": { "devDependencies": {
"@icon-park/vue-next": "^1.4.2", "@icon-park/vue-next": "^1.4.2",
@ -36,15 +36,15 @@
"@vicons/material": "^0.12.0", "@vicons/material": "^0.12.0",
"@vicons/tabler": "^0.12.0", "@vicons/tabler": "^0.12.0",
"@vicons/utils": "^0.1.4", "@vicons/utils": "^0.1.4",
"@vitejs/plugin-vue": "^5.1.4", "@vitejs/plugin-vue": "^5.2.0",
"eslint": "^9.14.0", "eslint": "^9.15.0",
"eslint-plugin-vue": "^9.30.0", "eslint-plugin-vue": "^9.31.0",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"sass": "^1.80.6", "sass": "^1.81.0",
"terser": "^5.36.0", "terser": "^5.36.0",
"unplugin-auto-import": "^0.18.3", "unplugin-auto-import": "^0.18.5",
"unplugin-vue-components": "^0.27.4", "unplugin-vue-components": "^0.27.4",
"vite": "^5.4.10", "vite": "^5.4.11",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-pwa": "^0.20.5" "vite-plugin-pwa": "^0.20.5"
} }

1008
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -47,7 +47,7 @@ const changeBg = (type) => {
bgUrl.value = "https://api.vvhan.com/api/wallpaper/views"; bgUrl.value = "https://api.vvhan.com/api/wallpaper/views";
} else if (type == 3) { } else if (type == 3) {
bgUrl.value = "https://api.vvhan.com/api/wallpaper/acg"; bgUrl.value = "https://api.vvhan.com/api/wallpaper/acg";
} };
}; };
// //

View File

@ -41,7 +41,11 @@
:key="store.playerLrc.length != 0 ? `lrc-line-${store.playerLrc[0][2]}` : `lrc-line-null`"> :key="store.playerLrc.length != 0 ? `lrc-line-${store.playerLrc[0][2]}` : `lrc-line-null`">
<music-one theme="filled" size="18" fill="#efefef" /> <music-one theme="filled" size="18" fill="#efefef" />
<span class="yrc-box"> <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]}`" <span v-for="i in store.playerLrc" :key="`lrc-char-${i[2]}-${i[3]}`"
:style="`opacity: ${i[1] ? '1' : '0.6'}`" :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'}`" :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://")) { if (!url.startsWith("http://") && !url.startsWith("https://")) {
return "//" + url; return "//" + url;
} };
return url; return url;
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
// 1
.yrc-char { .yrc-char {
//
display: inline-block; display: inline-block;
opacity: 0.3; opacity: 0.3;
transform: translateY(1px); 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 { .lrc-char {
//
display: inline; display: inline;
opacity: 1; opacity: 1;
background-clip: text; background-clip: text;
@ -187,6 +215,8 @@ const siteUrl = computed(() => {
color 0.5s linear; color 0.5s linear;
} }
// End
#footer { #footer {
width: 100%; width: 100%;
position: absolute; position: absolute;
@ -196,7 +226,7 @@ const siteUrl = computed(() => {
line-height: 46px; line-height: 46px;
text-align: center; text-align: center;
z-index: 0; z-index: 0;
font-size: 14px; font-size: 16px;
// //
word-break: keep-all; word-break: keep-all;
white-space: nowrap; white-space: nowrap;
@ -211,6 +241,8 @@ const siteUrl = computed(() => {
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
z-index: 1;
justify-content: flex-start;
.lrc-all { .lrc-all {
width: 98%; width: 98%;
@ -218,6 +250,7 @@ const siteUrl = computed(() => {
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
white-space: nowrap;
.lrc-text { .lrc-text {
margin: 0 8px; margin: 0 8px;
@ -250,9 +283,6 @@ const siteUrl = computed(() => {
.yrc-2 { .yrc-2 {
position: absolute; position: absolute;
z-index: 1000; z-index: 1000;
overflow: hidden;
float: left;
text-align: left;
} }
} }
} }

View File

@ -57,7 +57,7 @@ const siteLinksList = computed(() => {
for (let i = 0; i < siteLinks.length; i += 6) { for (let i = 0; i < siteLinks.length; i += 6) {
const subArr = siteLinks.slice(i, i + 6); const subArr = siteLinks.slice(i, i + 6);
result.push(subArr); result.push(subArr);
} };
return result; return result;
}); });
@ -78,7 +78,7 @@ const jumpLink = (data) => {
if (typeof $openList === "function") $openList(); if (typeof $openList === "function") $openList();
} else { } else {
window.open(data.link, "_blank"); window.open(data.link, "_blank");
} };
}; };
</script> </script>

View File

@ -47,7 +47,7 @@ const siteUrl = computed(() => {
if (url.startsWith("http://") || url.startsWith("https://")) { if (url.startsWith("http://") || url.startsWith("https://")) {
const urlFormat = url.replace(/^(https?:\/\/)/, ""); const urlFormat = url.replace(/^(https?:\/\/)/, "");
return urlFormat.split("."); return urlFormat.split(".");
} };
return url.split("."); return url.split(".");
}); });
@ -76,7 +76,7 @@ const changeBox = () => {
const vstyle = import.meta.env.VITE_TTS_Style; const vstyle = import.meta.env.VITE_TTS_Style;
SpeechLocal("分辨率不足.mp3"); SpeechLocal("分辨率不足.mp3");
}; };
} };
}; };
// //
@ -95,7 +95,7 @@ watch(
} else { } else {
descriptionText.hello = import.meta.env.VITE_DESC_HELLO; descriptionText.hello = import.meta.env.VITE_DESC_HELLO;
descriptionText.text = import.meta.env.VITE_DESC_TEXT; descriptionText.text = import.meta.env.VITE_DESC_TEXT;
} };
}, },
); );
</script> </script>

View File

@ -13,10 +13,8 @@ import APlayer from "@worstone/vue-aplayer";
import { Speech, stopSpeech, SpeechLocal } from "@/utils/speech"; import { Speech, stopSpeech, SpeechLocal } from "@/utils/speech";
import { decodeYrc } from "../utils/decodeYrc"; import { decodeYrc } from "../utils/decodeYrc";
let lastTimestamp = Date.now();
let webglRenderer;
const store = mainStore(); const store = mainStore();
let lastTimestamp = Date.now();
// DOM // DOM
const player = ref(null); const player = ref(null);
@ -175,8 +173,12 @@ const onPause = () => {
store.setPlayerState(player.value.audioRef.paused); store.setPlayerState(player.value.audioRef.paused);
}; };
let nowLineStart = -1
// //
function showYrc() { function showYrc() {
// YRC ...bushi... qrc yrc
try {
// try 西[20720,-4200]西 try
if (player.value == null) { if (player.value == null) {
return requestAnimationFrame(showYrc); return requestAnimationFrame(showYrc);
} }
@ -213,12 +215,20 @@ function showYrc() {
return; return;
}; };
// AMLL TTML Database // AMLL TTML Database
const songIdMatch = yrcUrl.match(/netease.*?id=(.*?)&/); const songUrlInf = new URLSearchParams(new URL(yrcUrl).search)
const songId = songIdMatch ? songIdMatch[1] : null; const songId = songUrlInf.get('id')
const songServer = songUrlInf.get("server");
if (!songId) { if (!songId) {
return; return;
}; };
const amllUrl = `https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/ncm-lyrics/${songId}.yrc`; 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) return fetch(amllUrl)
.then((response) => { .then((response) => {
if (!response.ok) { if (!response.ok) {
@ -245,15 +255,22 @@ function showYrc() {
} }
let lrc = lyrics[lyricIndex][1]; let lrc = lyrics[lyricIndex][1];
if (lrc === "Loading") { if (lrc === "Loading") {
lrc = "歌词加载中"; lrc = "歌词加载中...";
} else if (lrc === "Not available") { } else if (lrc === "Not available") {
if (store.playerYrcATDB) { if (store.playerYrcATDB) {
// //
const lrcUrlw = aplayer.audio[aplayer.index]["lrc"]; const songUrlInfw = new URLSearchParams(new URL(yrcUrl).search)
const songIdMatchlrc = lrcUrlw.match(/netease.*?id=(.*?)&/); const songIdlrc = songUrlInfw.get('id')
const songIdlrc = songIdMatchlrc ? songIdMatchlrc[1] : null; const songServerlrc = songUrlInfw.get("server");
if (songIdlrc) { if (songIdlrc) {
const amllUrllrc = `https://raw.githubusercontent.com/Steve-xmh/amll-ttml-db/main/ncm-lyrics/${songIdlrc}.lrc`; 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) fetch(amllUrllrc)
.then((response) => { .then((response) => {
if (response.status === 404 || !response.ok) { if (response.status === 404 || !response.ok) {
@ -274,51 +291,80 @@ function showYrc() {
const output = [[true, 1, lyricIndex, 0, lrc]]; const output = [[true, 1, lyricIndex, 0, lrc]];
if (store.playerLrc.toString() != output.toString()) { if (store.playerLrc.toString() != output.toString()) {
store.setPlayerLrc(output); store.setPlayerLrc(output);
} };
return requestAnimationFrame(showYrc); 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 now = player.value.audioStatus.playedTime * 1000;
const yrcFiltered = store.yrcTemp.filter((i) => i[0] < now); const yrcFiltered = store.yrcTemp.filter((i) => i[0] < now);
const yrc1 = document.querySelector(".yrc-1") let animationTmp = [];
if (yrc1 == null) {
return requestAnimationFrame(showYrc);
}
const yrcLyric = const yrcLyric =
yrcFiltered.length > 0 yrcFiltered.length > 0
? yrcFiltered.splice(-1)[0][2].map((it) => { ? yrcFiltered.slice(-1)[0][2].map((it) => {
const [[start, duration], word, line, row] = it; const [[start, duration], word, line, row] = it;
const isCurrent = now >= start && now <= start + duration; const isCurrent = now >= start && now <= start + duration;
const isSungLyrics = start + duration < now; const isSungLyrics = start + duration < now;
if (!isCurrent) {
return [isCurrent, isSungLyrics, line, row, word, "auto"]; 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}`]]; : [[true, 1, 0, 0, `${store.playerTitle} - ${store.playerArtist}`]];
if (store.playerLrc.toString() != yrcLyric.toString()) { if (store.playerLrc.toString() != yrcLyric.toString()) {
store.setPlayerLrc(yrcLyric); store.setPlayerLrc(yrcLyric);
} };
if (store.playerYrcShowPro) { if (store.playerYrcShowPro) {
webglRenderer.render(yrcLyric); // 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); requestAnimationFrame(showYrc);
} } catch (error) {
requestAnimationFrame(showYrc);
};
};
requestAnimationFrame(showYrc); requestAnimationFrame(showYrc);
// //

View File

@ -59,7 +59,7 @@
<el-switch v-model="playerYrcShow" inline-prompt :active-icon="CheckSmall" :inactive-icon="CloseSmall" /> <el-switch v-model="playerYrcShow" inline-prompt :active-icon="CheckSmall" :inactive-icon="CloseSmall" />
</div> </div>
<div v-if="playerLrcShow && playerYrcShow" class="item"> <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" /> <el-switch v-model="playerYrcShowPro" inline-prompt :active-icon="CheckSmall" :inactive-icon="CloseSmall" />
</div> </div>
</el-collapse-item> </el-collapse-item>

View File

@ -16,7 +16,7 @@
剩余&nbsp;{{ item.remaining }}&nbsp;{{ tag === "day" ? "小时" : "天" }} 剩余&nbsp;{{ item.remaining }}&nbsp;{{ tag === "day" ? "小时" : "天" }}
</span> </span>
</div> </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>
<!-- 建站日期 --> <!-- 建站日期 -->
<div v-if="store.siteStartShow" class="capsule-item start"> <div v-if="store.siteStartShow" class="capsule-item start">

View File

@ -20,6 +20,9 @@
<script setup> <script setup>
import { getAdcode, getWeather, getOtherWeather } from "@/api"; import { getAdcode, getWeather, getOtherWeather } from "@/api";
import { Error } from "@icon-park/vue-next"; import { Error } from "@icon-park/vue-next";
import { mainStore } from "@/store";
import { Speech, stopSpeech, SpeechLocal } from "@/utils/speech";
const store = mainStore();
// Key // Key
const mainKey = import.meta.env.VITE_WEATHER_KEY; const mainKey = import.meta.env.VITE_WEATHER_KEY;

View File

@ -1,6 +1,7 @@
import { createApp } from "vue"; import { createApp } from "vue";
import "@/style/style.scss"; import "@/style/style.scss";
import App from "@/App.vue"; import App from "@/App.vue";
import { mainStore } from "@/store";
import { Speech, stopSpeech, SpeechLocal } from "@/utils/speech"; import { Speech, stopSpeech, SpeechLocal } from "@/utils/speech";
// 引入 pinia // 引入 pinia
import { createPinia } from 'pinia'; import { createPinia } from 'pinia';
@ -22,30 +23,32 @@ window.addEventListener("beforeunload", () => {
// 这堆代码原本的意义是在于强制刷新这些本不需要被 pinia 缓存的变量,不知为什么这些变量只会在关闭页面重新输入域名访问才能恢复,导致刷新页面部分模块短时间内出现异常。 // 这堆代码原本的意义是在于强制刷新这些本不需要被 pinia 缓存的变量,不知为什么这些变量只会在关闭页面重新输入域名访问才能恢复,导致刷新页面部分模块短时间内出现异常。
// 但是貌似这堆代码也没能解决问题...罢了,先暂且留着叭() // 但是貌似这堆代码也没能解决问题...罢了,先暂且留着叭()
const store = mainStore(); const store = mainStore();
store.imgLoadStatus = false; // 壁纸加载状态 Object.assign(store, {
store.innerWidth = null; // 当前窗口宽度 imgLoadStatus: false, // 壁纸加载状态
store.musicIsOk = false; // 音乐是否加载完成 innerWidth: null, // 当前窗口宽度
store.musicOpenState = false; // 音乐面板开启状态 musicIsOk: false, // 音乐是否加载完成
store.backgroundShow = false; // 壁纸展示状态 musicOpenState: false, // 音乐面板开启状态
store.boxOpenState = false; // 盒子开启状态 backgroundShow: false, // 壁纸展示状态
store.mobileOpenState = false; // 移动端开启状态 boxOpenState: false, // 盒子开启状态
store.mobileFuncState = false; // 移动端功能区开启状态 mobileOpenState: false, // 移动端开启状态
store.setOpenState = false; // 设置页面开启状态 mobileFuncState: false, // 移动端功能区开启状态
store.playerState = false; // 当前播放状态 setOpenState: false, // 设置页面开启状态
store.playerTitle = null; // 当前播放歌曲名 playerState: false, // 当前播放状态
store.playerArtist = null; // 当前播放歌手名 playerTitle: null, // 当前播放歌曲名
store.playerLrc = [[true, "猫猫正在翻找歌词..."]]; // 当前播放歌词 playerArtist: null, // 当前播放歌手名
store.yrcIndex = -1; // 逐字歌词进度存储 playerLrc: [[true, "歌词加载中..."]], // 当前播放歌词
store.yrcTemp = []; // 逐字歌词缓存 yrcIndex: -1, // 逐字歌词进度存储
store.yrcEnable = true; yrcTemp: [], // 逐字歌词缓存
store.yrcLoading = false; yrcEnable: true,
yrcLoading: false,
});
}); });
app.use(pinia); app.use(pinia);
app.mount("#app"); app.mount("#app");
// PWA // PWA
navigator.serviceWorker.addEventListener("controllerchange", () => { navigator.serviceWorker.addEventListener("controllerchange", async () => {
// 弹出更新提醒 // 弹出更新提醒
console.log("站点已更新,刷新后生效"); console.log("站点已更新,刷新后生效");
ElMessage("站点已更新,刷新后生效"); ElMessage("站点已更新,刷新后生效");

View File

@ -24,10 +24,10 @@ export const mainStore = defineStore("main", {
playerAutoplay: true, // 是否自动播放 playerAutoplay: true, // 是否自动播放
playerLoop: "all", // 循环播放 "all", "one", "none" playerLoop: "all", // 循环播放 "all", "one", "none"
playerOrder: "random", // 循环顺序 "list", "random" playerOrder: "random", // 循环顺序 "list", "random"
webSpeech: false, // 网页语音交互总开关(包含播报歌名功能) webSpeech: true, // 网页语音交互总开关(包含播报歌名功能)
playerSpeechName: true, // 播报歌名 playerSpeechName: true, // 播报歌名
playerYrcShow: true, // 逐字歌词解析总开关 playerYrcShow: true, // 逐字歌词解析总开关
playerYrcShowPro: false, // 逐字效果增强开关(更高的性能要求) playerYrcShowPro: false, // 逐字效果增强开关
playerYrcATDB: true, // 允许接入 AMLL TTML Database playerYrcATDB: true, // 允许接入 AMLL TTML Database
yrcIndex: -1, // 逐字歌词进度存储 yrcIndex: -1, // 逐字歌词进度存储
yrcTemp: [], // 逐字歌词缓存 yrcTemp: [], // 逐字歌词缓存

View File

@ -110,7 +110,7 @@ export function stopSpeech() {
} }
export function SpeechLocal(fileName) { export function SpeechLocal(fileName) {
// 考虑到生成延迟,所以加了这个,仅必要模块调用 api 实时生成,其它模块使用预先生成好的音频 // 考虑到生成延迟,所以加了这个,仅必要模块调用 api 实时生成,其它模块使用预先生成好的音频。记得根据需求更换自己的音频文件哇!
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!fileName) { if (!fileName) {
reject(new Error("No file name provided")); reject(new Error("No file name provided"));