@@ -372,123 +406,182 @@ export default class Settings {
}
};
+ #updateOptions(id, array) {
+ const e = document.getElementById(id);
+ const value = array.map(item => `
`)
+ if (e) {
+ e.innerHTML = value.join("");
+ }
+ return value
+ }
+
#addEventListeners() {
const _this = this;
+ const listeners = [
+ {
+ id: "fps_slider", event: "change", handler: e => {
+ _this.#sync(e.currentTarget, "fps_input");
+ _this.setFPS(e.currentTarget.value);
+ }
+ }, {
+ id: "fps_slider", event: "input", handler: e => {
+ _this.#sync(e.currentTarget, "fps_input");
+ }
+ }, {
+ id: "fps_input", event: "change", handler: e => {
+ _this.#sync(e.currentTarget, "fps_slider");
+ _this.setFPS(e.currentTarget.value);
+ }
+ }, {
+ id: "operator_logo", event: "click", handler: e => {
+ _this.#showRelated(e.currentTarget, "operator_logo_realted");
+ _this.setLogoDisplay(!e.currentTarget.checked)
+ }
+ }, {
+ id: "logo_image", event: "change", handler: e => _this.setLogoImage(e)
+ }, {
+ id: "logo_image_clear", event: "click", handler: e => _this.resetLogoImage()
+ }, {
+ id: "logo_ratio_slider", event: "input", handler: e => {
+ _this.#sync(e.currentTarget, "logo_ratio_input");
+ _this.setLogoRatio(e.currentTarget.value);
+ }
+ }, {
+ id: "logo_ratio_input", event: "change", handler: e => {
+ _this.#sync(e.currentTarget, "logo_ratio_slider");
+ _this.setLogoRatio(e.currentTarget.value);
+ }
+ }, {
+ id: "logo_opacity_slider", event: "input", handler: e => {
+ _this.#sync(e.currentTarget, "logo_opacity_input");
+ _this.setLogoOpacity(e.currentTarget.value);
+ }
+ }, {
+ id: "logo_opacity_input", event: "change", handler: e => {
+ _this.#sync(e.currentTarget, "logo_opacity_slider");
+ _this.setLogoOpacity(e.currentTarget.value);
+ }
+ }, {
+ id: "logo_padding_x_slider", event: "input", handler: e => {
+ _this.#sync(e.currentTarget, "logo_padding_x_input");
+ _this.logoPadding("x", e.currentTarget.value);
+ }
+ }, {
+ id: "logo_padding_x_input", event: "change", handler: e => {
+ _this.#sync(e.currentTarget, "logo_padding_x_slider");
+ _this.logoPadding("x", e.currentTarget.value);
+ }
+ }, {
+ id: "logo_padding_y_slider", event: "input", handler: e => {
+ _this.#sync(e.currentTarget, "logo_padding_y_input");
+ _this.logoPadding("y", e.currentTarget.value);
+ }
+ }, {
+ id: "logo_padding_y_input", event: "change", handler: e => {
+ _this.#sync(e.currentTarget, "logo_padding_y_slider");
+ _this.logoPadding("y", e.currentTarget.value);
+ }
+ }, {
+ id: "default_background_select", event: "change", handler: e => _this.setDefaultBackground(e.currentTarget.value)
+ }, {
+ id: "custom_background", event: "change", handler: e => _this.setBackground(e)
+ }, {
+ id: "custom_background_clear", event: "click", handler: e => _this.resetBackground()
+ }, {
+ id: "voice", event: "click", handler: e => {
+ _this.#showRelated(e.currentTarget, "voice_realted");
+ window.voice.useVoice = e.currentTarget.checked;
+ }
+ }, {
+ id: "voice_lang_select", event: "change", handler: e => {
+ window.voice.language = e.currentTarget.value
+ _this.#updateOptions("subtitle_lang_select", window.voice.subtitleLanguages)
+ }
+ }, {
+ id: "voice_idle_duration_input", event: "change", handler: e => {
+ window.voice.idleDuration = parseInt(e.currentTarget.value)
+ }
+ }, {
+ id: "voice_next_duration_input", event: "change", handler: e => {
+ window.voice.nextDuration = parseInt(e.currentTarget.value)
+ }
+ }, {
+ id: "subtitle", event: "click", handler: e => {
+ _this.#showRelated(e.currentTarget, "subtitle_realted");
+ window.voice.useSubtitle = e.currentTarget.checked;
+ }
+ }, {
+ id: "subtitle_lang_select", event: "change", handler: e => window.voice.subtitleLanguage = e.currentTarget.value
+ }, {
+ id: "voice_actor", event: "click", handler: e => {
+ window.voice.useVoiceActor = e.currentTarget.checked;
+ }
+ }, {
+ id: "position", event: "click", handler: e => {
+ _this.#showRelated(e.currentTarget, "position_realted");
+ if (!e.currentTarget.checked) _this.positionReset();
+ }
+ }, {
+ id: "position_padding_left_slider", event: "input", handler: e => {
+ _this.#sync(e.currentTarget, "position_padding_left_input");
+ _this.positionPadding("left", e.currentTarget.value);
+ }
+ }, {
+ id: "position_padding_left_input", event: "change", handler: e => {
+ _this.#sync(e.currentTarget, "position_padding_left_slider");
+ _this.positionPadding("left", e.currentTarget.value);
+ }
+ }, {
+ id: "position_padding_right_slider", event: "input", handler: e => {
+ _this.#sync(e.currentTarget, "position_padding_right_input");
+ _this.positionPadding("right", e.currentTarget.value);
+ }
+ }, {
+ id: "position_padding_right_input", event: "change", handler: e => {
+ _this.#sync(e.currentTarget, "position_padding_right_slider");
+ _this.positionPadding("right", e.currentTarget.value);
+ }
+ }, {
+ id: "position_padding_top_slider", event: "input", handler: e => {
+ _this.#sync(e.currentTarget, "position_padding_top_input");
+ _this.positionPadding("top", e.currentTarget.value);
+ }
+ }, {
+ id: "position_padding_top_input", event: "change", handler: e => {
+ _this.#sync(e.currentTarget, "position_padding_top_slider");
+ _this.positionPadding("top", e.currentTarget.value);
+ }
+ }, {
+ id: "position_padding_bottom_slider", event: "input", handler: e => {
+ _this.#sync(e.currentTarget, "position_padding_bottom_input");
+ _this.positionPadding("bottom", e.currentTarget.value);
+ }
+ }, {
+ id: "position_padding_bottom_input", event: "change", handler: e => {
+ _this.#sync(e.currentTarget, "position_padding_bottom_slider");
+ _this.positionPadding("bottom", e.currentTarget.value);
+ }
+ }, {
+ id: "settings_play", event: "click", handler: e => {
+ this.spinePlayer.play();
+ e.currentTarget.disabled = true;
+ document.getElementById("settings_pause").disabled = false;
+ }
+ }, {
+ id: "settings_pause", event: "click", handler: e => {
+ this.spinePlayer.pause();
+ e.currentTarget.disabled = true;
+ document.getElementById("settings_play").disabled = false;
+ }
+ }, {
+ id: "settings_reset", event: "click", handler: e => _this.reset()
+ }, {
+ id: "settings_close", event: "click", handler: e => _this.close()
+ },
+ ]
- document.getElementById("fps_slider").addEventListener("change", e => {
- _this.#sync(e.currentTarget, "fps_input");
- _this.setFPS(e.currentTarget.value);
- })
- document.getElementById("fps_input").addEventListener("change", e => {
- _this.#sync(e.currentTarget, "fps_slider");
- _this.setFPS(e.currentTarget.value);
- })
-
- document.getElementById("operator_logo").addEventListener("click", e => {
- _this.#showRelated(e.currentTarget, "operator_logo_realted");
- _this.setLogoDisplay(!e.currentTarget.checked)
- })
-
- document.getElementById("logo_image").addEventListener("change", e => _this.setLogoImage(e))
- document.getElementById("logo_image_clear").addEventListener("click", e => this.resetLogoImage())
-
- document.getElementById("logo_ratio_slider").addEventListener("input", e => {
- _this.#sync(e.currentTarget, "logo_ratio_input");
- _this.setLogoRatio(e.currentTarget.value);
- })
- document.getElementById("logo_ratio_input").addEventListener("change", e => {
- _this.#sync(e.currentTarget, "logo_ratio_slider");
- _this.setLogoRatio(e.currentTarget.value);
- })
-
- document.getElementById("logo_opacity_slider").addEventListener("input", e => {
- _this.#sync(e.currentTarget, "logo_opacity_input");
- _this.setLogoOpacity(e.currentTarget.value);
- })
- document.getElementById("logo_opacity_input").addEventListener("change", e => {
- _this.#sync(e.currentTarget, "logo_opacity_slider");
- _this.setLogoOpacity(e.currentTarget.value);
- })
-
- document.getElementById("logo_padding_x_slider").addEventListener("input", e => {
- _this.#sync(e.currentTarget, "logo_padding_x_input");
- _this.logoPadding("x", e.currentTarget.value);
- })
- document.getElementById("logo_padding_x_input").addEventListener("change", e => {
- _this.#sync(e.currentTarget, "logo_padding_x_slider");
- _this.logoPadding("x", e.currentTarget.value);
- })
-
- document.getElementById("logo_padding_y_slider").addEventListener("input", e => {
- _this.#sync(e.currentTarget, "logo_padding_y_input");
- _this.logoPadding("y", e.currentTarget.value);
- })
- document.getElementById("logo_padding_y_input").addEventListener("change", e => {
- _this.#sync(e.currentTarget, "logo_padding_y_slider");
- _this.logoPadding("y", e.currentTarget.value);
- })
-
- document.getElementById('default_background_select').addEventListener("change", e => _this.setDefaultBackground(e.currentTarget.value))
-
- document.getElementById("custom_background").addEventListener("change", e => _this.setBackground(e))
- document.getElementById("custom_background_clear").addEventListener("click", e => _this.resetBackground())
-
- document.getElementById("position").addEventListener("click", e => {
- _this.#showRelated(e.currentTarget, "position_realted");
- if (!e.currentTarget.checked) _this.positionReset();
- })
-
- document.getElementById("position_padding_left_slider").addEventListener("input", e => {
- _this.#sync(e.currentTarget, "position_padding_left_input");
- _this.positionPadding("left", e.currentTarget.value);
- })
- document.getElementById("position_padding_left_input").addEventListener("change", e => {
- _this.#sync(e.currentTarget, "position_padding_left_slider");
- _this.positionPadding("left", e.currentTarget.value);
- })
-
- document.getElementById("position_padding_right_slider").addEventListener("input", e => {
- _this.#sync(e.currentTarget, "position_padding_right_input");
- _this.positionPadding("right", e.currentTarget.value);
- })
- document.getElementById("position_padding_right_input").addEventListener("change", e => {
- _this.#sync(e.currentTarget, "position_padding_right_slider");
- _this.positionPadding("right", e.currentTarget.value);
- })
-
- document.getElementById("position_padding_top_slider").addEventListener("input", e => {
- _this.#sync(e.currentTarget, "position_padding_top_input");
- _this.positionPadding("top", e.currentTarget.value);
- })
- document.getElementById("position_padding_top_input").addEventListener("change", e => {
- _this.#sync(e.currentTarget, "position_padding_top_slider");
- _this.positionPadding("top", e.currentTarget.value);
- })
-
- document.getElementById("position_padding_bottom_slider").addEventListener("input", e => {
- _this.#sync(e.currentTarget, "position_padding_bottom_input");
- _this.positionPadding("bottom", e.currentTarget.value);
- })
- document.getElementById("position_padding_bottom_input").addEventListener("change", e => {
- _this.#sync(e.currentTarget, "position_padding_bottom_slider");
- _this.positionPadding("bottom", e.currentTarget.value);
- })
-
- document.getElementById("settings_play").addEventListener("click", e => {
- this.spinePlayer.play();
- e.currentTarget.disabled = true;
- document.getElementById("settings_pause").disabled = false;
- })
- document.getElementById("settings_pause").addEventListener("click", e => {
- this.spinePlayer.pause();
- e.currentTarget.disabled = true;
- document.getElementById("settings_play").disabled = false;
- })
- document.getElementById("settings_reset").addEventListener("click", e => {
- _this.reset();
- })
- document.getElementById("settings_close").addEventListener("click", e => {
- _this.close();
+ listeners.forEach(listener => {
+ document.getElementById(listener.id).addEventListener(listener.event, e => listener.handler(e))
})
}
}
\ No newline at end of file
diff --git a/src/components/voice.js b/src/components/voice.js
index 91460fd..1a0a9a1 100644
--- a/src/components/voice.js
+++ b/src/components/voice.js
@@ -1,6 +1,254 @@
import charword_table from '!/charword_table.json'
import '@/components/voice.css'
-export default function Voice() {
-
+export default class Voice {
+ #el
+ #defaultVoiceLang = "JP"
+ #defaultRegion = charword_table.config.default_region
+ #defaultIdleDuration = 10 * 60 * 1000
+ #defaultNextDuration = 3 * 60 * 1000
+ #voiceLang = this.#defaultVoiceLang
+ #subtitleLang = this.#defaultRegion
+ #useSubtitle = false
+ #useVoice = false
+ #useVoiceActor = false
+ #currentVoiceId = null
+ #lastVoiceId = null
+ #idleListener = -1
+ #idleDuration = this.#defaultIdleDuration
+ #nextListener = -1
+ #nextDuration = this.#defaultNextDuration
+ #lastClickToNext = false
+
+ constructor(el) {
+ this.#el = el
+ }
+
+ init() {
+ this.#playTitleVoice()
+ }
+
+ success() {
+ this.#playEntryVoice()
+ this.#initNextVoiceTimer()
+ document.addEventListener('click', e => {
+ this.#lastClickToNext = true
+ this.#nextVoice()
+ })
+ document.addEventListener('mousemove', e => {
+ if (this.#idleListener === -1) {
+ this.#initIdleVoiceTimer()
+ }
+ })
+ }
+
+ /**
+ * @param {boolean} show
+ */
+ set useSubtitle(show) {
+ this.#useSubtitle = show
+ }
+
+ /**
+ * @param {boolean} show
+ */
+ set useVoice(show) {
+ this.#useVoice = show
+ }
+
+ /**
+ * @param {boolean} show
+ */
+ set useVoiceActor(show) {
+ this.#useVoiceActor = show
+ }
+
+ /**
+ * @param {string} lang
+ */
+ set subtitleLanguage(lang) {
+ if (this.#getSubtitleLanguages().includes(lang)) {
+ this.#subtitleLang = lang
+ } else {
+ this.#subtitleLang = this.#defaultRegion
+ }
+ }
+
+ get subtitleLanguage() {
+ return this.#subtitleLang
+ }
+
+ get subtitleLanguages() {
+ return this.#getSubtitleLanguages()
+ }
+
+ /**
+ * @param {string} lang
+ */
+ set language(lang) {
+ if (this.#getVoiceLanguages().includes(lang)) {
+ this.#voiceLang = lang
+ } else {
+ this.#voiceLang = this.#defaultVoiceLang
+ }
+ const availableSubtitleLang = this.#getSubtitleLanguages()
+ if (!availableSubtitleLang.includes(this.#subtitleLang)) {
+ this.#subtitleLang = availableSubtitleLang[0]
+ }
+ }
+
+ get language() {
+ return this.#voiceLang
+ }
+
+ get languages() {
+ return this.#getVoiceLanguages()
+ }
+
+ /**
+ * @param {int} duration
+ */
+ set idleDuration(duration) {
+ clearInterval(this.#idleListener)
+ if (duration !== 0) {
+ this.#idleDuration = duration * 60 * 1000
+ this.#initIdleVoiceTimer()
+ }
+ }
+
+ get idleDuration() {
+ return this.#idleDuration / 60 / 1000
+ }
+
+ /**
+ * @param {int} duration
+ */
+ set nextDuration(duration) {
+ clearInterval(this.#nextListener)
+ if (duration !== 0) {
+ this.#nextDuration = duration * 1000
+ this.#initNextVoiceTimer()
+ }
+ }
+
+ get nextDuration() {
+ return this.#nextDuration / 60 / 1000
+ }
+
+ #playTitleVoice() {
+ this.#playSpecialVoice("标题")
+ }
+
+ #initIdleVoiceTimer() {
+ this.#idleListener = setInterval(() => {
+ this.#playSpecialVoice("闲置")
+ clearInterval(this.#idleListener)
+ this.#idleListener = -1
+ }, this.#idleDuration)
+ }
+
+ #initNextVoiceTimer() {
+ this.#nextListener = setInterval(() => {
+ if (!this.#lastClickToNext) {
+ this.#nextVoice()
+ }
+ }, this.#nextDuration)
+ }
+
+ #nextVoice() {
+ this.#playVoice("CN_001")
+ }
+
+ #playEntryVoice() {
+ this.#playSpecialVoice("问候")
+ }
+
+ #setCurrentSubtitle(id) {
+ console.log(id, this.#getSubtitleById(id))
+ }
+
+ #playVoice(id) {
+ this.#currentVoiceId = id
+ const audio = new Audio()
+ // audio.src = `https://cdn.jsdelivr.net/gh/Arondight/Adachi-BOT@master/src/assets/voice/${id}.mp3`
+ audio.play()
+ audio.addEventListener('ended', () => {
+ this.#lastVoiceId = this.#currentVoiceId
+ this.#currentVoiceId = null
+ this.#setCurrentSubtitle(null)
+ this.#lastClickToNext = false
+ })
+ this.#setCurrentSubtitle(id)
+ }
+
+ #playSpecialVoice(matcher) {
+ const voiceId = this.#getSpecialVoiceId(matcher)
+ this.#playVoice(voiceId)
+ }
+
+ #getSpecialVoiceId(matcher) {
+ const voices = this.#getVoices()
+ const voiceId = Object.keys(voices).find(e => voices[e].title === matcher)
+ return voiceId
+ }
+
+ #getVoices() {
+ return charword_table.operator.voice[this.#defaultRegion][this.#getWordKeyByVoiceLang()[this.#defaultVoiceLang]]
+ }
+
+ #getSubtitleById(id) {
+ return charword_table.operator.voice[this.#subtitleLang][this.#getWordKeyByVoiceLang()[this.#voiceLang]][id]
+ }
+
+ #getVoiceLanguages() {
+ return Object.keys(this.#getCVInfo(this.#defaultRegion))
+ }
+
+ /**
+ * @returns the cvInfo in the region's language
+ */
+ #getCVInfo(region) {
+ const infoArray = Object.values(charword_table.operator.info[region])
+ // combine the infoArray
+ let output = {}
+ for (const info of infoArray) {
+ output = {
+ ...output,
+ ...info
+ }
+ }
+ return output
+ }
+
+ /**
+ * @returns the cvInfo corresponsing to the voice language
+ */
+ #getCVInfoByVoiceLang() {
+ const languages = {}
+ for (const lang of Object.keys(charword_table.operator.info)) {
+ const cvInfo = this.#getCVInfo(lang)
+ for (const [voiceLanguage, cvArray] of Object.entries(cvInfo)) {
+ if (languages[voiceLanguage] === undefined) {
+ languages[voiceLanguage] = {}
+ }
+ languages[voiceLanguage][lang] = cvArray
+ }
+ }
+ return languages
+ }
+
+ #getWordKeyByVoiceLang() {
+ const output = {}
+ for (const [wordKey, wordKeyDict] of Object.entries(charword_table.operator.info[this.#defaultRegion])) {
+ for (const lang of Object.keys(wordKeyDict)) {
+ output[lang] = wordKey
+ }
+ }
+ return output
+ }
+
+ #getSubtitleLanguages() {
+ return Object.keys(this.#getCVInfoByVoiceLang()[this.#voiceLang])
+ }
+
}
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index fff63cc..00a3e4f 100644
--- a/src/index.js
+++ b/src/index.js
@@ -2,6 +2,7 @@ import '@/index.css'
import '@/libs/wallpaper_engine'
import check_web_gl from '@/libs/check_web_gl'
import Settings from '@/components/settings'
+import Voice from '@/components/voice'
document.querySelector('#app').innerHTML = `

@@ -11,10 +12,12 @@ document.querySelector('#app').innerHTML = `
style="background-image: url(./assets/${import.meta.env.VITE_FALLBACK_FILENAME}.png)"
hidden
>