feat: code cleanup
This commit is contained in:
25
README.md
25
README.md
@@ -47,28 +47,11 @@ To generate the latest charword_table.json
|
||||
```
|
||||
### Webpage & JavaScript
|
||||
|
||||
Add query string `settings` to bring up the settings panel to adjust your settings. Then use appropriate JavaScript code to load your settings
|
||||
Add query string `aklive2d` to bring up the settings panel to adjust your settings.
|
||||
Settings can be adjusted under `window.aklive2d` or by dispatching custom events (under `window.aklive2d.events`) to `document`.
|
||||
Examples can be found at `showcase/src/libs/wallpaper_engine.js`.
|
||||
|
||||
``` javascript
|
||||
settings.setFPS(integer) // set FPS
|
||||
settings.setLogoDisplay(boolean) // display logo or not
|
||||
settings.setLogoRatio(float) // the ratio of the logo
|
||||
settings.setLogoOpacity(float) // the opacity of the logo
|
||||
settings.setLogo(url) // change the logo, url: image url, removeInvert: boolean
|
||||
settings.resetLogoImage() // reset to the default logo
|
||||
settings.setDefaultBackground(url) // change the default background, url: image filename from `background` folder
|
||||
settings.setBackgoundImage(url) // change the background, url: image url
|
||||
settings.resetBackground() // reset to the default background
|
||||
settings.positionPadding("left", integer) // left padding
|
||||
settings.positionPadding("right", integer) // right padding
|
||||
settings.positionPadding("top", integer) // top padding
|
||||
settings.positionPadding("bottom", integer) // bottom padding
|
||||
settings.positionReset() // reset the position
|
||||
|
||||
settings.open() // open settings panel
|
||||
settings.close() // close settings panel
|
||||
settings.reset() // reset settings
|
||||
```
|
||||
Using JS events to change settings is recommended.
|
||||
|
||||
## Config
|
||||
### General Config
|
||||
|
||||
@@ -5,6 +5,7 @@ import Player from "@/components/player";
|
||||
import Background from "@/components/background";
|
||||
import Logo from "@/components/logo";
|
||||
import Insight from "@/components/insight";
|
||||
import * as Event from "@/components/event";
|
||||
import {
|
||||
isWebGLSupported,
|
||||
insertHTMLChild,
|
||||
@@ -17,11 +18,11 @@ export default class AKLive2D {
|
||||
#el = document.createElement("div")
|
||||
#appEl
|
||||
#queries = new URLSearchParams(window.location.search)
|
||||
#voice = new Voice()
|
||||
#music = new Music()
|
||||
#player = new Player()
|
||||
#background = new Background()
|
||||
#logo = new Logo()
|
||||
#voice
|
||||
#music
|
||||
#player
|
||||
#background
|
||||
#logo
|
||||
#insight = new Insight()
|
||||
|
||||
constructor(appEl) {
|
||||
@@ -32,18 +33,16 @@ export default class AKLive2D {
|
||||
document.addEventListener("gesturestart", e => e.preventDefault());
|
||||
|
||||
this.#appEl = appEl
|
||||
this.#logo = new Logo(this.#appEl)
|
||||
this.#background = new Background(this.#appEl)
|
||||
this.#voice = new Voice(this.#appEl)
|
||||
this.#music = new Music(this.#appEl)
|
||||
if (isWebGLSupported()) {
|
||||
this.#player = new Player(this.#appEl)
|
||||
} else {
|
||||
new Fallback(this.#appEl)
|
||||
}
|
||||
|
||||
init() {
|
||||
this.#logo.init(this.#appEl);
|
||||
this.#background.init(this.#appEl);
|
||||
this.#voice.init(this.#appEl);
|
||||
this.#music.init(this.#appEl);
|
||||
if (isWebGLSupported()) {
|
||||
this.#player.init(this.#appEl);
|
||||
} else {
|
||||
(new Fallback()).init(this.#appEl)
|
||||
}
|
||||
this.#el.id = "settings-box"
|
||||
this.#el.hidden = true
|
||||
this.#el.innerHTML = `
|
||||
@@ -63,15 +62,8 @@ export default class AKLive2D {
|
||||
insertHTMLChild(this.#appEl, this.#el)
|
||||
addEventListeners([
|
||||
{
|
||||
event: "player-ready", handler: () => this.success()
|
||||
},
|
||||
...this.#logo.listeners,
|
||||
...this.#background.listeners,
|
||||
...this.#player.listeners,
|
||||
...this.#voice.listeners,
|
||||
...this.#music.listeners,
|
||||
...this.#insight.listeners,
|
||||
{
|
||||
event: "player-ready", handler: () => this.#success()
|
||||
}, {
|
||||
id: "settings-reset", event: "click", handler: () => this.reset()
|
||||
}, {
|
||||
id: "settings-close", event: "click", handler: () => this.close()
|
||||
@@ -79,10 +71,54 @@ export default class AKLive2D {
|
||||
id: "settings-to-directory", event: "click", handler: () => {
|
||||
window.location.href = '/';
|
||||
}
|
||||
}
|
||||
},
|
||||
...this.#logo.listeners,
|
||||
...this.#background.listeners,
|
||||
...this.#player.listeners,
|
||||
...this.#voice.listeners,
|
||||
...this.#music.listeners,
|
||||
...this.#insight.listeners,
|
||||
])
|
||||
}
|
||||
|
||||
get voice() {
|
||||
return this.#voice
|
||||
}
|
||||
|
||||
get music() {
|
||||
return this.#music
|
||||
}
|
||||
|
||||
get player() {
|
||||
return this.#player
|
||||
}
|
||||
|
||||
get background() {
|
||||
return this.#background
|
||||
}
|
||||
|
||||
get logo() {
|
||||
return this.#logo
|
||||
}
|
||||
|
||||
get events() {
|
||||
return Event
|
||||
}
|
||||
|
||||
get config() {
|
||||
return {
|
||||
player: this.#player.config,
|
||||
background: this.#background.config,
|
||||
logo: this.#logo.config,
|
||||
music: this.#music.config,
|
||||
voice: this.#voice.config
|
||||
}
|
||||
}
|
||||
|
||||
get configStr() {
|
||||
return JSON.stringify(this.config, null)
|
||||
}
|
||||
|
||||
open() {
|
||||
this.#el.hidden = false;
|
||||
}
|
||||
@@ -96,59 +132,36 @@ export default class AKLive2D {
|
||||
this.#background.reset()
|
||||
this.#logo.reset()
|
||||
this.#voice.reset()
|
||||
this.#music.reset()
|
||||
}
|
||||
|
||||
success() {
|
||||
#success() {
|
||||
this.#music.link(this.#background)
|
||||
this.#background.link(this.#music)
|
||||
this.#voice.link(this.#player)
|
||||
this.#player.success()
|
||||
this.#voice.success()
|
||||
this.#music.success()
|
||||
this.#insight.success()
|
||||
if (this.#queries.has("settings") || this.#queries.has("aklive2d") || import.meta.env.MODE === 'development') {
|
||||
if (this.#queries.has("aklive2d") || import.meta.env.MODE === 'development') {
|
||||
this.open()
|
||||
}
|
||||
this.#backCompatibility()
|
||||
this.#registerBackCompatibilityFns()
|
||||
}
|
||||
|
||||
#backCompatibility() {
|
||||
window.voice = this.#voice
|
||||
window.music = this.#music
|
||||
#registerBackCompatibilityFns() {
|
||||
const _this = this
|
||||
window.voice = _this.#voice
|
||||
window.music = _this.#music
|
||||
window.settings = {
|
||||
spinePlayer: this.#player.spine,
|
||||
setFPS: this.#player.setFPS,
|
||||
setLogoDisplay: this.#logo.setLogoDisplay,
|
||||
setLogo: this.#logo.setLogo,
|
||||
setLogoImage: this.#logo.setLogoImage,
|
||||
resetLogoImage: this.#logo.resetLogoImage,
|
||||
setLogoRatio: this.#logo.setLogoRatio,
|
||||
setLogoOpacity: this.#logo.setLogoOpacity,
|
||||
setBackgoundImage: this.#background.setBackgroundImage,
|
||||
currentBackground: this.#background.currentBackground,
|
||||
setDefaultBackground: this.#background.setDefaultBackground,
|
||||
setBackground: this.#background.setBackground,
|
||||
resetBackground: this.#background.resetBackground,
|
||||
loadViewport: this.#player.loadViewport,
|
||||
setScale: this.#player.setScale,
|
||||
scale: this.#player.scale,
|
||||
positionPadding: this.#player.positionPadding,
|
||||
positionReset: this.#player.positionReset,
|
||||
scaleReset: this.#player.scaleReset,
|
||||
elementPosition: updateElementPosition,
|
||||
logoPadding: this.#logo.logoPadding,
|
||||
logoReset: this.#logo.logoReset,
|
||||
useStartAnimation: this.#player.useStartAnimation,
|
||||
open: this.open,
|
||||
close: this.close,
|
||||
reset: this.reset,
|
||||
setMusicFromWE: this.#music.setMusicFromWE,
|
||||
setMusic: this.#music.setMusic,
|
||||
resetMusic: this.#music.resetMusic,
|
||||
setVideo: this.#background.setVideo,
|
||||
setVideoVolume: this.#background.setVideoVolume,
|
||||
getVideoVolume: this.#background.getVideoVolume,
|
||||
setVideoFromWE: this.#background.setVideoFromWE,
|
||||
resetVideo: this.#background.resetVideo
|
||||
open: _this.open,
|
||||
close: _this.close,
|
||||
reset: _this.reset,
|
||||
..._this.#player.backCompatibilityFns,
|
||||
..._this.#logo.backCompatibilityFns,
|
||||
..._this.#music.backCompatibilityFns,
|
||||
..._this.#background.backCompatibilityFns
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,16 @@ export default class Background {
|
||||
image: "operator_bg.png"
|
||||
}
|
||||
#config = {
|
||||
image: null
|
||||
video: {
|
||||
name: null,
|
||||
volume: 100,
|
||||
},
|
||||
useVideo: false,
|
||||
name: null
|
||||
}
|
||||
#musicObj
|
||||
|
||||
init(el) {
|
||||
constructor(el) {
|
||||
this.#parentEl = el
|
||||
this.#el.id = "background-box"
|
||||
this.image = this.#default.location + this.#default.image
|
||||
@@ -31,119 +36,20 @@ export default class Background {
|
||||
this.#videoEl = document.getElementById("video-src")
|
||||
}
|
||||
|
||||
set image(v) {
|
||||
this.#el.style.backgroundImage = `url("${v}")`
|
||||
}
|
||||
|
||||
set video(v) {
|
||||
const update = (url) => {
|
||||
this.#videoEl.src = url
|
||||
this.#videoEl.load()
|
||||
document.getElementById("custom-video-background-clear").disabled = false
|
||||
}
|
||||
if (typeof v === "object") {
|
||||
readFile(
|
||||
v,
|
||||
(blobURL) => update(blobURL)
|
||||
)
|
||||
} else {
|
||||
update(v)
|
||||
}
|
||||
}
|
||||
|
||||
get volume() {
|
||||
return this.#videoEl.volume * 100
|
||||
}
|
||||
|
||||
set volume(v) {
|
||||
this.#videoEl.volume = parseInt(v) / 100
|
||||
}
|
||||
|
||||
get current() {
|
||||
return this.#config.image || this.#default.image
|
||||
}
|
||||
|
||||
set default(v) {
|
||||
this.#default.image = v
|
||||
if (!this.#config.image) {
|
||||
this.image = this.#default.location + this.#default.image
|
||||
}
|
||||
}
|
||||
|
||||
set custom(v) {
|
||||
const update = (url) => {
|
||||
this.#config.image = v
|
||||
this.image = url
|
||||
document.getElementById("custom-background-clear").disabled = false
|
||||
}
|
||||
if (typeof v === "object") {
|
||||
readFile(
|
||||
v,
|
||||
(blobURL) => update(blobURL)
|
||||
)
|
||||
} else {
|
||||
update(v)
|
||||
}
|
||||
}
|
||||
|
||||
setVideoFromWE(url) {
|
||||
// Note: Back Compatibility
|
||||
this.video = url
|
||||
}
|
||||
|
||||
get currentBackground() {
|
||||
// Note: Back Compatibility
|
||||
return this.current
|
||||
}
|
||||
|
||||
resetImage() {
|
||||
document.getElementById("custom-background").value = ""
|
||||
document.getElementById("custom-background-clear").disabled = true
|
||||
this.#config.image = null
|
||||
this.#config.name = null
|
||||
this.image = this.#default.location + this.#default.image
|
||||
}
|
||||
|
||||
resetVideo() {
|
||||
this.#config.video.name = null
|
||||
this.#videoEl.src = ""
|
||||
document.getElementById("custom-video-background").value = ""
|
||||
document.getElementById("custom-video-background-clear").disabled = true
|
||||
}
|
||||
|
||||
setBackgroundImage(v) {
|
||||
// Note: Back Compatibility
|
||||
this.image = v
|
||||
}
|
||||
|
||||
setDefaultBackground(v) {
|
||||
// Note: Back Compatibility
|
||||
this.default = v
|
||||
}
|
||||
|
||||
setBackground(v) {
|
||||
// Note: Back Compatibility
|
||||
this.custom = v
|
||||
}
|
||||
|
||||
resetBackground() {
|
||||
// Note: Back Compatibility
|
||||
this.resetImage()
|
||||
}
|
||||
|
||||
setVideo(e) {
|
||||
// Note: Back Compatibility
|
||||
this.video = e.target.files[0]
|
||||
}
|
||||
|
||||
getVideoVolume() {
|
||||
// Note: Back Compatibility
|
||||
return this.volume
|
||||
}
|
||||
|
||||
setVideoVolume(v) {
|
||||
// Note: Back Compatibility
|
||||
this.volume = v
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.resetImage()
|
||||
this.resetVideo()
|
||||
@@ -153,6 +59,100 @@ export default class Background {
|
||||
this.#musicObj = musicObj
|
||||
}
|
||||
|
||||
get useVideo() {
|
||||
return this.#config.useVideo
|
||||
}
|
||||
|
||||
set useVideo(v) {
|
||||
this.#config.useVideo = v
|
||||
}
|
||||
|
||||
set image(v) {
|
||||
this.#el.style.backgroundImage = `url("${v}")`
|
||||
}
|
||||
|
||||
set video(v) {
|
||||
const update = (url, v = null) => {
|
||||
this.#config.video.name = {
|
||||
isLocalFile: v !== null,
|
||||
value: v ? v.name : url
|
||||
}
|
||||
this.#videoEl.src = url
|
||||
this.#videoEl.load()
|
||||
document.getElementById("custom-video-background-clear").disabled = false
|
||||
}
|
||||
if (typeof v === "object") {
|
||||
readFile(
|
||||
v,
|
||||
(blobURL) => update(blobURL, v)
|
||||
)
|
||||
} else {
|
||||
update(v)
|
||||
}
|
||||
}
|
||||
|
||||
get volume() {
|
||||
return this.#config.video.volume
|
||||
}
|
||||
|
||||
set volume(v) {
|
||||
v = parseInt(v)
|
||||
this.#config.video.volume = v
|
||||
this.#videoEl.volume = v / 100
|
||||
}
|
||||
|
||||
get current() {
|
||||
return this.#config.name || this.#default.image
|
||||
}
|
||||
|
||||
set default(v) {
|
||||
this.#default.image = v
|
||||
this.#musicObj.music = v
|
||||
this.image = this.#default.location + this.#default.image
|
||||
}
|
||||
|
||||
set custom(v) {
|
||||
const update = (url, v = null) => {
|
||||
this.#config.name = {
|
||||
isLocalFile: v !== null,
|
||||
value: v ? v.name : url
|
||||
}
|
||||
this.image = url
|
||||
document.getElementById("custom-background-clear").disabled = false
|
||||
}
|
||||
if (typeof v === "object") {
|
||||
readFile(
|
||||
v,
|
||||
(blobURL) => update(blobURL, v)
|
||||
)
|
||||
} else {
|
||||
update(v)
|
||||
}
|
||||
}
|
||||
|
||||
get config() {
|
||||
return {
|
||||
default: this.#default.image,
|
||||
...this.#config
|
||||
}
|
||||
}
|
||||
|
||||
get backCompatibilityFns() {
|
||||
const _this = this
|
||||
return {
|
||||
currentBackground: _this.current,
|
||||
setBackgoundImage: (v) => _this.image = v,
|
||||
setDefaultBackground: (v) => _this.default = v,
|
||||
setBackground: (v) => _this.custom = v,
|
||||
resetBackground: _this.resetImage,
|
||||
setVideo: (e) => _this.video = e.target.files[0],
|
||||
getVideoVolume: () => _this.volume,
|
||||
setVideoVolume: (v) => _this.volume = v,
|
||||
setVideoFromWE: (url) => _this.video = url,
|
||||
resetVideo: _this.resetVideo
|
||||
}
|
||||
}
|
||||
|
||||
get HTML() {
|
||||
return `
|
||||
<div>
|
||||
@@ -163,19 +163,29 @@ export default class Background {
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="custom-background"> Custom Background (Store Locally)</label>
|
||||
<label for="custom-background">Custom Background (Store Locally)</label>
|
||||
<input type="file" id="custom-background" accept="image/*"/>
|
||||
<button type="button" disabled id="custom-background-clear" disabled>Clear</button>
|
||||
<button type="button" id="custom-background-clear" ${this.#config.name ? this.#config.name.isLocalFile ? "" : "disabled" : "disabled"}>Clear</button>
|
||||
</div>
|
||||
<div>
|
||||
<label for="custom-background-url">Custom Background URL:</label>
|
||||
<input type="text" id="custom-background-url" name="custom-background-url" value="${this.#config.name ? this.#config.name.value : ""}">
|
||||
<button type="button" id="custom-background-url-apply">Apply</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label for="video">Video</label>
|
||||
<input type="checkbox" id="video" name="video" />
|
||||
<div id="video-realted" hidden>
|
||||
<input type="checkbox" id="video" name="video" ${this.useVideo ? "checked" : ""}/>
|
||||
<div id="video-realted" ${this.useVideo ? "" : "hidden"}>
|
||||
<div>
|
||||
<label for="custom-video-background"> Custom Video Background (Store Locally)</label>
|
||||
<label for="custom-video-background">Custom Video Background (Store Locally)</label>
|
||||
<input type="file" id="custom-video-background" accept="video/*"/>
|
||||
<button type="button" disabled id="custom-video-background-clear" disabled>Clear</button>
|
||||
<button type="button" id="custom-video-background-clear" ${this.#config.video.name ? this.#config.video.name.isLocalFile ? "" : "disabled" : "disabled"}>Clear</button>
|
||||
</div>
|
||||
<div>
|
||||
<label for="custom-video-background-url">Custom Video Background URL:</label>
|
||||
<input type="text" id="custom-video-background-url" name="custom-video-background-url" value="${this.#config.video.name ? this.#config.video.name.value : ""}">
|
||||
<button type="button" id="custom-video-background-url-apply">Apply</button>
|
||||
</div>
|
||||
<div>
|
||||
<label for="video-volume">Video Volume</label>
|
||||
@@ -204,21 +214,25 @@ export default class Background {
|
||||
}, {
|
||||
id: "default-background-select", event: "change", handler: e => {
|
||||
this.default = e.currentTarget.value
|
||||
this.#musicObj.music = e.currentTarget.value
|
||||
}
|
||||
}, {
|
||||
id: "custom-background", event: "change", handler: e => this.custom = e.target.files[0]
|
||||
}, {
|
||||
id: "custom-background-clear", event: "click", handler: () => this.resetImage()
|
||||
}, {
|
||||
id: "custom-background-url-apply", event: "click", handler: () => this.custom = document.getElementById("custom-background-url").value
|
||||
}, {
|
||||
id: "video", event: "click", handler: e => {
|
||||
showRelatedHTML(e.currentTarget, "video-realted");
|
||||
this.useVideo = e.currentTarget.checked
|
||||
if (!e.currentTarget.checked) this.resetVideo()
|
||||
}
|
||||
}, {
|
||||
id: "custom-video-background", event: "change", handler: e => this.video = e.target.files[0]
|
||||
}, {
|
||||
id: "custom-video-background-clear", event: "click", handler: () => this.resetVideo()
|
||||
}, {
|
||||
id: "custom-video-background-url-apply", event: "click", handler: () => this.video = document.getElementById("custom-video-background-url").value
|
||||
}, {
|
||||
id: "video-volume-slider", event: "input", handler: e => {
|
||||
syncHTMLValue(e.currentTarget, "video-volume-input");
|
||||
|
||||
@@ -4,7 +4,7 @@ import '@/components/fallback.css'
|
||||
export default class Fallback {
|
||||
#el = document.createElement("div")
|
||||
|
||||
init(parentEl) {
|
||||
constructor(parentEl) {
|
||||
alert('WebGL is unavailable. Fallback image will be used.');
|
||||
const calculateScale = (width, height) => {
|
||||
return { x: window.innerWidth / width, y: window.innerHeight / height };
|
||||
|
||||
@@ -42,10 +42,10 @@ export const updateHTMLOptions = (array, id = null) => {
|
||||
|
||||
export const addEventListeners = (listeners) => {
|
||||
listeners.forEach(listener => {
|
||||
if (typeof listener.id === "undefined") {
|
||||
document.addEventListener(listener.event, e => listener.handler(e))
|
||||
} else {
|
||||
if (listener.id) {
|
||||
document.getElementById(listener.id).addEventListener(listener.event, e => listener.handler(e))
|
||||
} else {
|
||||
document.addEventListener(listener.event, e => listener.handler(e))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -27,10 +27,11 @@ export default class Logo {
|
||||
hidden: this.#default.hidden,
|
||||
ratio: this.#default.ratio,
|
||||
opacity: this.#default.opacity,
|
||||
position: {...this.#default.position}
|
||||
position: { ...this.#default.position },
|
||||
name: null
|
||||
}
|
||||
|
||||
init(el) {
|
||||
constructor(el) {
|
||||
this.#parentEl = el
|
||||
this.#el.id = "logo-box"
|
||||
this.#el.innerHTML = `
|
||||
@@ -43,34 +44,48 @@ export default class Logo {
|
||||
this.#updateSizeOnWindowResize()
|
||||
}
|
||||
|
||||
#updateSizeOnWindowResize() {
|
||||
const _this = this
|
||||
const resize = () => {
|
||||
_this.#resize(_this)
|
||||
}
|
||||
window.addEventListener("resize", resize, true);
|
||||
resize()
|
||||
}
|
||||
|
||||
setImage(src, invertFilter = false) {
|
||||
this.#imageEl.src = src
|
||||
this.#resize()
|
||||
this.#setInvertFilter(invertFilter)
|
||||
}
|
||||
|
||||
set image(v) {
|
||||
const update = (url) => {
|
||||
this.setImage(url, false)
|
||||
document.getElementById("logo-image-clear").disabled = false
|
||||
resetPosition() {
|
||||
this.position = {...this.#default.position}
|
||||
document.getElementById("logo-position-x-slider").value = this.#default.position.x
|
||||
document.getElementById("logo-position-x-input").value = this.#default.position.x
|
||||
document.getElementById("logo-position-y-slider").value = this.#default.position.y
|
||||
document.getElementById("logo-position-y-input").value = this.#default.position.y
|
||||
}
|
||||
if (typeof v === "object") {
|
||||
readFile(
|
||||
v,
|
||||
(blobURL) => update(blobURL)
|
||||
)
|
||||
} else {
|
||||
update(v)
|
||||
|
||||
resetImage() {
|
||||
this.#config.name = null
|
||||
this.setImage(this.#default.location + this.#default.image, this.#default.useInvertFilter)
|
||||
document.getElementById("logo-image-clear").disabled = true
|
||||
}
|
||||
|
||||
resetOpacity() {
|
||||
this.opacity = this.#default.opacity
|
||||
document.getElementById("logo-opacity-slider").value = this.#default.opacity
|
||||
document.getElementById("logo-opacity-input").value = this.#default.opacity
|
||||
}
|
||||
|
||||
resetHidden() {
|
||||
this.hidden = this.#default.hidden
|
||||
}
|
||||
|
||||
resetRatio() {
|
||||
this.ratio = this.#default.ratio
|
||||
document.getElementById("logo-ratio-slider").value = this.#default.ratio
|
||||
document.getElementById("logo-ratio-input").value = this.#default.ratio
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.resetPosition()
|
||||
this.resetImage()
|
||||
this.resetRatio()
|
||||
this.resetOpacity()
|
||||
this.resetHidden()
|
||||
}
|
||||
|
||||
#resize(_this, value) {
|
||||
@@ -87,6 +102,38 @@ export default class Logo {
|
||||
}
|
||||
}
|
||||
|
||||
#updateLogoPosition() {
|
||||
updateElementPosition(this.#imageEl, this.#config.position)
|
||||
}
|
||||
|
||||
#updateSizeOnWindowResize() {
|
||||
const _this = this
|
||||
const resize = () => {
|
||||
_this.#resize(_this)
|
||||
}
|
||||
window.addEventListener("resize", resize, true);
|
||||
resize()
|
||||
}
|
||||
|
||||
set image(v) {
|
||||
const update = (url, v = null) => {
|
||||
this.#config.name = {
|
||||
isLocalFile: v !== null,
|
||||
value: v ? v.name : url
|
||||
}
|
||||
this.setImage(url, false)
|
||||
document.getElementById("logo-image-clear").disabled = false
|
||||
}
|
||||
if (typeof v === "object") {
|
||||
readFile(
|
||||
v,
|
||||
(blobURL) => update(blobURL, v)
|
||||
)
|
||||
} else {
|
||||
update(v)
|
||||
}
|
||||
}
|
||||
|
||||
get hidden() {
|
||||
return this.#config.hidden
|
||||
}
|
||||
@@ -140,17 +187,21 @@ export default class Logo {
|
||||
|
||||
set position(v) {
|
||||
if (typeof v !== "object") return;
|
||||
if (typeof v.x !== "undefined") this.#config.position.x = v.x;
|
||||
if (typeof v.y !== "undefined") this.#config.position.y = v.y;
|
||||
if (v.x) this.#config.position.x = v.x;
|
||||
if (v.y) this.#config.position.y = v.y;
|
||||
this.#updateLogoPosition()
|
||||
}
|
||||
|
||||
#updateLogoPosition() {
|
||||
updateElementPosition(this.#imageEl, this.#config.position)
|
||||
}
|
||||
|
||||
logoPadding(key, value) {
|
||||
// Note: Back Compatibility
|
||||
get backCompatibilityFns() {
|
||||
const _this = this
|
||||
return {
|
||||
setLogoDisplay: (v) => _this.hidden = v,
|
||||
setLogo: _this.setImage,
|
||||
setLogoImage: (e) => _this.image = e.target.files[0],
|
||||
resetLogoImage: _this.resetImage,
|
||||
setLogoRatio: (v) => _this.ratio = v,
|
||||
setLogoOpacity: (v) => _this.opacity = v,
|
||||
logoPadding: (key, value) => {
|
||||
switch (key) {
|
||||
case "x":
|
||||
this.position = {
|
||||
@@ -166,89 +217,31 @@ export default class Logo {
|
||||
this.position = value
|
||||
break;
|
||||
}
|
||||
},
|
||||
logoReset: _this.resetPosition
|
||||
}
|
||||
}
|
||||
|
||||
setLogoOpacity(v) {
|
||||
// Note: Back Compatibility
|
||||
this.opacity = v
|
||||
get config() {
|
||||
return {
|
||||
...this.#config
|
||||
}
|
||||
|
||||
setLogoRatio(value) {
|
||||
// Note: Back Compatibility
|
||||
this.ratio = value
|
||||
}
|
||||
|
||||
setLogoDisplay(flag) {
|
||||
// Note: Back Compatibility
|
||||
this.hidden = flag;
|
||||
}
|
||||
|
||||
setLogo(src, invertFilter) {
|
||||
// Note: Back Compatibility
|
||||
this.setImage(src, invertFilter)
|
||||
}
|
||||
|
||||
setLogoImage(e) {
|
||||
// Note: Back Compatibility
|
||||
this.image = e.target.files[0]
|
||||
}
|
||||
|
||||
resetPosition() {
|
||||
this.position = {...this.#default.position}
|
||||
document.getElementById("logo-position-x-slider").value = this.#default.position.x
|
||||
document.getElementById("logo-position-x-input").value = this.#default.position.x
|
||||
document.getElementById("logo-position-y-slider").value = this.#default.position.y
|
||||
document.getElementById("logo-position-y-input").value = this.#default.position.y
|
||||
}
|
||||
|
||||
logoReset() {
|
||||
// Note: Back Compatibility
|
||||
this.resetPosition()
|
||||
}
|
||||
|
||||
resetImage() {
|
||||
this.setImage(this.#default.location + this.#default.image, this.#default.useInvertFilter)
|
||||
document.getElementById("logo-image-clear").disabled = true
|
||||
}
|
||||
|
||||
resetLogoImage() {
|
||||
// Note: Back Compatibility
|
||||
this.resetImage()
|
||||
}
|
||||
|
||||
resetOpacity() {
|
||||
this.setLogoOpacity(this.#default.opacity)
|
||||
document.getElementById("logo-opacity-slider").value = this.#default.opacity
|
||||
document.getElementById("logo-opacity-input").value = this.#default.opacity
|
||||
}
|
||||
|
||||
resetHidden() {
|
||||
this.hidden = this.#default.hidden
|
||||
}
|
||||
|
||||
resetRatio() {
|
||||
this.ratio = this.#default.ratio
|
||||
document.getElementById("logo-ratio-slider").value = this.#default.ratio
|
||||
document.getElementById("logo-ratio-input").value = this.#default.ratio
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.resetPosition()
|
||||
this.resetImage()
|
||||
this.resetRatio()
|
||||
this.resetOpacity()
|
||||
this.resetHidden()
|
||||
}
|
||||
|
||||
get HTML() {
|
||||
return `
|
||||
<label for="operator-logo">Operator Logo</label>
|
||||
<input type="checkbox" id="operator-logo" name="operator-logo" checked/>
|
||||
<div id="operator-logo-realted">
|
||||
<input type="checkbox" id="operator-logo" name="operator-logo" ${this.hidden ? "" : "checked"}/>
|
||||
<div id="operator-logo-realted" ${this.hidden ? "hidden" : ""}>
|
||||
<div>
|
||||
<label for="logo-image">Logo Image (Store Locally)</label>
|
||||
<input type="file" id="logo-image" accept="image/*"/>
|
||||
<button type="button" id="logo-image-clear" disabled>Clear</button>
|
||||
<button type="button" id="logo-image-clear" ${this.#config.name ? this.#config.name.isLocalFile ? "" : "disabled" : "disabled"}>Clear</button>
|
||||
</div>
|
||||
<div>
|
||||
<label for="logo-image-url">Logo Image URL:</label>
|
||||
<input type="text" id="logo-image-url" name="logo-image-url" value="${this.#config.name ? this.#config.name.value : ""}">
|
||||
<button type="button" id="logo-image-url-apply">Apply</button>
|
||||
</div>
|
||||
<div>
|
||||
<label for="logo-ratio">Logo Ratio</label>
|
||||
@@ -297,6 +290,8 @@ export default class Logo {
|
||||
id: "logo-image", event: "change", handler: e => this.image = e.target.files[0]
|
||||
}, {
|
||||
id: "logo-image-clear", event: "click", handler: () => this.resetImage()
|
||||
}, {
|
||||
id: "logo-image-url-apply", event: "click", handler: () => this.image = document.getElementById("logo-image-url").value
|
||||
}, {
|
||||
id: "logo-ratio-slider", event: "input", handler: e => {
|
||||
syncHTMLValue(e.currentTarget, "logo-ratio-input");
|
||||
|
||||
@@ -30,60 +30,12 @@ export default class Music {
|
||||
#config = {
|
||||
useMusic: false,
|
||||
timeOffset: 0.3,
|
||||
volume: 0.5
|
||||
volume: 50,
|
||||
name: null
|
||||
}
|
||||
#backgroundObj
|
||||
|
||||
get timeOffset() {
|
||||
return this.#config.timeOffset
|
||||
}
|
||||
|
||||
set timeOffset(value) {
|
||||
this.#config.timeOffset = value
|
||||
}
|
||||
|
||||
get volume() {
|
||||
return this.#config.volume * 100
|
||||
}
|
||||
|
||||
set volume(value) {
|
||||
value = value / 100
|
||||
this.#config.volume = value
|
||||
this.#audio.intro.el.volume = value
|
||||
this.#audio.loop.el.volume = value
|
||||
}
|
||||
|
||||
get musics() {
|
||||
return this.#music.list
|
||||
}
|
||||
|
||||
get useMusic() {
|
||||
return this.#config.useMusic
|
||||
}
|
||||
|
||||
set useMusic(value) {
|
||||
this.#config.useMusic = value
|
||||
if (value) {
|
||||
this.#playMusic()
|
||||
} else {
|
||||
this.#stopMusic()
|
||||
}
|
||||
}
|
||||
|
||||
get currentMusic() {
|
||||
// Note: Back Compatibility
|
||||
return this.music
|
||||
}
|
||||
|
||||
get music() {
|
||||
return this.#music.current
|
||||
}
|
||||
|
||||
get isUsingCustom() {
|
||||
return this.#music.isUsingCustom
|
||||
}
|
||||
|
||||
init(el) {
|
||||
constructor(el) {
|
||||
this.#parentEl = el
|
||||
this.#el.id = "music-box"
|
||||
this.#el.innerHTML = `
|
||||
@@ -98,13 +50,13 @@ export default class Music {
|
||||
this.#music.list = Object.keys(this.#music.mapping)
|
||||
this.#audio.intro.el = document.getElementById(this.#audio.intro.id)
|
||||
this.#audio.loop.el = document.getElementById(this.#audio.loop.id)
|
||||
this.#audio.intro.el.volume = this.#config.volume
|
||||
this.#audio.loop.el.volume = this.#config.volume
|
||||
this.#audio.intro.el.volume = this.#volume
|
||||
this.#audio.loop.el.volume = this.#volume
|
||||
this.#audio.intro.el.ontimeupdate = () => {
|
||||
if (this.#audio.intro.el.currentTime >= this.#audio.intro.el.duration - this.#config.timeOffset) {
|
||||
this.#audio.intro.el.pause()
|
||||
this.#audio.loop.el.currentTime = 0
|
||||
this.#audio.loop.el.volume = this.#config.volume
|
||||
this.#audio.loop.el.volume = this.#volume
|
||||
}
|
||||
}
|
||||
this.#audio.loop.el.ontimeupdate = () => {
|
||||
@@ -123,62 +75,16 @@ export default class Music {
|
||||
this.#backgroundObj = backgroundObj
|
||||
}
|
||||
|
||||
changeMusic(name) {
|
||||
// Note: Back Compatibility
|
||||
this.music = name
|
||||
}
|
||||
|
||||
set music(name) {
|
||||
if (name !== null && name !== this.#music.current) {
|
||||
this.#music.current = name
|
||||
if (this.#config.useMusic && !this.#music.isUsingCustom) {
|
||||
this.#audio.loop.el.pause()
|
||||
this.#audio.intro.el.pause()
|
||||
this.#playMusic()
|
||||
}
|
||||
getCurrentHTMLOptions("music-select", name)
|
||||
}
|
||||
}
|
||||
|
||||
set custom(url) {
|
||||
const update = (url, type) => {
|
||||
this.#setMusic(url, type)
|
||||
document.getElementById("custom-music-clear").disabled = false
|
||||
}
|
||||
if (typeof url === "object") {
|
||||
readFile(
|
||||
url,
|
||||
(blobURL, type) => update(blobURL, type)
|
||||
)
|
||||
} else {
|
||||
update(url, url.split(".").pop())
|
||||
}
|
||||
}
|
||||
|
||||
setMusicFromWE(url) {
|
||||
// Note: Back Compatibility
|
||||
this.custom = url
|
||||
}
|
||||
|
||||
setMusic(e) {
|
||||
// Note: Back Compatibility
|
||||
this.custom = e.target.files[0]
|
||||
}
|
||||
|
||||
reset() {
|
||||
document.getElementById("custom-music").value = ""
|
||||
document.getElementById("custom-music-clear").disabled = true
|
||||
this.#music.isUsingCustom = false
|
||||
this.#config.name = null
|
||||
if (this.#config.useMusic) {
|
||||
this.#playMusic()
|
||||
}
|
||||
}
|
||||
|
||||
resetMusic() {
|
||||
// Note: Back Compatibility
|
||||
this.reset()
|
||||
}
|
||||
|
||||
#setMusic(data, type) {
|
||||
this.#audio.loop.el.src = data
|
||||
this.#audio.loop.el.querySelector('source').type = type
|
||||
@@ -200,12 +106,12 @@ export default class Music {
|
||||
this.#audio.loop.el.volume = 0
|
||||
this.#audio.loop.el.play()
|
||||
} else {
|
||||
this.#audio.loop.el.volume = this.#config.volume
|
||||
this.#audio.loop.el.volume = this.#volume
|
||||
this.#audio.loop.el.play()
|
||||
}
|
||||
} else {
|
||||
this.#audio.intro.el.pause()
|
||||
this.#audio.loop.el.volume = this.#config.volume
|
||||
this.#audio.loop.el.volume = this.#volume
|
||||
this.#audio.loop.el.play()
|
||||
}
|
||||
}
|
||||
@@ -215,12 +121,116 @@ export default class Music {
|
||||
this.#audio.loop.el.pause()
|
||||
}
|
||||
|
||||
get timeOffset() {
|
||||
return this.#config.timeOffset
|
||||
}
|
||||
|
||||
set timeOffset(value) {
|
||||
this.#config.timeOffset = value
|
||||
}
|
||||
|
||||
get volume() {
|
||||
return this.#config.volume
|
||||
}
|
||||
|
||||
get #volume() {
|
||||
return this.#config.volume / 100
|
||||
}
|
||||
|
||||
set volume(value) {
|
||||
this.#config.volume = value
|
||||
this.#audio.intro.el.volume = this.#volume
|
||||
if (this.#audio.intro.el.paused) this.#audio.loop.el.volume = this.#volume
|
||||
}
|
||||
|
||||
get musics() {
|
||||
return this.#music.list
|
||||
}
|
||||
|
||||
get useMusic() {
|
||||
return this.#config.useMusic
|
||||
}
|
||||
|
||||
set useMusic(value) {
|
||||
this.#config.useMusic = value
|
||||
if (value) {
|
||||
this.#playMusic()
|
||||
} else {
|
||||
this.#stopMusic()
|
||||
}
|
||||
}
|
||||
|
||||
get music() {
|
||||
return this.#music.current
|
||||
}
|
||||
|
||||
get isUsingCustom() {
|
||||
return this.#music.isUsingCustom
|
||||
}
|
||||
|
||||
set music(name) {
|
||||
if (name !== null && name !== this.#music.current) {
|
||||
this.#music.current = name
|
||||
if (this.#config.useMusic && !this.#music.isUsingCustom) {
|
||||
this.#audio.loop.el.pause()
|
||||
this.#audio.intro.el.pause()
|
||||
this.#playMusic()
|
||||
}
|
||||
getCurrentHTMLOptions("music-select", name)
|
||||
}
|
||||
}
|
||||
|
||||
set custom(url) {
|
||||
const update = (url, type, v = null) => {
|
||||
this.#config.name = {
|
||||
isLocalFile: v !== null,
|
||||
value: v ? v.name : url
|
||||
}
|
||||
this.#setMusic(url, type)
|
||||
document.getElementById("custom-music-clear").disabled = false
|
||||
}
|
||||
if (typeof url === "object") {
|
||||
readFile(
|
||||
url,
|
||||
(blobURL, type) => update(blobURL, type, url)
|
||||
)
|
||||
} else {
|
||||
update(url, url.split(".").pop())
|
||||
}
|
||||
}
|
||||
|
||||
get currentMusic() {
|
||||
// Note: Back Compatibility
|
||||
return this.music
|
||||
}
|
||||
|
||||
changeMusic(name) {
|
||||
// Note: Back Compatibility
|
||||
this.music = name
|
||||
}
|
||||
|
||||
get backCompatibilityFns() {
|
||||
const _this = this
|
||||
return {
|
||||
setMusicFromWE: (url) => _this.custom = url,
|
||||
setMusic: (e) => _this.custom = e.target.files[0],
|
||||
resetMusic: _this.reset
|
||||
}
|
||||
}
|
||||
|
||||
get config() {
|
||||
return {
|
||||
default: this.#music.current,
|
||||
...this.#config
|
||||
}
|
||||
}
|
||||
|
||||
get HTML() {
|
||||
return `
|
||||
<div>
|
||||
<label for="music">Music</label>
|
||||
<input type="checkbox" id="music" name="music" />
|
||||
<div id="music-realted" hidden>
|
||||
<input type="checkbox" id="music" name="music" ${this.useMusic ? "checked" : ""}/>
|
||||
<div id="music-realted" ${this.useMusic ? "" : "hidden"}>
|
||||
<div>
|
||||
<label for="music-select">Choose theme music:</label>
|
||||
<select name="music-select" id="music-select">
|
||||
@@ -228,9 +238,14 @@ export default class Music {
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="custom-music"> Custom Music (Store Locally)</label>
|
||||
<label for="custom-music">Custom Music (Store Locally)</label>
|
||||
<input type="file" id="custom-music" accept="audio/*"/>
|
||||
<button type="button" disabled id="custom-music-clear" disabled>Clear</button>
|
||||
<button type="button" id="custom-music-clear" ${this.#config.name ? this.#config.name.isLocalFile ? "" : "disabled" : "disabled"}>Clear</button>
|
||||
</div>
|
||||
<div>
|
||||
<label for="custom-music-url">Custom Music URL:</label>
|
||||
<input type="text" id="custom-music-url" name="custom-music-url" value="${this.#config.name ? this.#config.name.value : ""}">
|
||||
<button type="button" id="custom-music-url-apply">Apply</button>
|
||||
</div>
|
||||
<div>
|
||||
<label for="music-volume">Music Volume</label>
|
||||
@@ -270,6 +285,8 @@ export default class Music {
|
||||
id: "custom-music", event: "change", handler: e => this.custom = e.target.files[0]
|
||||
}, {
|
||||
id: "custom-music-clear", event: "click", handler: () => this.reset()
|
||||
}, {
|
||||
id: "custom-music-url-apply", event: "click", handler: () => this.custom = document.getElementById("custom-music-url").value
|
||||
}, {
|
||||
id: "music-volume-slider", event: "input", handler: e => {
|
||||
syncHTMLValue(e.currentTarget, "music-volume-input");
|
||||
|
||||
@@ -32,66 +32,14 @@ export default class Player {
|
||||
#config = {
|
||||
fps: this.#default.fps,
|
||||
useStartAnimation: true,
|
||||
padding: {...this.#default.padding},
|
||||
usePadding: false,
|
||||
padding: {
|
||||
...this.#default.padding
|
||||
},
|
||||
scale: this.#default.scale
|
||||
}
|
||||
|
||||
set useStartAnimation(v) {
|
||||
this.#config.useStartAnimation = v
|
||||
}
|
||||
|
||||
get useStartAnimation() {
|
||||
return this.#config.useStartAnimation
|
||||
}
|
||||
|
||||
get spine() {
|
||||
return this.#spine
|
||||
}
|
||||
|
||||
set fps(v) {
|
||||
this.#config.fps = v
|
||||
this.#spine.setFps(v)
|
||||
}
|
||||
|
||||
get fps() {
|
||||
return this.#config.fps
|
||||
}
|
||||
|
||||
setFPS(fps) {
|
||||
// Note: Back Compatibility
|
||||
this.fps = fps
|
||||
}
|
||||
|
||||
resetFPS() {
|
||||
this.fps = this.#default.fps
|
||||
document.getElementById("fps-slider").value = this.#default.fps
|
||||
document.getElementById("fps-input").value = this.#default.fps
|
||||
}
|
||||
|
||||
set scale(v) {
|
||||
this.#config.scale = 1 / v
|
||||
this.#spine.setOperatorScale(1 / v)
|
||||
}
|
||||
|
||||
setScale(v) {
|
||||
// Note: Back Compatibility
|
||||
this.scale = v
|
||||
}
|
||||
|
||||
resetScale() {
|
||||
this.scale = this.#default.scale
|
||||
}
|
||||
|
||||
scaleReset() {
|
||||
// Note: Back Compatibility
|
||||
this.resetScale()
|
||||
}
|
||||
|
||||
get scale() {
|
||||
return this.#config.scale
|
||||
}
|
||||
|
||||
init(el) {
|
||||
constructor(el) {
|
||||
this.#parentEl = el
|
||||
this.#el.id = "player-box"
|
||||
insertHTMLChild(this.#parentEl, this.#el)
|
||||
@@ -144,7 +92,6 @@ export default class Player {
|
||||
entry.mixDuration = 0.3;
|
||||
widget.animationState.addAnimation(0, "Idle", true, 0);
|
||||
}
|
||||
_this.success()
|
||||
document.dispatchEvent(PlayerReadyEvent);
|
||||
},
|
||||
}
|
||||
@@ -161,8 +108,33 @@ export default class Player {
|
||||
updateHTMLOptions(this.#spine.skeleton.data.animations.map(e => e.name), "animation-selection")
|
||||
}
|
||||
|
||||
get node() {
|
||||
return this.#el
|
||||
resetPadding() {
|
||||
this.padding = {...this.#default.padding}
|
||||
document.getElementById("position-padding-left-slider").value = this.#default.padding.left
|
||||
document.getElementById("position-padding-left-input").value = this.#default.padding.left
|
||||
document.getElementById("position-padding-right-slider").value = this.#default.padding.right
|
||||
document.getElementById("position-padding-right-input").value = this.#default.padding.right
|
||||
document.getElementById("position-padding-top-slider").value = this.#default.padding.top
|
||||
document.getElementById("position-padding-top-input").value = this.#default.padding.top
|
||||
document.getElementById("position-padding-bottom-slider").value = this.#default.padding.bottom
|
||||
document.getElementById("position-padding-bottom-input").value = this.#default.padding.bottom
|
||||
}
|
||||
|
||||
resetScale() {
|
||||
this.scale = this.#default.scale
|
||||
}
|
||||
|
||||
resetFPS() {
|
||||
this.fps = this.#default.fps
|
||||
document.getElementById("fps-slider").value = this.#default.fps
|
||||
document.getElementById("fps-input").value = this.#default.fps
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.resetFPS()
|
||||
this.resetPadding()
|
||||
this.resetScale()
|
||||
this.#spine.play()
|
||||
}
|
||||
|
||||
#loadViewport() {
|
||||
@@ -174,9 +146,46 @@ export default class Player {
|
||||
})
|
||||
}
|
||||
|
||||
loadViewport() {
|
||||
// Note: Back Compatibility
|
||||
this.#loadViewport()
|
||||
get usePadding() {
|
||||
return this.#config.usePadding
|
||||
}
|
||||
|
||||
set usePadding(v) {
|
||||
this.#config.usePadding = v
|
||||
}
|
||||
|
||||
set useStartAnimation(v) {
|
||||
this.#config.useStartAnimation = v
|
||||
}
|
||||
|
||||
get useStartAnimation() {
|
||||
return this.#config.useStartAnimation
|
||||
}
|
||||
|
||||
get spine() {
|
||||
return this.#spine
|
||||
}
|
||||
|
||||
set fps(v) {
|
||||
this.#config.fps = v
|
||||
this.#spine.setFps(v)
|
||||
}
|
||||
|
||||
get fps() {
|
||||
return this.#config.fps
|
||||
}
|
||||
|
||||
set scale(v) {
|
||||
this.#config.scale = 1 / v
|
||||
this.#spine.setOperatorScale(1 / v)
|
||||
}
|
||||
|
||||
get scale() {
|
||||
return this.#config.scale
|
||||
}
|
||||
|
||||
get node() {
|
||||
return this.#el
|
||||
}
|
||||
|
||||
get padLeft() {
|
||||
@@ -225,15 +234,22 @@ export default class Player {
|
||||
|
||||
set padding(v) {
|
||||
if (typeof v !== "object") return;
|
||||
if (typeof v.left !== "undefined") this.#config.padding.left = v.left;
|
||||
if (typeof v.right !== "undefined") this.#config.padding.right = v.right ;
|
||||
if (typeof v.top !== "undefined") this.#config.padding.top = v.top;
|
||||
if (typeof v.bottom !== "undefined") this.#config.padding.bottom = v.bottom;
|
||||
if (v.left) this.#config.padding.left = v.left;
|
||||
if (v.right) this.#config.padding.right = v.right ;
|
||||
if (v.top) this.#config.padding.top = v.top;
|
||||
if (v.bottom) this.#config.padding.bottom = v.bottom;
|
||||
this.#loadViewport()
|
||||
}
|
||||
|
||||
positionPadding(key, value) {
|
||||
// Note: Back Compatibility
|
||||
get backCompatibilityFns() {
|
||||
const _this = this
|
||||
return {
|
||||
spinePlayer: _this.#spine,
|
||||
setFPS: (fps) => _this.fps = fps,
|
||||
loadViewport: _this.#loadViewport,
|
||||
setScale: (v) => this.scale = v,
|
||||
scale: _this.scale,
|
||||
positionPadding: (key, value) => {
|
||||
switch (key) {
|
||||
case "left":
|
||||
this.padding = {
|
||||
@@ -259,30 +275,15 @@ export default class Player {
|
||||
this.#config.padding = value
|
||||
break;
|
||||
}
|
||||
},
|
||||
positionReset: _this.resetPadding,
|
||||
scaleReset: _this.resetScale,
|
||||
useStartAnimation: _this.useStartAnimation
|
||||
}
|
||||
}
|
||||
|
||||
resetPadding() {
|
||||
this.padding = {...this.#default.padding}
|
||||
document.getElementById("position-padding-left-slider").value = this.#default.padding.left
|
||||
document.getElementById("position-padding-left-input").value = this.#default.padding.left
|
||||
document.getElementById("position-padding-right-slider").value = this.#default.padding.right
|
||||
document.getElementById("position-padding-right-input").value = this.#default.padding.right
|
||||
document.getElementById("position-padding-top-slider").value = this.#default.padding.top
|
||||
document.getElementById("position-padding-top-input").value = this.#default.padding.top
|
||||
document.getElementById("position-padding-bottom-slider").value = this.#default.padding.bottom
|
||||
document.getElementById("position-padding-bottom-input").value = this.#default.padding.bottom
|
||||
}
|
||||
|
||||
positionReset() {
|
||||
// Note: Back Compatibility
|
||||
this.resetPadding()
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.resetFPS()
|
||||
this.resetPadding()
|
||||
this.resetScale()
|
||||
this.#spine.play()
|
||||
get config() {
|
||||
return {...this.#config}
|
||||
}
|
||||
|
||||
get HTML() {
|
||||
@@ -310,8 +311,8 @@ export default class Player {
|
||||
</div>
|
||||
<div>
|
||||
<label for="position">Position</label>
|
||||
<input type="checkbox" id="position" name="position" />
|
||||
<div id="position-realted" hidden>
|
||||
<input type="checkbox" id="position" name="position" ${this.usePadding ? "checked" : ""}/>
|
||||
<div id="position-realted" ${this.usePadding ? "" : "hidden"}>
|
||||
<div>
|
||||
<label for="position-padding-left">Padding Left</label>
|
||||
<input type="range" min="-100" max="100" id="position-padding-left-slider" value="${this.padding.left}" />
|
||||
@@ -398,6 +399,7 @@ export default class Player {
|
||||
}, {
|
||||
id: "position", event: "click", handler: e => {
|
||||
showRelatedHTML(e.currentTarget, "position-realted");
|
||||
this.usePadding = e.currentTarget.checked;
|
||||
if (!e.currentTarget.checked) this.resetPadding();
|
||||
}
|
||||
}, {
|
||||
|
||||
@@ -50,7 +50,7 @@ export default class Voice {
|
||||
useSubtitle: false,
|
||||
useVoice: false,
|
||||
useVoiceActor: false,
|
||||
voiceLang: null,
|
||||
language: null,
|
||||
subtitle: {
|
||||
language: this.#default.region,
|
||||
...this.#default.subtitle
|
||||
@@ -59,11 +59,188 @@ export default class Voice {
|
||||
}
|
||||
#playerObj
|
||||
|
||||
constructor() {
|
||||
constructor(el) {
|
||||
this.#default.language.voice = this.#voice.languages[0]
|
||||
this.#config.voiceLang = this.#default.language.voice
|
||||
this.#config.language = this.#default.language.voice
|
||||
this.#voice.locations = this.#getVoiceLocations()
|
||||
this.#voice.list = Object.keys(this.#getVoices())
|
||||
|
||||
this.#parentEl = el
|
||||
this.#el.id = "voice-box"
|
||||
this.#el.hidden = true
|
||||
this.#el.innerHTML = `
|
||||
<audio id="${this.#audio.id}" autoplay>
|
||||
<source type="audio/ogg" />
|
||||
</audio>
|
||||
<div class="voice-wrapper" id="voice-wrapper">
|
||||
<div class="voice-title" id="voice-title"></div>
|
||||
<div class="voice-subtitle">
|
||||
<div id="voice-subtitle"></div>
|
||||
<div class="voice-triangle"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="voice-actor-box" hidden>
|
||||
<div class="voice-actor">
|
||||
<span class="voice-actor-icon"></span>
|
||||
<span id="voice-actor-name" class="voice-actor-name"></span>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
insertHTMLChild(this.#parentEl, this.#el)
|
||||
}
|
||||
|
||||
success() {
|
||||
const audioEndedFunc = () => {
|
||||
this.#audio.isPlaying = false
|
||||
this.#setCurrentSubtitle(null)
|
||||
this.#audio.lastClickToNext = false
|
||||
}
|
||||
this.#audio.el.addEventListener('ended', audioEndedFunc)
|
||||
this.#playEntryVoice()
|
||||
this.#initNextVoiceTimer()
|
||||
this.#playerObj.node.addEventListener('click', () => {
|
||||
this.#audio.lastClickToNext = true
|
||||
this.#nextVoice()
|
||||
})
|
||||
document.addEventListener('mousemove', () => {
|
||||
if (this.#voice.listener.idle === -1) {
|
||||
this.#initIdleVoiceTimer()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
link(playerObj) {
|
||||
this.#playerObj = playerObj
|
||||
}
|
||||
|
||||
resetPosition() {
|
||||
this.position = {...this.#default.subtitle}
|
||||
document.getElementById("subtitle-padding-x-slider").value = this.#default.subtitle.x
|
||||
document.getElementById("subtitle-padding-x-input").value = this.#default.subtitle.x
|
||||
document.getElementById("subtitle-padding-y-slider").value = this.#default.subtitle.y
|
||||
document.getElementById("subtitle-padding-y-input").value = this.#default.subtitle.y
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.resetPosition()
|
||||
}
|
||||
|
||||
#getVoiceLocations() {
|
||||
const folders = JSON.parse(import.meta.env.VITE_VOICE_FOLDERS)
|
||||
const customVoiceName = this.#voice.languages.filter(i => !folders.sub.map(e => e.lang).includes(i))[0]
|
||||
folders.sub = folders.sub.map(e => {
|
||||
return {
|
||||
name: e.name,
|
||||
lang: e.lang === "CUSTOM" ? customVoiceName : e.lang
|
||||
}
|
||||
})
|
||||
return folders
|
||||
}
|
||||
|
||||
#getVoices() {
|
||||
return charword_table.subtitleLangs[this.#config.subtitle.language].default
|
||||
}
|
||||
|
||||
#playEntryVoice() {
|
||||
this.#playSpecialVoice("问候")
|
||||
}
|
||||
|
||||
#playSpecialVoice(matcher) {
|
||||
const voices = this.#getVoices()
|
||||
const voiceId = Object.keys(voices).find(e => voices[e].title === matcher)
|
||||
this.#playVoice(voiceId)
|
||||
}
|
||||
|
||||
#playVoice(id) {
|
||||
if (!this.useVoice) return
|
||||
this.#voice.id.last = this.#voice.id.current
|
||||
this.#voice.id.current = id
|
||||
this.#audio.el.src = `./assets/${this.#getVoiceLocation()
|
||||
}/${id}.ogg`
|
||||
let startPlayPromise = this.#audio.el.play()
|
||||
if (startPlayPromise !== undefined) {
|
||||
startPlayPromise
|
||||
.then(() => {
|
||||
this.#audio.isPlaying = true
|
||||
this.#setCurrentSubtitle(id)
|
||||
})
|
||||
.catch(() => {
|
||||
return
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#getVoiceLocation() {
|
||||
const locations = this.#voice.locations
|
||||
return `${locations.main}/${locations.sub.find(e => e.lang === this.#config.language).name}`
|
||||
}
|
||||
|
||||
#setCurrentSubtitle(id) {
|
||||
if (id === null) {
|
||||
setTimeout(() => {
|
||||
if (this.#audio.isPlaying) return
|
||||
this.#toggleSubtitle(0)
|
||||
}, 5 * 1000);
|
||||
return
|
||||
}
|
||||
const subtitle = this.#getSubtitleById(id)
|
||||
const title = subtitle.title
|
||||
const content = subtitle.text
|
||||
const cvInfo = charword_table.voiceLangs[this.subtitleLanguage][this.#config.language]
|
||||
document.getElementById('voice-title').innerText = title
|
||||
document.getElementById('voice-subtitle').innerText = content
|
||||
document.getElementById('voice-actor-name').innerText = cvInfo.join('')
|
||||
if (this.#audio.isPlaying) {
|
||||
this.#toggleSubtitle(1)
|
||||
}
|
||||
}
|
||||
|
||||
#toggleSubtitle(v) {
|
||||
this.#el.style.opacity = v ? 1 : 0
|
||||
}
|
||||
|
||||
#getSubtitleById(id) {
|
||||
const obj = charword_table.subtitleLangs[this.#config.subtitle.language]
|
||||
let key = 'default'
|
||||
if (obj[this.#config.language]) {
|
||||
key = this.#config.language
|
||||
}
|
||||
return obj[key][id]
|
||||
}
|
||||
|
||||
#getSubtitleLanguages() {
|
||||
return Object.keys(charword_table.subtitleLangs)
|
||||
}
|
||||
|
||||
#updateSubtitlePosition() {
|
||||
updateElementPosition(this.#el, {
|
||||
x: this.position.x,
|
||||
y: this.position.y - 100
|
||||
})
|
||||
}
|
||||
|
||||
#initNextVoiceTimer() {
|
||||
this.#voice.listener.next = setInterval(() => {
|
||||
if (!this.#voice.lastClickToNext) {
|
||||
this.#nextVoice()
|
||||
}
|
||||
}, this.#config.duration.next)
|
||||
}
|
||||
|
||||
#nextVoice() {
|
||||
const getVoiceId = () => {
|
||||
const id = this.#voice.list[Math.floor((Math.random() * this.#voice.list.length))]
|
||||
return id === this.#voice.id.last ? getVoiceId() : id
|
||||
}
|
||||
this.#playVoice(getVoiceId())
|
||||
}
|
||||
|
||||
#initIdleVoiceTimer() {
|
||||
this.#voice.listener.idle = setInterval(() => {
|
||||
this.#playSpecialVoice("闲置")
|
||||
clearInterval(this.#voice.listener.idle)
|
||||
this.#voice.listener.idle = -1
|
||||
}, this.#config.duration.idle)
|
||||
}
|
||||
|
||||
set useSubtitle(show) {
|
||||
@@ -143,11 +320,76 @@ export default class Voice {
|
||||
|
||||
set position(v) {
|
||||
if (typeof v !== "object") return;
|
||||
if (typeof v.x !== "undefined") this.#config.subtitle.x = v.x;
|
||||
if (typeof v.y !== "undefined") this.#config.subtitle.y = v.y;
|
||||
if (v.x) this.#config.subtitle.x = v.x;
|
||||
if (v.y) this.#config.subtitle.y = v.y;
|
||||
this.#updateSubtitlePosition()
|
||||
}
|
||||
|
||||
set language(lang) {
|
||||
if (this.#voice.languages.includes(lang)) {
|
||||
this.#config.language = lang
|
||||
} else {
|
||||
this.#config.language = this.#default.language.voice
|
||||
}
|
||||
const availableSubtitleLang = this.#getSubtitleLanguages()
|
||||
if (!availableSubtitleLang.includes(this.#config.subtitle.language)) {
|
||||
this.#config.subtitle.language = availableSubtitleLang[0]
|
||||
}
|
||||
}
|
||||
|
||||
get language() {
|
||||
return this.#config.language
|
||||
}
|
||||
|
||||
get languages() {
|
||||
return this.#voice.languages
|
||||
}
|
||||
|
||||
get duration() {
|
||||
return {
|
||||
idle: this.#config.duration.idle / 60 / 1000,
|
||||
next: this.#config.duration.next / 60 / 1000
|
||||
}
|
||||
}
|
||||
|
||||
set duration(v) {
|
||||
if (typeof v !== "object") return;
|
||||
if (v.idle) {
|
||||
clearInterval(this.#voice.listener.idle)
|
||||
if (v.idle !== 0) {
|
||||
this.#config.duration.idle = parseInt(v.idle) * 60 * 1000
|
||||
this.#initIdleVoiceTimer()
|
||||
}
|
||||
}
|
||||
if (v.next) {
|
||||
clearInterval(this.#voice.listener.next)
|
||||
if (v.next !== 0) {
|
||||
this.#config.duration.next = parseInt(v.next) * 60 * 1000
|
||||
this.#initNextVoiceTimer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get durationIdle() {
|
||||
return this.duration.idle
|
||||
}
|
||||
|
||||
set durationIdle(duration) {
|
||||
this.duration = {
|
||||
idle: duration
|
||||
}
|
||||
}
|
||||
|
||||
set durationNext(duration) {
|
||||
this.duration = {
|
||||
next: duration
|
||||
}
|
||||
}
|
||||
|
||||
get durationNext() {
|
||||
return this.duration.next
|
||||
}
|
||||
|
||||
set subtitleX(x) {
|
||||
// Note: Back Compatibility
|
||||
this.position = {
|
||||
@@ -172,61 +414,6 @@ export default class Voice {
|
||||
return this.position.y
|
||||
}
|
||||
|
||||
set language(lang) {
|
||||
if (this.#voice.languages.includes(lang)) {
|
||||
this.#config.voiceLang = lang
|
||||
} else {
|
||||
this.#config.voiceLang = this.#default.language.voice
|
||||
}
|
||||
const availableSubtitleLang = this.#getSubtitleLanguages()
|
||||
if (!availableSubtitleLang.includes(this.#config.subtitle.language)) {
|
||||
this.#config.subtitle.language = availableSubtitleLang[0]
|
||||
}
|
||||
}
|
||||
|
||||
get language() {
|
||||
return this.#config.voiceLang
|
||||
}
|
||||
|
||||
get languages() {
|
||||
return this.#voice.languages
|
||||
}
|
||||
|
||||
get duration() {
|
||||
return {
|
||||
idle: this.#config.duration.idle / 60 / 1000,
|
||||
next: this.#config.duration.next / 60 / 1000
|
||||
}
|
||||
}
|
||||
|
||||
set duration(v) {
|
||||
if (typeof v !== "object") return;
|
||||
if (typeof v.idle !== "undefined") {
|
||||
clearInterval(this.#voice.listener.idle)
|
||||
if (v.idle !== 0) {
|
||||
this.#config.duration.idle = parseInt(v.idle) * 60 * 1000
|
||||
this.#initIdleVoiceTimer()
|
||||
}
|
||||
}
|
||||
if (typeof v.next !== "undefined") {
|
||||
clearInterval(this.#voice.listener.next)
|
||||
if (v.next !== 0) {
|
||||
this.#config.duration.next = parseInt(v.next) * 60 * 1000
|
||||
this.#initNextVoiceTimer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get durationIdle() {
|
||||
return this.duration.idle
|
||||
}
|
||||
|
||||
set durationIdle(duration) {
|
||||
this.duration = {
|
||||
idle: duration
|
||||
}
|
||||
}
|
||||
|
||||
set idleDuration(duration) {
|
||||
// Note: Back Compatibility
|
||||
this.duration = {
|
||||
@@ -239,211 +426,26 @@ export default class Voice {
|
||||
return this.duration.idle
|
||||
}
|
||||
|
||||
set durationNext(duration) {
|
||||
this.duration = {
|
||||
next: duration
|
||||
}
|
||||
}
|
||||
|
||||
set nextDuration(duration) {
|
||||
// Note: Back Compatibility
|
||||
this.duration.next = duration
|
||||
}
|
||||
|
||||
get durationNext() {
|
||||
return this.duration.next
|
||||
}
|
||||
|
||||
get nextDuration() {
|
||||
// Note: Back Compatibility
|
||||
return this.duration.next
|
||||
}
|
||||
|
||||
init(el) {
|
||||
this.#parentEl = el
|
||||
this.#el.id = "voice-box"
|
||||
this.#el.hidden = true
|
||||
this.#el.innerHTML = `
|
||||
<audio id="${this.#audio.id}" autoplay>
|
||||
<source type="audio/ogg" />
|
||||
</audio>
|
||||
<div class="voice-wrapper" id="voice-wrapper">
|
||||
<div class="voice-title" id="voice-title"></div>
|
||||
<div class="voice-subtitle">
|
||||
<div id="voice-subtitle"></div>
|
||||
<div class="voice-triangle"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="voice-actor-box" hidden>
|
||||
<div class="voice-actor">
|
||||
<span class="voice-actor-icon"></span>
|
||||
<span id="voice-actor-name" class="voice-actor-name"></span>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
insertHTMLChild(this.#parentEl, this.#el)
|
||||
}
|
||||
|
||||
success() {
|
||||
const audioEndedFunc = () => {
|
||||
this.#audio.isPlaying = false
|
||||
this.#setCurrentSubtitle(null)
|
||||
this.#audio.lastClickToNext = false
|
||||
}
|
||||
this.#audio.el.addEventListener('ended', audioEndedFunc)
|
||||
this.#playEntryVoice()
|
||||
this.#initNextVoiceTimer()
|
||||
this.#playerObj.node.addEventListener('click', () => {
|
||||
this.#audio.lastClickToNext = true
|
||||
this.#nextVoice()
|
||||
})
|
||||
document.addEventListener('mousemove', () => {
|
||||
if (this.#voice.listener.idle === -1) {
|
||||
this.#initIdleVoiceTimer()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
link(playerObj) {
|
||||
this.#playerObj = playerObj
|
||||
}
|
||||
|
||||
#getVoiceLocations() {
|
||||
const folders = JSON.parse(import.meta.env.VITE_VOICE_FOLDERS)
|
||||
const customVoiceName = this.#voice.languages.filter(i => !folders.sub.map(e => e.lang).includes(i))[0]
|
||||
folders.sub = folders.sub.map(e => {
|
||||
return {
|
||||
name: e.name,
|
||||
lang: e.lang === "CUSTOM" ? customVoiceName : e.lang
|
||||
}
|
||||
})
|
||||
return folders
|
||||
}
|
||||
|
||||
#getVoices() {
|
||||
return charword_table.subtitleLangs[this.#config.subtitle.language].default
|
||||
}
|
||||
|
||||
#playEntryVoice() {
|
||||
this.#playSpecialVoice("问候")
|
||||
}
|
||||
|
||||
#playSpecialVoice(matcher) {
|
||||
const voices = this.#getVoices()
|
||||
const voiceId = Object.keys(voices).find(e => voices[e].title === matcher)
|
||||
this.#playVoice(voiceId)
|
||||
}
|
||||
|
||||
#playVoice(id) {
|
||||
if (!this.useVoice) return
|
||||
this.#voice.id.last = this.#voice.id.current
|
||||
this.#voice.id.current = id
|
||||
this.#audio.el.src = `./assets/${this.#getVoiceLocation()
|
||||
}/${id}.ogg`
|
||||
let startPlayPromise = this.#audio.el.play()
|
||||
if (startPlayPromise !== undefined) {
|
||||
startPlayPromise
|
||||
.then(() => {
|
||||
this.#audio.isPlaying = true
|
||||
this.#setCurrentSubtitle(id)
|
||||
})
|
||||
.catch(() => {
|
||||
return
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#getVoiceLocation() {
|
||||
const locations = this.#voice.locations
|
||||
return `${locations.main}/${locations.sub.find(e => e.lang === this.#config.voiceLang).name}`
|
||||
}
|
||||
|
||||
#setCurrentSubtitle(id) {
|
||||
if (id === null) {
|
||||
setTimeout(() => {
|
||||
if (this.#audio.isPlaying) return
|
||||
this.#toggleSubtitle(0)
|
||||
}, 5 * 1000);
|
||||
return
|
||||
}
|
||||
const subtitle = this.#getSubtitleById(id)
|
||||
const title = subtitle.title
|
||||
const content = subtitle.text
|
||||
const cvInfo = charword_table.voiceLangs[this.subtitleLanguage][this.#config.voiceLang]
|
||||
document.getElementById('voice-title').innerText = title
|
||||
document.getElementById('voice-subtitle').innerText = content
|
||||
document.getElementById('voice-actor-name').innerText = cvInfo.join('')
|
||||
if (this.#audio.isPlaying) {
|
||||
this.#toggleSubtitle(1)
|
||||
}
|
||||
}
|
||||
|
||||
#toggleSubtitle(v) {
|
||||
this.#el.style.opacity = v ? 1 : 0
|
||||
}
|
||||
|
||||
#getSubtitleById(id) {
|
||||
const obj = charword_table.subtitleLangs[this.#config.subtitle.language]
|
||||
let key = 'default'
|
||||
if (obj[this.#config.voiceLang]) {
|
||||
key = this.#config.voiceLang
|
||||
}
|
||||
return obj[key][id]
|
||||
}
|
||||
|
||||
#getSubtitleLanguages() {
|
||||
return Object.keys(charword_table.subtitleLangs)
|
||||
}
|
||||
|
||||
#updateSubtitlePosition() {
|
||||
updateElementPosition(this.#el, {
|
||||
x: this.position.x,
|
||||
y: this.position.y - 100
|
||||
})
|
||||
}
|
||||
|
||||
#initNextVoiceTimer() {
|
||||
this.#voice.listener.next = setInterval(() => {
|
||||
if (!this.#voice.lastClickToNext) {
|
||||
this.#nextVoice()
|
||||
}
|
||||
}, this.#config.duration.next)
|
||||
}
|
||||
|
||||
#nextVoice() {
|
||||
const getVoiceId = () => {
|
||||
const id = this.#voice.list[Math.floor((Math.random() * this.#voice.list.length))]
|
||||
return id === this.#voice.id.last ? getVoiceId() : id
|
||||
}
|
||||
this.#playVoice(getVoiceId())
|
||||
}
|
||||
|
||||
#initIdleVoiceTimer() {
|
||||
this.#voice.listener.idle = setInterval(() => {
|
||||
this.#playSpecialVoice("闲置")
|
||||
clearInterval(this.#voice.listener.idle)
|
||||
this.#voice.listener.idle = -1
|
||||
}, this.#config.duration.idle)
|
||||
}
|
||||
|
||||
resetPosition() {
|
||||
this.position = {...this.#default.subtitle}
|
||||
document.getElementById("subtitle-padding-x-slider").value = this.#default.subtitle.x
|
||||
document.getElementById("subtitle-padding-x-input").value = this.#default.subtitle.x
|
||||
document.getElementById("subtitle-padding-y-slider").value = this.#default.subtitle.y
|
||||
document.getElementById("subtitle-padding-y-input").value = this.#default.subtitle.y
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.resetPosition()
|
||||
get config() {
|
||||
return {...this.#config}
|
||||
}
|
||||
|
||||
get HTML() {
|
||||
return `
|
||||
<div>
|
||||
<label for="voice">Voice</label>
|
||||
<input type="checkbox" id="voice" name="voice"/>
|
||||
<div id="voice-realted" hidden>
|
||||
<input type="checkbox" id="voice" name="voice" ${this.useVoice ? "checked" : ""}/>
|
||||
<div id="voice-realted" ${this.useVoice ? "" : "hidden"}>
|
||||
<div>
|
||||
<label for="voice-lang-select">Choose the language of voice:</label>
|
||||
<select name="voice-lang" id="voice-lang-select">
|
||||
@@ -460,8 +462,8 @@ export default class Voice {
|
||||
</div>
|
||||
<div>
|
||||
<label for="subtitle">Subtitle</label>
|
||||
<input type="checkbox" id="subtitle" name="subtitle"/>
|
||||
<div id="subtitle-realted" hidden>
|
||||
<input type="checkbox" id="subtitle" name="subtitle" ${this.useSubtitle ? "checked" : ""}/>
|
||||
<div id="subtitle-realted" ${this.useSubtitle ? "" : "hidden"}>
|
||||
<div>
|
||||
<label for="subtitle-lang-select">Choose the language of subtitle:</label>
|
||||
<select name="subtitle-lang" id="subtitle-lang-select">
|
||||
@@ -480,7 +482,7 @@ export default class Voice {
|
||||
</div>
|
||||
<div>
|
||||
<label for="voice-actor">Voice Actor</label>
|
||||
<input type="checkbox" id="voice-actor" name="voice-actor"/>
|
||||
<input type="checkbox" id="voice-actor" name="voice-actor" ${this.useVoiceActor ? "checked" : ""}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,5 +2,6 @@ import '@/index.css'
|
||||
import '@/libs/wallpaper_engine'
|
||||
import AKLive2D from '@/components/aklive2d'
|
||||
|
||||
window.aklive2d = new AKLive2D(document.getElementById('app'))
|
||||
window.aklive2d.init()
|
||||
(() => {
|
||||
window.aklive2d = new AKLive2D(document.getElementById("app"))
|
||||
})()
|
||||
|
||||
Reference in New Issue
Block a user