feat(showcase): add operator voice
This commit is contained in:
@@ -55,6 +55,7 @@ export default function spinePlayer(el) {
|
||||
entry.mixDuration = 0.3;
|
||||
widget.animationState.addAnimation(0, "Idle", true, 0);
|
||||
}
|
||||
window.voice.success()
|
||||
window.settings.success()
|
||||
},
|
||||
})
|
||||
|
||||
@@ -38,6 +38,8 @@ export default class Settings {
|
||||
#logoX = this.#defaultLogoX
|
||||
#logoY = this.#defaultLogoY
|
||||
#isInsightsInited = false
|
||||
#doNotTrack = false
|
||||
#lastFunctionInsights = null
|
||||
|
||||
constructor(el, logoEl) {
|
||||
this.#el = el
|
||||
@@ -65,22 +67,31 @@ export default class Settings {
|
||||
|
||||
success() {
|
||||
this.loadViewport()
|
||||
this.insights(false)
|
||||
this.insights(false, false)
|
||||
}
|
||||
|
||||
insights(flag) {
|
||||
if (this.#isInsightsInited) return
|
||||
window.umami.trackView(`/${import.meta.env.VITE_LINK}${flag ? "?steam" : ""}`);
|
||||
insights(isWallpaperEngine, doNotTrack) {
|
||||
this.#isInsightsInited = true
|
||||
if (this.#isInsightsInited || doNotTrack || import.meta.env.MODE === 'development') return
|
||||
this.#doNotTrack = doNotTrack
|
||||
window.umami?.trackView(`/${import.meta.env.VITE_LINK}${isWallpaperEngine ? "?steam" : ""}`);
|
||||
}
|
||||
|
||||
functionInsights(functionName) {
|
||||
if (!this.#isInsightsInited || this.#doNotTrack || import.meta.env.MODE === 'development' || functionName === this.#lastFunctionInsights) return
|
||||
this.#lastFunctionInsights = functionName
|
||||
window.umami?.trackEvent(`${functionName}`);
|
||||
}
|
||||
|
||||
setFPS(value) {
|
||||
this.#fps = value
|
||||
this.spinePlayer.setFps(value)
|
||||
this.functionInsights("setFPS")
|
||||
}
|
||||
|
||||
setLogoDisplay(flag) {
|
||||
this.#logoEl.hidden = flag;
|
||||
this.functionInsights("setLogoDisplay")
|
||||
}
|
||||
|
||||
#resize(_this, value) {
|
||||
@@ -101,6 +112,7 @@ export default class Settings {
|
||||
this.#logoEl.src = src
|
||||
this.#resize()
|
||||
this.#setLogoInvertFilter(invert_filter)
|
||||
this.functionInsights("setLogo")
|
||||
}
|
||||
|
||||
#readFile(e, onload, callback) {
|
||||
@@ -131,23 +143,27 @@ export default class Settings {
|
||||
setLogoRatio(value) {
|
||||
this.#ratio = value
|
||||
this.#resize(this, value)
|
||||
this.functionInsights("setLogoRatio")
|
||||
}
|
||||
|
||||
setLogoOpacity(value) {
|
||||
this.#logoEl.style.opacity = value / 100
|
||||
this.#opacity = value
|
||||
this.functionInsights("setLogoOpacity")
|
||||
}
|
||||
|
||||
setBackgoundImage(v) {
|
||||
setBackgoundImage(v, skipInsights = false) {
|
||||
document.body.style.backgroundImage = v
|
||||
if (!skipInsights) this.functionInsights("setBackgoundImage");
|
||||
}
|
||||
|
||||
setDefaultBackground(e) {
|
||||
const backgroundURL = `url("${import.meta.env.BASE_URL}assets/${import.meta.env.VITE_BACKGROUND_FOLDER}/${e}")`
|
||||
if (document.getElementById("custom_background_clear").disabled && !document.body.style.backgroundImage.startsWith("url(\"file:")) {
|
||||
this.setBackgoundImage(backgroundURL)
|
||||
this.setBackgoundImage(backgroundURL, true)
|
||||
}
|
||||
this.#defaultBackgroundImage = backgroundURL
|
||||
this.functionInsights("setDefaultBackground")
|
||||
}
|
||||
|
||||
setBackground(e) {
|
||||
@@ -198,6 +214,7 @@ export default class Settings {
|
||||
break;
|
||||
}
|
||||
this.loadViewport()
|
||||
this.functionInsights("positionPadding")
|
||||
}
|
||||
|
||||
positionReset() {
|
||||
@@ -242,6 +259,7 @@ export default class Settings {
|
||||
break;
|
||||
}
|
||||
this.elementPosition(this.#logoEl, this.#logoX, this.#logoY)
|
||||
this.functionInsights("logoPadding")
|
||||
}
|
||||
|
||||
logoReset() {
|
||||
|
||||
@@ -3,11 +3,15 @@ import '@/components/voice.css'
|
||||
|
||||
export default class Voice {
|
||||
#el
|
||||
#widgetEl
|
||||
#audioEl = new Audio()
|
||||
#audioElId = 'voice-audio'
|
||||
#defaultVoiceLang = "JP"
|
||||
#defaultRegion = charword_table.config.default_region
|
||||
#defaultIdleDuration = 10 * 60 * 1000
|
||||
#defaultNextDuration = 3 * 60 * 1000
|
||||
#voiceLang = this.#defaultVoiceLang
|
||||
#voiceLanguages = Object.keys(this.#getCVInfo(this.#defaultRegion))
|
||||
#subtitleLang = this.#defaultRegion
|
||||
#useSubtitle = false
|
||||
#useVoice = false
|
||||
@@ -19,19 +23,22 @@ export default class Voice {
|
||||
#nextListener = -1
|
||||
#nextDuration = this.#defaultNextDuration
|
||||
#lastClickToNext = false
|
||||
#voiceFolderObject = this.#getVoiceFolderObject()
|
||||
|
||||
constructor(el) {
|
||||
constructor(el, widgetEl) {
|
||||
this.#el = el
|
||||
this.#widgetEl = widgetEl
|
||||
}
|
||||
|
||||
init() {
|
||||
this.#playTitleVoice()
|
||||
this.#insertHTML()
|
||||
this.#audioEl = document.getElementById(this.#audioElId)
|
||||
}
|
||||
|
||||
success() {
|
||||
this.#playEntryVoice()
|
||||
this.#initNextVoiceTimer()
|
||||
document.addEventListener('click', e => {
|
||||
this.#widgetEl.addEventListener('click', e => {
|
||||
this.#lastClickToNext = true
|
||||
this.#nextVoice()
|
||||
})
|
||||
@@ -86,7 +93,7 @@ export default class Voice {
|
||||
* @param {string} lang
|
||||
*/
|
||||
set language(lang) {
|
||||
if (this.#getVoiceLanguages().includes(lang)) {
|
||||
if (this.#voiceLanguages.includes(lang)) {
|
||||
this.#voiceLang = lang
|
||||
} else {
|
||||
this.#voiceLang = this.#defaultVoiceLang
|
||||
@@ -102,7 +109,7 @@ export default class Voice {
|
||||
}
|
||||
|
||||
get languages() {
|
||||
return this.#getVoiceLanguages()
|
||||
return this.#voiceLanguages
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,10 +142,6 @@ export default class Voice {
|
||||
return this.#nextDuration / 60 / 1000
|
||||
}
|
||||
|
||||
#playTitleVoice() {
|
||||
this.#playSpecialVoice("标题")
|
||||
}
|
||||
|
||||
#initIdleVoiceTimer() {
|
||||
this.#idleListener = setInterval(() => {
|
||||
this.#playSpecialVoice("闲置")
|
||||
@@ -169,16 +172,26 @@ export default class Voice {
|
||||
|
||||
#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)
|
||||
this.#audioEl.src = `./assets/${this.#getVoiceFoler()
|
||||
}/${id}.wav`
|
||||
let startPlayPromise = this.#audioEl.play()
|
||||
if (startPlayPromise !== undefined) {
|
||||
startPlayPromise
|
||||
.then(() => {
|
||||
const audioEndedFunc = () => {
|
||||
this.#lastVoiceId = this.#currentVoiceId
|
||||
this.#currentVoiceId = null
|
||||
this.#setCurrentSubtitle(null)
|
||||
this.#lastClickToNext = false
|
||||
this.#audioEl.removeEventListener('ended', audioEndedFunc)
|
||||
}
|
||||
this.#audioEl.addEventListener('ended', audioEndedFunc)
|
||||
this.#setCurrentSubtitle(id)
|
||||
})
|
||||
.catch(() => {
|
||||
return
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#playSpecialVoice(matcher) {
|
||||
@@ -186,6 +199,11 @@ export default class Voice {
|
||||
this.#playVoice(voiceId)
|
||||
}
|
||||
|
||||
#getVoiceFoler() {
|
||||
const folderObject = this.#voiceFolderObject
|
||||
return `${folderObject.main}/${folderObject.sub.find(e => e.lang === this.#voiceLang).name}`
|
||||
}
|
||||
|
||||
#getSpecialVoiceId(matcher) {
|
||||
const voices = this.#getVoices()
|
||||
const voiceId = Object.keys(voices).find(e => voices[e].title === matcher)
|
||||
@@ -200,8 +218,17 @@ export default class Voice {
|
||||
return charword_table.operator.voice[this.#subtitleLang][this.#getWordKeyByVoiceLang()[this.#voiceLang]][id]
|
||||
}
|
||||
|
||||
#getVoiceLanguages() {
|
||||
return Object.keys(this.#getCVInfo(this.#defaultRegion))
|
||||
#getVoiceFolderObject() {
|
||||
const folderObject = JSON.parse(import.meta.env.VITE_VOICE_FOLDERS)
|
||||
const languagesCopy = this.#voiceLanguages.slice()
|
||||
const customVoiceName = languagesCopy.filter(i => !folderObject.sub.map(e => e.lang).includes(i))[0]
|
||||
folderObject.sub = folderObject.sub.map(e => {
|
||||
return {
|
||||
name: e.name,
|
||||
lang: e.lang === "CUSTOM" ? customVoiceName : e.lang
|
||||
}
|
||||
})
|
||||
return folderObject
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -251,4 +278,12 @@ export default class Voice {
|
||||
return Object.keys(this.#getCVInfoByVoiceLang()[this.#voiceLang])
|
||||
}
|
||||
|
||||
#insertHTML() {
|
||||
this.#el.innerHTML = `
|
||||
<audio id="${this.#audioElId}" autoplay>
|
||||
<source type="audio/wav">
|
||||
Your browser does not support the audio element.
|
||||
</audio>
|
||||
`
|
||||
}
|
||||
}
|
||||
@@ -7,16 +7,16 @@ import Voice from '@/components/voice'
|
||||
document.querySelector('#app').innerHTML = `
|
||||
<img src="./assets/${import.meta.env.VITE_LOGO_FILENAME}.png" class="logo invert-filter" id="logo" alt="operator logo" />
|
||||
<div id="settings"></div>
|
||||
<div id="voice" hidden></div>
|
||||
<div id="widget-wrapper">
|
||||
<div id="fallback"
|
||||
style="background-image: url(./assets/${import.meta.env.VITE_FALLBACK_FILENAME}.png)"
|
||||
hidden
|
||||
></div>
|
||||
<div id="player" hidden></div>
|
||||
<div id="voice" hidden></div>
|
||||
</div>
|
||||
`
|
||||
window.voice = new Voice(document.querySelector('#voice'))
|
||||
window.voice = new Voice(document.querySelector('#voice'), document.querySelector('#widget-wrapper'))
|
||||
window.voice.init()
|
||||
window.settings = new Settings(document.querySelector('#settings'), document.querySelector('#logo'))
|
||||
document.title = import.meta.env.VITE_TITLE
|
||||
|
||||
@@ -5,7 +5,7 @@ window.wallpaperPropertyListener = {
|
||||
}
|
||||
},
|
||||
applyUserProperties: function (properties) {
|
||||
window.settings.insights(true)
|
||||
window.settings.insights(true, false)
|
||||
if (properties.logo) {
|
||||
window.settings.setLogoDisplay(!properties.logo.value)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user