Showcase refactor (#20)
* refactor: update voice.js * refactor: update fallback.js * refactor: update music.js * refactor: update player.js * refactor: misc changes * feat: added background.js * feat: added logo.js * chore: update * refactor: port all changes * fix: fix WE issues * fix: code cleanup
This commit is contained in:
@@ -42,6 +42,7 @@ localization:
|
|||||||
ui_video_title: <hr><h4>📝 Video</h4><hr>
|
ui_video_title: <hr><h4>📝 Video</h4><hr>
|
||||||
ui_custom_video: Custom Video
|
ui_custom_video: Custom Video
|
||||||
ui_video_volume: Volume
|
ui_video_volume: Volume
|
||||||
|
ui_misc_title: <hr><h4>💡 Misc</h4><hr>
|
||||||
zh-chs:
|
zh-chs:
|
||||||
ui_notice_title: <hr><h4>📝 通知</h4><hr>
|
ui_notice_title: <hr><h4>📝 通知</h4><hr>
|
||||||
ui_notice_set_fps: <span><b>在设置中设定FPS目标</b></span>
|
ui_notice_set_fps: <span><b>在设置中设定FPS目标</b></span>
|
||||||
@@ -84,6 +85,7 @@ localization:
|
|||||||
ui_video_title: <hr><h4>📹 视频</h4><hr>
|
ui_video_title: <hr><h4>📹 视频</h4><hr>
|
||||||
ui_custom_video: 自定义视频
|
ui_custom_video: 自定义视频
|
||||||
ui_video_volume: 音量
|
ui_video_volume: 音量
|
||||||
|
ui_misc_title: <hr><h4>💡 杂项</h4><hr>
|
||||||
properties:
|
properties:
|
||||||
- key: notice_title
|
- key: notice_title
|
||||||
value:
|
value:
|
||||||
@@ -282,7 +284,7 @@ properties:
|
|||||||
value: false
|
value: false
|
||||||
- key: custom_video
|
- key: custom_video
|
||||||
value:
|
value:
|
||||||
text: ui_video_music
|
text: ui_custom_video
|
||||||
condition: video_title.value == true
|
condition: video_title.value == true
|
||||||
type: file
|
type: file
|
||||||
fileType: video
|
fileType: video
|
||||||
@@ -296,20 +298,6 @@ properties:
|
|||||||
fraction: false
|
fraction: false
|
||||||
max: 100
|
max: 100
|
||||||
min: 0
|
min: 0
|
||||||
- key: useStartAnimation
|
|
||||||
value:
|
|
||||||
text: ui_useStartAnimation_title
|
|
||||||
type: bool
|
|
||||||
value: true
|
|
||||||
- key: scale
|
|
||||||
value:
|
|
||||||
text: ui_scale
|
|
||||||
type: slider
|
|
||||||
value: 1
|
|
||||||
fraction: true
|
|
||||||
max: 10
|
|
||||||
min: 0
|
|
||||||
step: 0.1
|
|
||||||
- key: position
|
- key: position
|
||||||
value:
|
value:
|
||||||
text: ui_position_title
|
text: ui_position_title
|
||||||
@@ -351,6 +339,23 @@ properties:
|
|||||||
fraction: false
|
fraction: false
|
||||||
max: 100
|
max: 100
|
||||||
min: -100
|
min: -100
|
||||||
|
- key: misc_title
|
||||||
|
value:
|
||||||
|
text: ui_misc_title
|
||||||
|
- key: useStartAnimation
|
||||||
|
value:
|
||||||
|
text: ui_useStartAnimation_title
|
||||||
|
type: bool
|
||||||
|
value: true
|
||||||
|
- key: scale
|
||||||
|
value:
|
||||||
|
text: ui_scale
|
||||||
|
type: slider
|
||||||
|
value: 1
|
||||||
|
fraction: true
|
||||||
|
max: 10
|
||||||
|
min: 0
|
||||||
|
step: 0.1
|
||||||
- key: privacytitle
|
- key: privacytitle
|
||||||
value:
|
value:
|
||||||
text: ui_privacy_title
|
text: ui_privacy_title
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
defer
|
defer
|
||||||
></script>
|
></script>
|
||||||
</head>
|
</head>
|
||||||
<body style="background-image: url('./assets/background/operator_bg.png');">
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<script type="module" src="/src/index.js"></script>
|
<script type="module" src="/src/index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#settings {
|
#settings-box {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
155
showcase/src/components/aklive2d.js
Normal file
155
showcase/src/components/aklive2d.js
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
import Voice from "@/components/voice";
|
||||||
|
import Fallback from "@/components/fallback";
|
||||||
|
import Music from "@/components/music";
|
||||||
|
import Player from "@/components/player";
|
||||||
|
import Background from "@/components/background";
|
||||||
|
import Logo from "@/components/logo";
|
||||||
|
import Insight from "@/components/insight";
|
||||||
|
import {
|
||||||
|
isWebGLSupported,
|
||||||
|
insertHTMLChild,
|
||||||
|
addEventListeners,
|
||||||
|
updateElementPosition,
|
||||||
|
} from "@/components/helper";
|
||||||
|
import '@/components/aklive2d.css'
|
||||||
|
|
||||||
|
export default class AKLive2D {
|
||||||
|
#el = document.createElement("div")
|
||||||
|
#appEl
|
||||||
|
#widgetEl
|
||||||
|
#queries = new URLSearchParams(window.location.search)
|
||||||
|
#voice = new Voice()
|
||||||
|
#music = new Music()
|
||||||
|
#player = new Player()
|
||||||
|
#background = new Background()
|
||||||
|
#logo = new Logo()
|
||||||
|
#insight = new Insight()
|
||||||
|
|
||||||
|
constructor(appEl, widgetEl) {
|
||||||
|
document.title = import.meta.env.VITE_TITLE
|
||||||
|
console.log("All resources are extracted from Arknights. Github: https://gura.ch/aklive2d-gh")
|
||||||
|
|
||||||
|
window.addEventListener("contextmenu", e => e.preventDefault());
|
||||||
|
document.addEventListener("gesturestart", e => e.preventDefault());
|
||||||
|
|
||||||
|
this.#appEl = appEl
|
||||||
|
this.#widgetEl = widgetEl
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
if (isWebGLSupported) {
|
||||||
|
this.#logo.init(this.#appEl);
|
||||||
|
this.#background.init(this.#appEl, this.#widgetEl);
|
||||||
|
this.#voice.init(this.#appEl, this.#widgetEl);
|
||||||
|
this.#music.init(this.#appEl);
|
||||||
|
this.#player.init(this.#widgetEl, this);
|
||||||
|
} else {
|
||||||
|
(new Fallback()).init(this.#widgetEl)
|
||||||
|
}
|
||||||
|
this.#el.id = "settings-box"
|
||||||
|
this.#el.hidden = true
|
||||||
|
this.#el.innerHTML = `
|
||||||
|
<div>
|
||||||
|
${this.#logo.HTML}
|
||||||
|
${this.#background.HTML}
|
||||||
|
${this.#player.HTML}
|
||||||
|
${this.#voice.HTML}
|
||||||
|
${this.#music.HTML}
|
||||||
|
<div>
|
||||||
|
<button type="button" id="settings-reset">Reset</button>
|
||||||
|
<button type="button" id="settings-close">Close</button>
|
||||||
|
<button type="button" id="settings-to-directory">Back to Directory</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
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,
|
||||||
|
{
|
||||||
|
id: "settings-reset", event: "click", handler: () => this.reset()
|
||||||
|
}, {
|
||||||
|
id: "settings-close", event: "click", handler: () => this.close()
|
||||||
|
}, {
|
||||||
|
id: "settings-to-directory", event: "click", handler: () => {
|
||||||
|
window.location.href = '/';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
open() {
|
||||||
|
this.#el.hidden = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.#el.hidden = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.#player.reset()
|
||||||
|
this.#background.reset()
|
||||||
|
this.#logo.reset()
|
||||||
|
this.#voice.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
success() {
|
||||||
|
this.#music.link(this.#background)
|
||||||
|
this.#background.link(this.#music)
|
||||||
|
this.#voice.success()
|
||||||
|
this.#music.success()
|
||||||
|
this.#insight.success()
|
||||||
|
if (this.#queries.has("settings") || this.#queries.has("aklive2d") || import.meta.env.MODE === 'development') {
|
||||||
|
this.open()
|
||||||
|
}
|
||||||
|
this.#backCompatibility()
|
||||||
|
}
|
||||||
|
|
||||||
|
#backCompatibility() {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
showcase/src/components/background.css
Normal file
23
showcase/src/components/background.css
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#background-box {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
z-index: -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#background-box #video-src {
|
||||||
|
min-width: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
235
showcase/src/components/background.js
Normal file
235
showcase/src/components/background.js
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
import {
|
||||||
|
insertHTMLNodeBefore,
|
||||||
|
readFile,
|
||||||
|
updateHTMLOptions,
|
||||||
|
showRelatedHTML,
|
||||||
|
syncHTMLValue,
|
||||||
|
} from "@/components/helper";
|
||||||
|
import "@/components/background.css"
|
||||||
|
|
||||||
|
export default class Background {
|
||||||
|
#el = document.createElement("div")
|
||||||
|
#parentEl
|
||||||
|
#videoEl
|
||||||
|
#default = {
|
||||||
|
location: `${import.meta.env.BASE_URL}assets/${import.meta.env.VITE_BACKGROUND_FOLDER}/`,
|
||||||
|
image: "operator_bg.png"
|
||||||
|
}
|
||||||
|
#config = {
|
||||||
|
image: null
|
||||||
|
}
|
||||||
|
#musicObj
|
||||||
|
|
||||||
|
init(el, widgetEl) {
|
||||||
|
this.#parentEl = el
|
||||||
|
this.#el.id = "background-box"
|
||||||
|
this.image = this.#default.location + this.#default.image
|
||||||
|
this.#el.innerHTML = `
|
||||||
|
<video autoplay loop disablepictureinpicture id="video-src" />
|
||||||
|
`
|
||||||
|
insertHTMLNodeBefore(this.#parentEl, widgetEl, this.#el)
|
||||||
|
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.image = this.#default.location + this.#default.image
|
||||||
|
}
|
||||||
|
|
||||||
|
resetVideo() {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
link(musicObj) {
|
||||||
|
this.#musicObj = musicObj
|
||||||
|
}
|
||||||
|
|
||||||
|
get HTML() {
|
||||||
|
return `
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<label for="default-background-select">Choose a default background:</label>
|
||||||
|
<select name="default-backgrounds" id="default-background-select">
|
||||||
|
${updateHTMLOptions(JSON.parse(import.meta.env.VITE_BACKGROUND_FILES))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="video">Video</label>
|
||||||
|
<input type="checkbox" id="video" name="video" />
|
||||||
|
<div id="video-realted" hidden>
|
||||||
|
<div>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="video-volume">Video Volume</label>
|
||||||
|
<input type="range" min="0" max="100" step="1" id="video-volume-slider" value="${this.volume}" />
|
||||||
|
<input type="number" id="video-volume-input" min="0" max="100" step="1" name="video-volume" value="${this.volume}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
get listeners() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
event: "background-set-default", handler: e => this.default = e.detail
|
||||||
|
}, {
|
||||||
|
event: "background-set-custom", handler: e => this.custom = e.detail
|
||||||
|
}, {
|
||||||
|
event: "background-set-video", handler: e => this.video = e.detail
|
||||||
|
}, {
|
||||||
|
event: "background-set-volume", handler: e => this.volume = e.detail
|
||||||
|
}, {
|
||||||
|
event: "background-reset-image", handler: () => this.resetImage()
|
||||||
|
}, {
|
||||||
|
event: "background-reset-video", handler: () => this.resetVideo()
|
||||||
|
}, {
|
||||||
|
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: "video", event: "click", handler: e => {
|
||||||
|
showRelatedHTML(e.currentTarget, "video-realted");
|
||||||
|
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: "video-volume-slider", event: "input", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "video-volume-input");
|
||||||
|
this.volume = e.currentTarget.value
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "video-volume-input", event: "change", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "video-volume-slider");
|
||||||
|
this.volume = e.currentTarget.value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
63
showcase/src/components/event.js
Normal file
63
showcase/src/components/event.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
export const PlayerReadyEvent = new Event("player-ready");
|
||||||
|
|
||||||
|
const createCustomEvent = (name) => (detail) => new CustomEvent(name, {detail})
|
||||||
|
|
||||||
|
export const InsightRegisterEventFn = createCustomEvent("insight-register")
|
||||||
|
|
||||||
|
export const PlayerSetFPSEventFn = createCustomEvent("player-set-fps")
|
||||||
|
|
||||||
|
export const PlayerSetScaleEventFn = createCustomEvent("player-set-scale")
|
||||||
|
|
||||||
|
export const PlayerSetPaddingEventFn = createCustomEvent("player-set-padding")
|
||||||
|
|
||||||
|
export const PlayerResetPaddingEvent = new Event("player-reset-padding")
|
||||||
|
|
||||||
|
export const PlayerSetUseStartAnimationEventFn = createCustomEvent("player-set-usestartanimation")
|
||||||
|
|
||||||
|
export const LogoSetHiddenEventFn = createCustomEvent("logo-set-hidden")
|
||||||
|
|
||||||
|
export const LogoSetRatioEventFn = createCustomEvent("logo-set-ratio")
|
||||||
|
|
||||||
|
export const LogoSetOpacityEventFn = createCustomEvent("logo-set-opacity")
|
||||||
|
|
||||||
|
export const LogoSetImageEventFn = createCustomEvent("logo-set-image")
|
||||||
|
|
||||||
|
export const LogoResetImageEvent = new Event("logo-reset-image")
|
||||||
|
|
||||||
|
export const LogoSetPositionEventFn = createCustomEvent("logo-set-position")
|
||||||
|
|
||||||
|
export const BackgroundSetDefaultEventFn = createCustomEvent("background-set-default")
|
||||||
|
|
||||||
|
export const BackgroundSetCustomEventFn = createCustomEvent("background-set-custom")
|
||||||
|
|
||||||
|
export const BackgroundSetVideoEventFn = createCustomEvent("background-set-video")
|
||||||
|
|
||||||
|
export const BackgroundSetVolumeEventFn = createCustomEvent("background-set-volume")
|
||||||
|
|
||||||
|
export const BackgroundResetImageEvent = new Event("background-reset-image")
|
||||||
|
|
||||||
|
export const BackgroundResetVideoEvent = new Event("background-reset-video")
|
||||||
|
|
||||||
|
export const VoiceSetUseVoiceEventFn = createCustomEvent("voice-set-usevoice")
|
||||||
|
|
||||||
|
export const VoiceSetLanguageEventFn = createCustomEvent("voice-set-language")
|
||||||
|
|
||||||
|
export const VoiceSetDurationEventFn = createCustomEvent("voice-set-duration")
|
||||||
|
|
||||||
|
export const VoiceSetUseSubtitleEventFn = createCustomEvent("voice-set-usesubtitle")
|
||||||
|
|
||||||
|
export const VoiceSetSubtitleLanguageEventFn = createCustomEvent("voice-set-subtitlelanguage")
|
||||||
|
|
||||||
|
export const VoiceSetSubtitlePositionEventFn = createCustomEvent("voice-set-subtitleposition")
|
||||||
|
|
||||||
|
export const VoiceSetUseVoiceActorEventFn = createCustomEvent("voice-set-usevoiceactor")
|
||||||
|
|
||||||
|
export const MusicSetMusicEventFn = createCustomEvent("music-set-music")
|
||||||
|
|
||||||
|
export const MusicSetUseMusicEventFn = createCustomEvent("music-set-usemusic")
|
||||||
|
|
||||||
|
export const MusicSetVolumeEventFn = createCustomEvent("music-set-volume")
|
||||||
|
|
||||||
|
export const MusicSetCustomEventFn = createCustomEvent("music-set-custom")
|
||||||
|
|
||||||
|
export const MusicResetEvent = new Event("music-reset")
|
||||||
@@ -1,16 +1,26 @@
|
|||||||
|
import { insertHTMLChild } from "@/components/helper";
|
||||||
import '@/components/fallback.css'
|
import '@/components/fallback.css'
|
||||||
|
|
||||||
export default function (el) {
|
export default class Fallback {
|
||||||
el.hidden = false;
|
#el = document.createElement("div")
|
||||||
alert('WebGL is unavailable. Fallback image will be used.');
|
|
||||||
const calculateScale = (width, height) => {
|
init(parentEl) {
|
||||||
return { x: window.innerWidth / width, y: window.innerHeight / height };
|
alert('WebGL is unavailable. Fallback image will be used.');
|
||||||
|
const calculateScale = (width, height) => {
|
||||||
|
return { x: window.innerWidth / width, y: window.innerHeight / height };
|
||||||
|
}
|
||||||
|
const fallback = () => {
|
||||||
|
const scale = calculateScale(import.meta.env.VITE_IMAGE_WIDTH, import.meta.env.VITE_IMAGE_HEIGHT);
|
||||||
|
this.#el.style.width = import.meta.env.VITE_IMAGE_WIDTH * (scale.x > scale.y ? scale.y : scale.x) + "px";
|
||||||
|
this.#el.style.height = import.meta.env.VITE_IMAGE_HEIGHT * (scale.x > scale.y ? scale.y : scale.x) + "px";
|
||||||
|
}
|
||||||
|
fallback();
|
||||||
|
window.addEventListener('resize', fallback, true);
|
||||||
|
this.#el.innerHTML = `
|
||||||
|
<div id="fallback"
|
||||||
|
style="background-image: url(./assets/${import.meta.env.VITE_FALLBACK_FILENAME}.png)"
|
||||||
|
/>
|
||||||
|
`
|
||||||
|
insertHTMLChild(parentEl, this.#el)
|
||||||
}
|
}
|
||||||
const fallback = () => {
|
|
||||||
const scale = calculateScale(import.meta.env.VITE_IMAGE_WIDTH, import.meta.env.VITE_IMAGE_HEIGHT);
|
|
||||||
el.style.width = import.meta.env.VITE_IMAGE_WIDTH * (scale.x > scale.y ? scale.y : scale.x) + "px";
|
|
||||||
el.style.height = import.meta.env.VITE_IMAGE_HEIGHT * (scale.x > scale.y ? scale.y : scale.x) + "px";
|
|
||||||
}
|
|
||||||
fallback();
|
|
||||||
window.addEventListener('resize', fallback, true);
|
|
||||||
}
|
}
|
||||||
78
showcase/src/components/helper.js
Normal file
78
showcase/src/components/helper.js
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
export const isWebGLSupported = () => {
|
||||||
|
try {
|
||||||
|
const canvas = document.createElement("canvas");
|
||||||
|
const ctx = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
|
||||||
|
return ctx != null;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const insertHTMLChild = (parent, child) => {
|
||||||
|
parent.appendChild(child)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const insertHTMLNodeBefore = (parent, sibling, child) => {
|
||||||
|
parent.insertBefore(child, sibling)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getIntPx = (value) => parseInt(value.replace("px", ""))
|
||||||
|
export const updateElementPosition = (el, position) => {
|
||||||
|
const computedStyle = getComputedStyle(el)
|
||||||
|
const elWidth = getIntPx(computedStyle.width)
|
||||||
|
const elHeight = getIntPx(computedStyle.height)
|
||||||
|
const elMarginLeft = getIntPx(computedStyle.marginLeft)
|
||||||
|
const elMarginRight = getIntPx(computedStyle.marginRight)
|
||||||
|
const windowWidth = window.innerWidth
|
||||||
|
const windowHeight = window.innerHeight
|
||||||
|
const xRange = windowWidth - (elWidth + elMarginLeft + elMarginRight)
|
||||||
|
const yRange = windowHeight - elHeight
|
||||||
|
const xpx = position.x * xRange / 100
|
||||||
|
const ypx = position.y * yRange / 100
|
||||||
|
el.style.transform = `translate(${xpx}px, ${ypx}px)`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateHTMLOptions = (array, id = null) => {
|
||||||
|
const value = array.map(item => `<option value="${item}">${item}</option>`)
|
||||||
|
if (id) {
|
||||||
|
document.getElementById(id).innerHTML = value.join("");
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
export const addEventListeners = (listeners) => {
|
||||||
|
listeners.forEach(listener => {
|
||||||
|
if (typeof listener.id === "undefined") {
|
||||||
|
document.addEventListener(listener.event, e => listener.handler(e))
|
||||||
|
} else {
|
||||||
|
document.getElementById(listener.id).addEventListener(listener.event, e => listener.handler(e))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const showRelatedHTML = (e, relatedSettingsID, revert = false) => {
|
||||||
|
const eRelatedSettings = document.getElementById(relatedSettingsID)
|
||||||
|
const checked = revert ? !e.checked : e.checked;
|
||||||
|
if (checked) {
|
||||||
|
eRelatedSettings.hidden = false;
|
||||||
|
} else {
|
||||||
|
eRelatedSettings.hidden = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getCurrentHTMLOptions = (id, value) => {
|
||||||
|
const e = document.getElementById(id);
|
||||||
|
const options = [...e]
|
||||||
|
const toSelecteIndex = options.findIndex(i => options.find(o => o.value === value) === i)
|
||||||
|
e.selectedIndex = toSelecteIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const syncHTMLValue = (source, targetID) => {
|
||||||
|
if (typeof source === "string") source = document.getElementById(source);
|
||||||
|
document.getElementById(targetID).value = source.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const readFile = (file, callback = () => { }) => {
|
||||||
|
if (!file) return
|
||||||
|
callback(URL.createObjectURL(file.slice()), file.type)
|
||||||
|
}
|
||||||
33
showcase/src/components/insight.js
Normal file
33
showcase/src/components/insight.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
export default class Insight {
|
||||||
|
#isInsightInited = false
|
||||||
|
|
||||||
|
success() {
|
||||||
|
this.insight(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
insight(doNotTrack, isFromWallpaperEngine = false) {
|
||||||
|
if (this.#isInsightInited || import.meta.env.MODE === 'development') return
|
||||||
|
this.#isInsightInited = true
|
||||||
|
if (doNotTrack) return
|
||||||
|
try {
|
||||||
|
const config = {
|
||||||
|
path: `/${import.meta.env.VITE_LINK}`
|
||||||
|
}
|
||||||
|
if (isFromWallpaperEngine) config.hostname = "file://wallpaperengine.local";
|
||||||
|
window.counterscale = {
|
||||||
|
q: [["set", "siteId", import.meta.env.VITE_INSIGHT_ID], ["trackPageview", config]],
|
||||||
|
};
|
||||||
|
window.counterscaleOnDemandTrack();
|
||||||
|
} catch (e) {
|
||||||
|
console.warn && console.warn(e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get listeners() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
event: "insight-register", handler: e => this.insight(e.detail, true)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
6
showcase/src/components/logo.css
Normal file
6
showcase/src/components/logo.css
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#logo-box {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
351
showcase/src/components/logo.js
Normal file
351
showcase/src/components/logo.js
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
import {
|
||||||
|
insertHTMLChild,
|
||||||
|
updateElementPosition,
|
||||||
|
readFile,
|
||||||
|
showRelatedHTML,
|
||||||
|
syncHTMLValue,
|
||||||
|
} from "@/components/helper";
|
||||||
|
import "@/components/logo.css"
|
||||||
|
|
||||||
|
export default class Logo {
|
||||||
|
#el = document.createElement("div")
|
||||||
|
#imageEl
|
||||||
|
#parentEl
|
||||||
|
#default = {
|
||||||
|
location: `${import.meta.env.BASE_URL}assets/`,
|
||||||
|
image: `${import.meta.env.VITE_LOGO_FILENAME}.png`,
|
||||||
|
useInvertFilter: import.meta.env.VITE_INVERT_FILTER === "true",
|
||||||
|
ratio: 61.8,
|
||||||
|
opacity: 30,
|
||||||
|
hidden: false,
|
||||||
|
position: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#config = {
|
||||||
|
hidden: this.#default.hidden,
|
||||||
|
ratio: this.#default.ratio,
|
||||||
|
opacity: this.#default.opacity,
|
||||||
|
position: {...this.#default.position}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(el) {
|
||||||
|
this.#parentEl = el
|
||||||
|
this.#el.id = "logo-box"
|
||||||
|
this.#el.innerHTML = `
|
||||||
|
<img src="${this.#default.location + this.#default.image}" id="logo" alt="operator logo" />
|
||||||
|
`
|
||||||
|
insertHTMLChild(this.#parentEl, this.#el)
|
||||||
|
this.#imageEl = document.getElementById("logo")
|
||||||
|
this.#setInvertFilter(this.#default.useInvertFilter)
|
||||||
|
this.opacity = this.#default.opacity
|
||||||
|
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
|
||||||
|
}
|
||||||
|
if (typeof v === "object") {
|
||||||
|
readFile(
|
||||||
|
v,
|
||||||
|
(blobURL) => update(blobURL)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
update(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#resize(_this, value) {
|
||||||
|
_this = _this || this
|
||||||
|
_this.#imageEl.width = window.innerWidth / 2 * (value || _this.ratio) / 100
|
||||||
|
updateElementPosition(_this.#imageEl, _this.#config.position)
|
||||||
|
}
|
||||||
|
|
||||||
|
#setInvertFilter(v) {
|
||||||
|
if (!v) {
|
||||||
|
this.#imageEl.style.filter = "invert(0)"
|
||||||
|
} else {
|
||||||
|
this.#imageEl.style.filter = "invert(1)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get hidden() {
|
||||||
|
return this.#config.hidden
|
||||||
|
}
|
||||||
|
|
||||||
|
set hidden(v) {
|
||||||
|
this.#config.hidden = v
|
||||||
|
this.#imageEl.hidden = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
get ratio() {
|
||||||
|
return this.#config.ratio
|
||||||
|
}
|
||||||
|
|
||||||
|
set ratio(v) {
|
||||||
|
this.#config.ratio = v
|
||||||
|
this.#resize(this, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
get opacity() {
|
||||||
|
return this.#config.opacity
|
||||||
|
}
|
||||||
|
|
||||||
|
set opacity(v) {
|
||||||
|
this.#imageEl.style.opacity = v / 100
|
||||||
|
this.#config.opacity = v
|
||||||
|
}
|
||||||
|
|
||||||
|
get x() {
|
||||||
|
return this.position.x
|
||||||
|
}
|
||||||
|
|
||||||
|
set x(v) {
|
||||||
|
this.position = {
|
||||||
|
x: v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get y() {
|
||||||
|
return this.position.y
|
||||||
|
}
|
||||||
|
|
||||||
|
set y(v) {
|
||||||
|
this.position = {
|
||||||
|
y: v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get position() {
|
||||||
|
return this.#config.position
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
this.#updateLogoPosition()
|
||||||
|
}
|
||||||
|
|
||||||
|
#updateLogoPosition() {
|
||||||
|
updateElementPosition(this.#imageEl, this.#config.position)
|
||||||
|
}
|
||||||
|
|
||||||
|
logoPadding(key, value) {
|
||||||
|
// Note: Back Compatibility
|
||||||
|
switch (key) {
|
||||||
|
case "x":
|
||||||
|
this.position = {
|
||||||
|
x: value
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "y":
|
||||||
|
this.position = {
|
||||||
|
y: value
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.position = value
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setLogoOpacity(v) {
|
||||||
|
// Note: Back Compatibility
|
||||||
|
this.opacity = v
|
||||||
|
}
|
||||||
|
|
||||||
|
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">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="logo-ratio">Logo Ratio</label>
|
||||||
|
<input type="range" min="0" max="100" step="0.1" id="logo-ratio-slider" value="${this.ratio}" />
|
||||||
|
<input type="number" id="logo-ratio-input" name="logo-ratio" value="${this.ratio}" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="logo-opacity">Logo Opacity</label>
|
||||||
|
<input type="range" min="0" max="100" data-css-class="logo" step="1" id="logo-opacity-slider" value="${this.opacity}" />
|
||||||
|
<input type="number" id="logo-opacity-input" name="logo-opacity" value="${this.opacity}" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="logo-position-x">Logo X Position</label>
|
||||||
|
<input type="range" min="0" max="100" id="logo-position-x-slider" value="${this.position.x}" />
|
||||||
|
<input type="number" id="logo-position-x-input" name="logo-position-x" value="${this.position.x}" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="logo-position-y">Logo Y Position</label>
|
||||||
|
<input type="range" min="0" max="100" id="logo-position-y-slider" value="${this.position.y}" />
|
||||||
|
<input type="number" id="logo-position-y-input" name="logo-position-y" value="${this.position.y}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
get listeners() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
event: "logo-set-hidden", handler: e => this.hidden = e.detail
|
||||||
|
}, {
|
||||||
|
event: "logo-set-ratio", handler: e => this.ratio = e.detail
|
||||||
|
}, {
|
||||||
|
event: "logo-set-opacity", handler: e => this.opacity = e.detail
|
||||||
|
}, {
|
||||||
|
event: "logo-set-image", handler: e => this.image = e.detail
|
||||||
|
}, {
|
||||||
|
event: "logo-reset-image", handler: () => this.resetImage()
|
||||||
|
}, {
|
||||||
|
event: "logo-set-position", handler: e => this.position = e.detail
|
||||||
|
}, {
|
||||||
|
id: "operator-logo", event: "click", handler: e => {
|
||||||
|
showRelatedHTML(e.currentTarget, "operator-logo-realted");
|
||||||
|
this.hidden = !e.currentTarget.checked;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "logo-image", event: "change", handler: e => this.image = e.target.files[0]
|
||||||
|
}, {
|
||||||
|
id: "logo-image-clear", event: "click", handler: () => this.resetImage()
|
||||||
|
}, {
|
||||||
|
id: "logo-ratio-slider", event: "input", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "logo-ratio-input");
|
||||||
|
this.ratio = e.currentTarget.value;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "logo-ratio-input", event: "change", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "logo-ratio-slider");
|
||||||
|
this.ratio = e.currentTarget.value;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "logo-opacity-slider", event: "input", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "logo-opacity-input");
|
||||||
|
this.opacity = e.currentTarget.value;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "logo-opacity-input", event: "change", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "logo-opacity-slider");
|
||||||
|
this.opacity = e.currentTarget.value;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "logo-position-x-slider", event: "input", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "logo-position-x-input");
|
||||||
|
this.position = {
|
||||||
|
x: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "logo-position-x-input", event: "change", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "logo-position-x-slider");
|
||||||
|
this.position = {
|
||||||
|
x: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "logo-position-y-slider", event: "input", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "logo-position-y-input");
|
||||||
|
this.position = {
|
||||||
|
y: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "logo-position-y-input", event: "change", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "logo-position-y-slider");
|
||||||
|
this.position = {
|
||||||
|
y: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,74 +1,68 @@
|
|||||||
export default class Music {
|
import {
|
||||||
#el
|
insertHTMLChild,
|
||||||
#mapping = JSON.parse(import.meta.env.VITE_MUSIC_MAPPING)
|
updateHTMLOptions,
|
||||||
#folder = import.meta.env.VITE_MUSIC_FOLDER
|
showRelatedHTML,
|
||||||
#currentMusic = null
|
syncHTMLValue,
|
||||||
#audioIntroEl
|
readFile,
|
||||||
#audioLoopEl
|
getCurrentHTMLOptions
|
||||||
#audioIntroElId = 'music-intro'
|
} from "@/components/helper";
|
||||||
#audioLoopElId = 'music-loop'
|
|
||||||
#useMusic = false
|
|
||||||
#timeOffset = 0.3
|
|
||||||
#volume = 0.5
|
|
||||||
#isUsingCustomMusic = false
|
|
||||||
|
|
||||||
constructor(el) {
|
export default class Music {
|
||||||
this.#el = el
|
#el = document.createElement("div")
|
||||||
this.#insertHTML()
|
#parentEl
|
||||||
this.#audioIntroEl = document.getElementById(this.#audioIntroElId)
|
#audio = {
|
||||||
this.#audioLoopEl = document.getElementById(this.#audioLoopElId)
|
intro: {
|
||||||
this.#audioIntroEl.volume = this.#volume
|
id: "music-intro",
|
||||||
this.#audioLoopEl.volume = this.#volume
|
el: null
|
||||||
this.#audioIntroEl.ontimeupdate = () => {
|
},
|
||||||
if (this.#audioIntroEl.currentTime >= this.#audioIntroEl.duration - this.#timeOffset) {
|
loop: {
|
||||||
this.#audioIntroEl.pause()
|
id: "music-loop",
|
||||||
this.#audioLoopEl.play()
|
el: null
|
||||||
}
|
|
||||||
}
|
|
||||||
this.#audioLoopEl.ontimeupdate = () => {
|
|
||||||
if (this.#audioLoopEl.currentTime >= this.#audioLoopEl.duration - this.#timeOffset) {
|
|
||||||
this.#audioLoopEl.currentTime = 0
|
|
||||||
this.#audioLoopEl.play()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#music = {
|
||||||
|
mapping: JSON.parse(import.meta.env.VITE_MUSIC_MAPPING),
|
||||||
|
location: import.meta.env.VITE_MUSIC_FOLDER,
|
||||||
|
current: null,
|
||||||
|
isUsingCustom: false,
|
||||||
|
list: []
|
||||||
|
}
|
||||||
|
#config = {
|
||||||
|
useMusic: false,
|
||||||
|
timeOffset: 0.3,
|
||||||
|
volume: 0.5
|
||||||
|
}
|
||||||
|
#backgroundObj
|
||||||
|
|
||||||
get timeOffset() {
|
get timeOffset() {
|
||||||
return this.#timeOffset
|
return this.#config.timeOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
set timeOffset(value) {
|
set timeOffset(value) {
|
||||||
this.#timeOffset = value
|
this.#config.timeOffset = value
|
||||||
}
|
}
|
||||||
|
|
||||||
get volume() {
|
get volume() {
|
||||||
return this.#volume * 100
|
return this.#config.volume * 100
|
||||||
}
|
}
|
||||||
|
|
||||||
set volume(value) {
|
set volume(value) {
|
||||||
value = value / 100
|
value = value / 100
|
||||||
this.#volume = value
|
this.#config.volume = value
|
||||||
this.#audioIntroEl.volume = value
|
this.#audio.intro.el.volume = value
|
||||||
this.#audioLoopEl.volume = value
|
this.#audio.loop.el.volume = value
|
||||||
}
|
}
|
||||||
|
|
||||||
get music() {
|
get musics() {
|
||||||
return Object.keys(this.#mapping)
|
return this.#music.list
|
||||||
}
|
}
|
||||||
|
|
||||||
get useMusic() {
|
get useMusic() {
|
||||||
return this.#useMusic
|
return this.#config.useMusic
|
||||||
}
|
}
|
||||||
|
|
||||||
get currentMusic() {
|
|
||||||
return this.#currentMusic
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {bool} value
|
|
||||||
*/
|
|
||||||
set useMusic(value) {
|
set useMusic(value) {
|
||||||
this.#useMusic = value
|
this.#config.useMusic = value
|
||||||
if (value) {
|
if (value) {
|
||||||
this.#playMusic()
|
this.#playMusic()
|
||||||
} else {
|
} else {
|
||||||
@@ -76,67 +70,227 @@ export default class Music {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
success() {
|
get currentMusic() {
|
||||||
if (this.#currentMusic === null) this.changeMusic(window.settings.currentBackground)
|
// Note: Back Compatibility
|
||||||
|
return this.music
|
||||||
}
|
}
|
||||||
|
|
||||||
changeMusic(name) {
|
get music() {
|
||||||
if (name !== null && name !== this.#currentMusic && !this.#isUsingCustomMusic) {
|
return this.#music.current
|
||||||
this.#currentMusic = name
|
}
|
||||||
if (this.#useMusic) {
|
|
||||||
this.#audioLoopEl.pause()
|
get isUsingCustom() {
|
||||||
this.#audioIntroEl.pause()
|
return this.#music.isUsingCustom
|
||||||
this.#playMusic()
|
}
|
||||||
|
|
||||||
|
init(el) {
|
||||||
|
this.#parentEl = el
|
||||||
|
this.#el.id = "music-box"
|
||||||
|
this.#el.innerHTML = `
|
||||||
|
<audio id="${this.#audio.intro.id}" preload="auto">
|
||||||
|
<source type="audio/ogg" />
|
||||||
|
</audio>
|
||||||
|
<audio id="${this.#audio.loop.id}" preload="auto">
|
||||||
|
<source type="audio/ogg" />
|
||||||
|
</audio>
|
||||||
|
`
|
||||||
|
insertHTMLChild(this.#parentEl, this.#el)
|
||||||
|
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.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.ontimeupdate = () => {
|
||||||
|
if (this.#audio.loop.el.currentTime >= this.#audio.loop.el.duration - this.#config.timeOffset) {
|
||||||
|
this.#audio.loop.el.currentTime = 0
|
||||||
|
this.#audio.loop.el.play()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setMusic(data, type) {
|
success() {
|
||||||
this.#audioLoopEl.src = data
|
if (this.#music.current === null) this.music = this.#backgroundObj.current
|
||||||
this.#audioLoopEl.querySelector('source').type = type
|
|
||||||
this.#isUsingCustomMusic = true
|
|
||||||
this.#playMusic()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resetMusic() {
|
link(backgroundObj) {
|
||||||
this.#isUsingCustomMusic = false
|
this.#backgroundObj = backgroundObj
|
||||||
if (this.#useMusic) {
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
if (this.#config.useMusic) {
|
||||||
this.#playMusic()
|
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
|
||||||
|
this.#music.isUsingCustom = true
|
||||||
|
this.#playMusic()
|
||||||
|
}
|
||||||
|
|
||||||
#playMusic() {
|
#playMusic() {
|
||||||
if (!this.#isUsingCustomMusic) {
|
if (!this.#music.isUsingCustom) {
|
||||||
const introOgg = this.#mapping[this.#currentMusic].intro
|
const introOgg = this.#music.mapping[this.#music.current].intro
|
||||||
const intro = `./assets/${this.#folder}/${introOgg}`
|
const intro = `./assets/${this.#music.location}/${introOgg}`
|
||||||
const loop = `./assets/${this.#folder}/${this.#mapping[this.#currentMusic].loop}`
|
const loop = `./assets/${this.#music.location}/${this.#music.mapping[this.#music.current].loop}`
|
||||||
this.#audioLoopEl.src = loop
|
this.#audio.loop.el.src = loop
|
||||||
this.#audioLoopEl.querySelector('source').type = 'audio/ogg'
|
this.#audio.loop.el.querySelector('source').type = 'audio/ogg'
|
||||||
if (introOgg) {
|
if (introOgg) {
|
||||||
this.#audioIntroEl.src = intro || loop
|
this.#audio.intro.el.src = intro || loop
|
||||||
this.#audioIntroEl.querySelector('source').type = 'audio/ogg'
|
this.#audio.intro.el.querySelector('source').type = 'audio/ogg'
|
||||||
|
this.#audio.intro.el.play()
|
||||||
|
this.#audio.loop.el.volume = 0
|
||||||
|
this.#audio.loop.el.play()
|
||||||
} else {
|
} else {
|
||||||
this.#audioLoopEl.play()
|
this.#audio.loop.el.volume = this.#config.volume
|
||||||
|
this.#audio.loop.el.play()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.#audioIntroEl.pause()
|
this.#audio.intro.el.pause()
|
||||||
this.#audioLoopEl.play()
|
this.#audio.loop.el.volume = this.#config.volume
|
||||||
|
this.#audio.loop.el.play()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#stopMusic() {
|
#stopMusic() {
|
||||||
this.#audioIntroEl.pause()
|
this.#audio.intro.el.pause()
|
||||||
this.#audioLoopEl.pause()
|
this.#audio.loop.el.pause()
|
||||||
}
|
}
|
||||||
|
|
||||||
#insertHTML() {
|
get HTML() {
|
||||||
this.#el.innerHTML = `
|
return `
|
||||||
<audio id="${this.#audioIntroElId}" preload="auto" autoplay>
|
<div>
|
||||||
<source type="audio/ogg" />
|
<label for="music">Music</label>
|
||||||
</audio>
|
<input type="checkbox" id="music" name="music" />
|
||||||
<audio id="${this.#audioLoopElId}" preload="auto">
|
<div id="music-realted" hidden>
|
||||||
<source type="audio/ogg" />
|
<div>
|
||||||
</audio>
|
<label for="music-select">Choose theme music:</label>
|
||||||
|
<select name="music-select" id="music-select">
|
||||||
|
${updateHTMLOptions(this.musics)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="music-volume">Music Volume</label>
|
||||||
|
<input type="range" min="0" max="100" step="1" id="music-volume-slider" value="${this.volume}" />
|
||||||
|
<input type="number" id="music-volume-input" min="0" max="100" step="1" name="music-volume" value="${this.volume}" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="music-switch-offset">Music Swtich Offset</label>
|
||||||
|
<input type="range" min="0" max="1" step="0.01" id="music-switch-offset-slider" value="${this.timeOffset}" />
|
||||||
|
<input type="number" id="music-switch-offset-input" min="0" max="1" step="0.01" name="music-switch-offset" value="${this.timeOffset}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get listeners() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
event: "music-set-music", handler: e => this.music = e.detail
|
||||||
|
}, {
|
||||||
|
event: "music-set-usemusic", handler: e => this.useMusic = e.detail
|
||||||
|
}, {
|
||||||
|
event: "music-set-volume", handler: e => this.volume = e.detail
|
||||||
|
}, {
|
||||||
|
event: "music-set-custom", handler: e => this.custom = e.detail
|
||||||
|
}, {
|
||||||
|
event: "music-reset", handler: () => this.reset()
|
||||||
|
}, {
|
||||||
|
id: "music", event: "click", handler: e => {
|
||||||
|
showRelatedHTML(e.currentTarget, "music-realted");
|
||||||
|
this.useMusic = e.currentTarget.checked;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "music-select", event: "change", handler: e => this.music = e.currentTarget.value
|
||||||
|
}, {
|
||||||
|
id: "custom-music", event: "change", handler: e => this.custom = e.target.files[0]
|
||||||
|
}, {
|
||||||
|
id: "custom-music-clear", event: "click", handler: () => this.reset()
|
||||||
|
}, {
|
||||||
|
id: "music-volume-slider", event: "input", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "music-volume-input");
|
||||||
|
this.volume = parseInt(e.currentTarget.value)
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "music-volume-input", event: "change", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "music-volume-slider");
|
||||||
|
this.volume = parseInt(e.currentTarget.value)
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "music-switch-offset-slider", event: "input", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "music-switch-offset-input");
|
||||||
|
this.timeOffset = parseFloat(e.currentTarget.value)
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "music-switch-offset-input", event: "change", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "music-switch-offset-slider");
|
||||||
|
this.timeOffset = parseFloat(e.currentTarget.value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#player {
|
#player-box {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
@@ -1,71 +1,458 @@
|
|||||||
|
import {
|
||||||
|
insertHTMLChild,
|
||||||
|
updateHTMLOptions,
|
||||||
|
showRelatedHTML,
|
||||||
|
syncHTMLValue
|
||||||
|
} from "@/components/helper";
|
||||||
|
import {
|
||||||
|
PlayerReadyEvent
|
||||||
|
} from "@/components/event"
|
||||||
import '@/libs/spine-player.css'
|
import '@/libs/spine-player.css'
|
||||||
import spine from '@/libs/spine-player'
|
import spine from '@/libs/spine-player'
|
||||||
import assets from '!/assets.json'
|
import assets from '!/assets.json'
|
||||||
import '@/components/player.css'
|
import '@/components/player.css'
|
||||||
|
|
||||||
const showControls = (new URLSearchParams(window.location.search)).has("controls")
|
export default class Player {
|
||||||
let resetTime = window.performance.now();
|
#el = document.createElement("div")
|
||||||
let isPlayingInteract = false;
|
#parentEl
|
||||||
|
#showControls = (new URLSearchParams(window.location.search)).has("controls")
|
||||||
export default function spinePlayer(el) {
|
#resetTime = window.performance.now()
|
||||||
el.hidden = false
|
#isPlayingInteract = false
|
||||||
const playerConfig = {
|
#spine
|
||||||
atlasUrl: `./assets/${import.meta.env.VITE_FILENAME}.atlas`,
|
#default = {
|
||||||
rawDataURIs: assets,
|
|
||||||
premultipliedAlpha: true,
|
|
||||||
alpha: true,
|
|
||||||
backgroundColor: "#00000000",
|
|
||||||
viewport: {
|
|
||||||
debugRender: false,
|
|
||||||
padLeft: `${import.meta.env.VITE_VIEWPORT_LEFT}%`,
|
|
||||||
padRight: `${import.meta.env.VITE_VIEWPORT_RIGHT}%`,
|
|
||||||
padTop: `${import.meta.env.VITE_VIEWPORT_TOP}%`,
|
|
||||||
padBottom: `${import.meta.env.VITE_VIEWPORT_BOTTOM}%`,
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
},
|
|
||||||
showControls: showControls,
|
|
||||||
touch: showControls,
|
|
||||||
fps: 60,
|
fps: 60,
|
||||||
defaultMix: 0,
|
padding: {
|
||||||
success: function (widget) {
|
left: parseInt(import.meta.env.VITE_VIEWPORT_LEFT),
|
||||||
if (widget.skeleton.data.animations.map(e => e.name).includes("Start") && window.settings.useStartAnimation) {
|
right: parseInt(import.meta.env.VITE_VIEWPORT_RIGHT),
|
||||||
widget.animationState.setAnimation(0, "Start", false)
|
top: parseInt(import.meta.env.VITE_VIEWPORT_TOP),
|
||||||
}
|
bottom: parseInt(import.meta.env.VITE_VIEWPORT_BOTTOM),
|
||||||
widget.animationState.addAnimation(0, "Idle", true, 0);
|
|
||||||
widget.animationState.addListener({
|
|
||||||
end: (e) => {
|
|
||||||
if (e.animation.name == "Interact") {
|
|
||||||
isPlayingInteract = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
complete: () => {
|
|
||||||
if (window.performance.now() - resetTime >= 8 * 1000 && Math.random() < 0.3) {
|
|
||||||
resetTime = window.performance.now();
|
|
||||||
let entry = widget.animationState.setAnimation(0, "Special", false);
|
|
||||||
entry.mixDuration = 0.3;
|
|
||||||
widget.animationState.addAnimation(0, "Idle", true, 0);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
widget.canvas.onclick = function () {
|
|
||||||
if (isPlayingInteract) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
isPlayingInteract = true;
|
|
||||||
let entry = widget.animationState.setAnimation(0, "Interact", false);
|
|
||||||
entry.mixDuration = 0.3;
|
|
||||||
widget.animationState.addAnimation(0, "Idle", true, 0);
|
|
||||||
}
|
|
||||||
window.voice.success()
|
|
||||||
window.settings.success()
|
|
||||||
window.music.success()
|
|
||||||
},
|
},
|
||||||
|
scale: 1,
|
||||||
}
|
}
|
||||||
if (import.meta.env.VITE_USE_JSON === "true") {
|
#config = {
|
||||||
playerConfig.jsonUrl = `./assets/${import.meta.env.VITE_FILENAME}.json`
|
fps: this.#default.fps,
|
||||||
} else {
|
useStartAnimation: true,
|
||||||
playerConfig.skelUrl = `./assets/${import.meta.env.VITE_FILENAME}.skel`
|
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) {
|
||||||
|
this.#parentEl = el
|
||||||
|
this.#el.id = "player-box"
|
||||||
|
insertHTMLChild(this.#parentEl, this.#el)
|
||||||
|
const _this = this
|
||||||
|
const playerConfig = {
|
||||||
|
atlasUrl: `./assets/${import.meta.env.VITE_FILENAME}.atlas`,
|
||||||
|
rawDataURIs: assets,
|
||||||
|
premultipliedAlpha: true,
|
||||||
|
alpha: true,
|
||||||
|
backgroundColor: "#00000000",
|
||||||
|
viewport: {
|
||||||
|
debugRender: false,
|
||||||
|
padLeft: `${import.meta.env.VITE_VIEWPORT_LEFT}%`,
|
||||||
|
padRight: `${import.meta.env.VITE_VIEWPORT_RIGHT}%`,
|
||||||
|
padTop: `${import.meta.env.VITE_VIEWPORT_TOP}%`,
|
||||||
|
padBottom: `${import.meta.env.VITE_VIEWPORT_BOTTOM}%`,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
showControls: _this.#showControls,
|
||||||
|
touch: _this.#showControls,
|
||||||
|
fps: 60,
|
||||||
|
defaultMix: 0,
|
||||||
|
success: function (widget) {
|
||||||
|
if (widget.skeleton.data.animations.map(e => e.name).includes("Start") && _this.useStartAnimation) {
|
||||||
|
widget.animationState.setAnimation(0, "Start", false)
|
||||||
|
}
|
||||||
|
widget.animationState.addAnimation(0, "Idle", true, 0);
|
||||||
|
widget.animationState.addListener({
|
||||||
|
end: (e) => {
|
||||||
|
if (e.animation.name == "Interact") {
|
||||||
|
_this.#isPlayingInteract = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
complete: () => {
|
||||||
|
if (window.performance.now() - _this.#resetTime >= 8 * 1000 && Math.random() < 0.3) {
|
||||||
|
_this.#resetTime = window.performance.now();
|
||||||
|
let entry = widget.animationState.setAnimation(0, "Special", false);
|
||||||
|
entry.mixDuration = 0.3;
|
||||||
|
widget.animationState.addAnimation(0, "Idle", true, 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
widget.canvas.onclick = function () {
|
||||||
|
if (_this.#isPlayingInteract) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_this.#isPlayingInteract = true;
|
||||||
|
let entry = widget.animationState.setAnimation(0, "Interact", false);
|
||||||
|
entry.mixDuration = 0.3;
|
||||||
|
widget.animationState.addAnimation(0, "Idle", true, 0);
|
||||||
|
}
|
||||||
|
_this.success()
|
||||||
|
document.dispatchEvent(PlayerReadyEvent);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if (import.meta.env.VITE_USE_JSON === "true") {
|
||||||
|
playerConfig.jsonUrl = `./assets/${import.meta.env.VITE_FILENAME}.json`
|
||||||
|
} else {
|
||||||
|
playerConfig.skelUrl = `./assets/${import.meta.env.VITE_FILENAME}.skel`
|
||||||
|
}
|
||||||
|
this.#spine = new spine.SpinePlayer(this.#el, playerConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
success() {
|
||||||
|
this.#loadViewport()
|
||||||
|
updateHTMLOptions(this.#spine.skeleton.data.animations.map(e => e.name), "animation-selection")
|
||||||
|
}
|
||||||
|
|
||||||
|
#loadViewport() {
|
||||||
|
this.#spine.updateViewport({
|
||||||
|
padLeft: `${this.#config.padding.left}%`,
|
||||||
|
padRight: `${this.#config.padding.right}%`,
|
||||||
|
padTop: `${this.#config.padding.top}%`,
|
||||||
|
padBottom: `${this.#config.padding.bottom}%`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
loadViewport() {
|
||||||
|
// Note: Back Compatibility
|
||||||
|
this.#loadViewport()
|
||||||
|
}
|
||||||
|
|
||||||
|
get padLeft() {
|
||||||
|
return this.padding.left
|
||||||
|
}
|
||||||
|
|
||||||
|
set padLeft(v) {
|
||||||
|
this.padding = {
|
||||||
|
left: v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get padRight() {
|
||||||
|
return this.padding.right
|
||||||
|
}
|
||||||
|
|
||||||
|
set padRight(v) {
|
||||||
|
this.padding = {
|
||||||
|
right: v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get padTop() {
|
||||||
|
return this.padding.top
|
||||||
|
}
|
||||||
|
|
||||||
|
set padTop(v) {
|
||||||
|
this.padding = {
|
||||||
|
top: v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get padBottom() {
|
||||||
|
return this.padding.bottom
|
||||||
|
}
|
||||||
|
|
||||||
|
set padBottom(v) {
|
||||||
|
this.padding = {
|
||||||
|
bottom: v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get padding() {
|
||||||
|
return this.#config.padding
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
this.#loadViewport()
|
||||||
|
}
|
||||||
|
|
||||||
|
positionPadding(key, value) {
|
||||||
|
// Note: Back Compatibility
|
||||||
|
switch (key) {
|
||||||
|
case "left":
|
||||||
|
this.padding = {
|
||||||
|
left: value
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "right":
|
||||||
|
this.padding = {
|
||||||
|
right: value
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "top":
|
||||||
|
this.padding = {
|
||||||
|
top: value
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "bottom":
|
||||||
|
this.padding = {
|
||||||
|
bottom: value
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.#config.padding = value
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 HTML() {
|
||||||
|
return `
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<label for="fps">FPS</label>
|
||||||
|
<input type="range" min="1" max="60" value="${this.fps}" step="1" id="fps-slider"/>
|
||||||
|
<input type="number" id="fps-input" min="1" max="60" name="fps" value="${this.fps}" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="animation-select">Animation:</label>
|
||||||
|
<select name="animation-select" id="animation-selection"></select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="use-start-animation">Use Start Animation</label>
|
||||||
|
<input type="checkbox" id="use-start-animation" name="use-start-animation" checked/>
|
||||||
|
</div>
|
||||||
|
<button type="button" id="player-play" disabled>Play</button>
|
||||||
|
<button type="button" id="player-pause">Pause</button>
|
||||||
|
<div>
|
||||||
|
<label for="scale">Scale</label>
|
||||||
|
<input type="range" min="0.1" max="10" step="0.1" id="scale-slider" value="${this.scale}" />
|
||||||
|
<input type="number" id="scale-input" name="scale" value="${this.scale}" step="0.1"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="position">Position</label>
|
||||||
|
<input type="checkbox" id="position" name="position" />
|
||||||
|
<div id="position-realted" 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}" />
|
||||||
|
<input type="number" id="position-padding-left-input" name="position-padding-left" value="${this.padding.left}" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="position-padding-right">Padding Right</label>
|
||||||
|
<input type="range" min="-100" max="100" id="position-padding-right-slider" value="${this.padding.right}" />
|
||||||
|
<input type="number" id="position-padding-right-input" name="position-padding-right" value="${this.padding.right}" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="position-padding-top">Padding Top</label>
|
||||||
|
<input type="range" min="-100" max="100" id="position-padding-top-slider" value="${this.padding.top}" />
|
||||||
|
<input type="number" id="position-padding-top-input" name="position-padding-top" value="${this.padding.top}" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="position-padding-bottom">Padding Bottom</label>
|
||||||
|
<input type="range" min="-100" max="100" id="position-padding-bottom-slider" value="${this.padding.bottom}" />
|
||||||
|
<input type="number" id="position-padding-bottom-input" name="position-padding-bottom" value="${this.padding.bottom}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
get listeners() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
event: "player-set-fps", handler: e => this.fps = e.detail
|
||||||
|
}, {
|
||||||
|
event: "player-set-scale", handler: e => this.scale = e.detail
|
||||||
|
}, {
|
||||||
|
event: "player-set-padding", handler: e => this.padding = e.detail
|
||||||
|
}, {
|
||||||
|
event: "player-reset-padding", handler: () => this.resetPadding()
|
||||||
|
}, {
|
||||||
|
event: "player-set-usestartanimation", handler: e => this.useStartAnimation = e.detail
|
||||||
|
}, {
|
||||||
|
id: "fps-slider", event: "change", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "fps-input");
|
||||||
|
this.fps = e.currentTarget.value;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "fps-slider", event: "input", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "fps-input");
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "fps-input", event: "change", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "fps-slider");
|
||||||
|
this.fps = e.currentTarget.value;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "animation-selection", event: "change", handler: e => {
|
||||||
|
this.spine.animationState.setAnimation(0, e.currentTarget.value, false, 0)
|
||||||
|
this.spine.animationState.addAnimation(0, "Idle", true, 0);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "use-start-animation", event: "click", handler: e => {
|
||||||
|
this.useStartAnimation = e.currentTarget.checked;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "player-play", event: "click", handler: e => {
|
||||||
|
this.spine.play();
|
||||||
|
e.currentTarget.disabled = true;
|
||||||
|
document.getElementById("player-pause").disabled = false;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "player-pause", event: "click", handler: e => {
|
||||||
|
this.spine.pause();
|
||||||
|
e.currentTarget.disabled = true;
|
||||||
|
document.getElementById("player-play").disabled = false;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "scale-slider", event: "input", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "scale-input");
|
||||||
|
this.scale = e.currentTarget.value;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "scale-input", event: "change", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "scale-slider");
|
||||||
|
this.scale = e.currentTarget.value;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "position", event: "click", handler: e => {
|
||||||
|
showRelatedHTML(e.currentTarget, "position-realted");
|
||||||
|
if (!e.currentTarget.checked) this.resetPadding();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "position-padding-left-slider", event: "input", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "position-padding-left-input");
|
||||||
|
this.padding = {
|
||||||
|
left: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "position-padding-left-input", event: "change", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "position-padding-left-slider");
|
||||||
|
this.padding = {
|
||||||
|
left: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "position-padding-right-slider", event: "input", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "position-padding-right-input");
|
||||||
|
this.padding = {
|
||||||
|
right: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "position-padding-right-input", event: "change", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "position-padding-right-slider");
|
||||||
|
this.padding = {
|
||||||
|
right: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "position-padding-top-slider", event: "input", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "position-padding-top-input");
|
||||||
|
this.padding = {
|
||||||
|
top: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "position-padding-top-input", event: "change", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "position-padding-top-slider");
|
||||||
|
this.padding = {
|
||||||
|
top: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "position-padding-bottom-slider", event: "input", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "position-padding-bottom-input");
|
||||||
|
this.padding = {
|
||||||
|
bottom: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "position-padding-bottom-input", event: "change", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "position-padding-bottom-slider");
|
||||||
|
this.padding = {
|
||||||
|
bottom: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
return new spine.SpinePlayer(el, playerConfig)
|
|
||||||
}
|
}
|
||||||
@@ -1,870 +0,0 @@
|
|||||||
import '@/components/settings.css'
|
|
||||||
|
|
||||||
const getPercentage = (value) => parseInt(value.replace("%", ""))
|
|
||||||
|
|
||||||
export default class Settings {
|
|
||||||
#el
|
|
||||||
#logoEl
|
|
||||||
#videoEl
|
|
||||||
#defaultLogoImage
|
|
||||||
#defaultFps = 60
|
|
||||||
#defaultRatio = 61.8
|
|
||||||
#defaultOpacity = 30
|
|
||||||
#defaulthideLogo = false
|
|
||||||
#defaultBackgroundImage = getComputedStyle(document.body).backgroundImage
|
|
||||||
#defaultInvertFilter = import.meta.env.VITE_INVERT_FILTER === "true"
|
|
||||||
#defaultPadLeft = getPercentage(`${import.meta.env.VITE_VIEWPORT_LEFT}%`)
|
|
||||||
#defaultPadRight = getPercentage(`${import.meta.env.VITE_VIEWPORT_RIGHT}%`)
|
|
||||||
#defaultPadTop = getPercentage(`${import.meta.env.VITE_VIEWPORT_TOP}%`)
|
|
||||||
#defaultPadBottom = getPercentage(`${import.meta.env.VITE_VIEWPORT_BOTTOM}%`)
|
|
||||||
#defaultScale = 1
|
|
||||||
#defaultLogoX = 0
|
|
||||||
#defaultLogoY = 0
|
|
||||||
#defaultViewport = {
|
|
||||||
debugRender: false,
|
|
||||||
padLeft: `${this.#defaultPadLeft}%`,
|
|
||||||
padRight: `${this.#defaultPadRight}%`,
|
|
||||||
padTop: `${this.#defaultPadTop}%`,
|
|
||||||
padBottom: `${this.#defaultPadBottom}%`,
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
}
|
|
||||||
#fps = this.#defaultFps
|
|
||||||
#ratio = this.#defaultRatio
|
|
||||||
#opacity = this.#defaultOpacity
|
|
||||||
#padLeft = this.#defaultPadLeft
|
|
||||||
#padRight = this.#defaultPadRight
|
|
||||||
#padTop = this.#defaultPadTop
|
|
||||||
#padBottom = this.#defaultPadBottom
|
|
||||||
#scale = this.#defaultScale
|
|
||||||
#logoX = this.#defaultLogoX
|
|
||||||
#logoY = this.#defaultLogoY
|
|
||||||
#isInsightInited = false
|
|
||||||
#doNotTrack = false
|
|
||||||
#useStartAnimation = true
|
|
||||||
|
|
||||||
constructor(el, logoEl) {
|
|
||||||
this.isWallpaperEngine = false
|
|
||||||
this.#el = el
|
|
||||||
this.#logoEl = logoEl
|
|
||||||
this.spinePlayer = null
|
|
||||||
this.#defaultLogoImage = this.#logoEl.src
|
|
||||||
this.#init()
|
|
||||||
}
|
|
||||||
|
|
||||||
#init() {
|
|
||||||
const _this = this
|
|
||||||
window.addEventListener("contextmenu", e => e.preventDefault());
|
|
||||||
document.addEventListener("gesturestart", e => e.preventDefault());
|
|
||||||
|
|
||||||
const resize = () => {
|
|
||||||
_this.#resize(_this)
|
|
||||||
}
|
|
||||||
window.addEventListener("resize", resize, true);
|
|
||||||
resize()
|
|
||||||
this.#setLogoInvertFilter(this.#defaultInvertFilter)
|
|
||||||
this.setLogoOpacity(this.#defaultOpacity)
|
|
||||||
this.#videoEl = document.getElementById("video-src")
|
|
||||||
this.#insertHTML()
|
|
||||||
}
|
|
||||||
|
|
||||||
success() {
|
|
||||||
this.loadViewport()
|
|
||||||
this.insight(false, false)
|
|
||||||
this.#updateOptions("animation_selection", this.spinePlayer.skeleton.data.animations.map(e => e.name))
|
|
||||||
if ((new URLSearchParams(window.location.search)).has("settings") || import.meta.env.MODE === 'development') {
|
|
||||||
this.open()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
insight(isWallpaperEngine, doNotTrack) {
|
|
||||||
this.isWallpaperEngine = isWallpaperEngine
|
|
||||||
if (this.#isInsightInited || import.meta.env.MODE === 'development') return
|
|
||||||
this.#isInsightInited = true
|
|
||||||
this.#doNotTrack = doNotTrack
|
|
||||||
if (this.#doNotTrack) return
|
|
||||||
try {
|
|
||||||
const config = {
|
|
||||||
path: `/${import.meta.env.VITE_LINK}`
|
|
||||||
}
|
|
||||||
if (this.isWallpaperEngine) config.hostname = "file://wallpaperengine.local";
|
|
||||||
window.counterscale = {
|
|
||||||
q: [["set", "siteId", import.meta.env.VITE_INSIGHT_ID], ["trackPageview", config]],
|
|
||||||
};
|
|
||||||
window.counterscaleOnDemandTrack();
|
|
||||||
} catch(e) {
|
|
||||||
console.warn && console.warn(e.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setFPS(value) {
|
|
||||||
this.#fps = value
|
|
||||||
this.spinePlayer.setFps(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
setLogoDisplay(flag) {
|
|
||||||
this.#logoEl.hidden = flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
#resize(_this, value) {
|
|
||||||
_this = _this || this
|
|
||||||
_this.#logoEl.width = window.innerWidth / 2 * (value || _this.#ratio) / 100
|
|
||||||
_this.elementPosition(this.#logoEl, this.#logoX, this.#logoY)
|
|
||||||
}
|
|
||||||
|
|
||||||
#setLogoInvertFilter(flag) {
|
|
||||||
if (!flag) {
|
|
||||||
this.#logoEl.style.filter = "invert(0)"
|
|
||||||
} else {
|
|
||||||
this.#logoEl.style.filter = "invert(1)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setLogo(src, invert_filter) {
|
|
||||||
this.#logoEl.src = src
|
|
||||||
this.#resize()
|
|
||||||
this.#setLogoInvertFilter(invert_filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
#readFile(e, callback = () => { }) {
|
|
||||||
const file = e.target.files[0]
|
|
||||||
if (!file) return
|
|
||||||
callback(URL.createObjectURL(file.slice()), file.type)
|
|
||||||
}
|
|
||||||
|
|
||||||
setLogoImage(e) {
|
|
||||||
this.#readFile(
|
|
||||||
e,
|
|
||||||
(blobURL, type) => {
|
|
||||||
this.setLogo(blobURL, false)
|
|
||||||
document.getElementById("logo_image_clear").disabled = false
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
resetLogoImage() {
|
|
||||||
this.setLogo(this.#defaultLogoImage, this.#defaultInvertFilter)
|
|
||||||
document.getElementById("logo_image_clear").disabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
setLogoRatio(value) {
|
|
||||||
this.#ratio = value
|
|
||||||
this.#resize(this, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
setLogoOpacity(value) {
|
|
||||||
this.#logoEl.style.opacity = value / 100
|
|
||||||
this.#opacity = value
|
|
||||||
}
|
|
||||||
|
|
||||||
setBackgoundImage(v) {
|
|
||||||
document.body.style.backgroundImage = v
|
|
||||||
}
|
|
||||||
|
|
||||||
get currentBackground() {
|
|
||||||
if (!document.getElementById("custom_background_clear").disabled) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return this.#defaultBackgroundImage.replace(/^(url\(('|"))(.+)(\/)(.+.png)(('|")\))$/, '$5')
|
|
||||||
}
|
|
||||||
|
|
||||||
setDefaultBackground(e) {
|
|
||||||
this.#defaultBackgroundImage = `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(this.#defaultBackgroundImage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setBackground(e) {
|
|
||||||
this.#readFile(
|
|
||||||
e,
|
|
||||||
(blobURL, type) => {
|
|
||||||
this.setBackgoundImage(`url("${blobURL}")`)
|
|
||||||
document.getElementById("custom_background_clear").disabled = false
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
resetBackground() {
|
|
||||||
document.getElementById("custom_background").value = ""
|
|
||||||
document.getElementById("custom_background_clear").disabled = true
|
|
||||||
this.setBackgoundImage(this.#defaultBackgroundImage)
|
|
||||||
}
|
|
||||||
|
|
||||||
loadViewport() {
|
|
||||||
this.spinePlayer.updateViewport({
|
|
||||||
padLeft: `${this.#padLeft}%`,
|
|
||||||
padRight: `${this.#padRight}%`,
|
|
||||||
padTop: `${this.#padTop}%`,
|
|
||||||
padBottom: `${this.#padBottom}%`,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
setScale(value) {
|
|
||||||
this.#scale = value
|
|
||||||
}
|
|
||||||
|
|
||||||
get scale() {
|
|
||||||
return 1 / this.#scale
|
|
||||||
}
|
|
||||||
|
|
||||||
positionPadding(key, value) {
|
|
||||||
switch (key) {
|
|
||||||
case "left":
|
|
||||||
this.#padLeft = value
|
|
||||||
break;
|
|
||||||
case "right":
|
|
||||||
this.#padRight = value
|
|
||||||
break;
|
|
||||||
case "top":
|
|
||||||
this.#padTop = value
|
|
||||||
break;
|
|
||||||
case "bottom":
|
|
||||||
this.#padBottom = value
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.#padLeft = value.left
|
|
||||||
this.#padRight = value.right
|
|
||||||
this.#padTop = value.top
|
|
||||||
this.#padBottom = value.bottom
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.loadViewport()
|
|
||||||
}
|
|
||||||
|
|
||||||
positionReset() {
|
|
||||||
this.#padLeft = this.#defaultPadLeft
|
|
||||||
this.#padRight = this.#defaultPadRight
|
|
||||||
this.#padTop = this.#defaultPadTop
|
|
||||||
this.#padBottom = this.#defaultPadBottom
|
|
||||||
this.spinePlayer.updateViewport(this.#defaultViewport)
|
|
||||||
document.getElementById("position_padding_left_slider").value = this.#defaultPadLeft
|
|
||||||
document.getElementById("position_padding_left_input").value = this.#defaultPadLeft
|
|
||||||
document.getElementById("position_padding_right_slider").value = this.#defaultPadRight
|
|
||||||
document.getElementById("position_padding_right_input").value = this.#defaultPadRight
|
|
||||||
document.getElementById("position_padding_top_slider").value = this.#defaultPadTop
|
|
||||||
document.getElementById("position_padding_top_input").value = this.#defaultPadTop
|
|
||||||
document.getElementById("position_padding_bottom_slider").value = this.#defaultPadBottom
|
|
||||||
document.getElementById("position_padding_bottom_input").value = this.#defaultPadBottom
|
|
||||||
}
|
|
||||||
|
|
||||||
scaleReset() {
|
|
||||||
this.#scale = this.#defaultScale
|
|
||||||
}
|
|
||||||
|
|
||||||
elementPosition(el, x, y) {
|
|
||||||
const computedStyle = getComputedStyle(el)
|
|
||||||
const elWidth = computedStyle.width
|
|
||||||
const elHeight = computedStyle.height
|
|
||||||
const windowWidth = window.innerWidth
|
|
||||||
const windowHeight = window.innerHeight
|
|
||||||
const xRange = windowWidth - parseInt(elWidth)
|
|
||||||
const yRange = windowHeight - parseInt(elHeight)
|
|
||||||
const xpx = x * xRange / 100
|
|
||||||
const ypx = y * yRange / 100
|
|
||||||
el.style.transform = `translate(${xpx}px, ${ypx}px)`
|
|
||||||
}
|
|
||||||
|
|
||||||
logoPadding(key, value) {
|
|
||||||
switch (key) {
|
|
||||||
case "x":
|
|
||||||
this.#logoX = value
|
|
||||||
break;
|
|
||||||
case "y":
|
|
||||||
this.#logoY = value
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.#logoX = value.x
|
|
||||||
this.#logoY = value.y
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.elementPosition(this.#logoEl, this.#logoX, this.#logoY)
|
|
||||||
}
|
|
||||||
|
|
||||||
logoReset() {
|
|
||||||
this.#logoX = this.#defaultLogoX
|
|
||||||
this.#logoY = this.#defaultLogoY
|
|
||||||
this.elementPosition(this.#logoEl, this.#logoX, this.#logoY)
|
|
||||||
document.getElementById("logo_padding_x_slider").value = this.#defaultLogoX
|
|
||||||
document.getElementById("logo_padding_x_input").value = this.#defaultLogoX
|
|
||||||
document.getElementById("logo_padding_y_slider").value = this.#defaultLogoY
|
|
||||||
document.getElementById("logo_padding_y_input").value = this.#defaultLogoY
|
|
||||||
}
|
|
||||||
|
|
||||||
set useStartAnimation(v) {
|
|
||||||
this.#useStartAnimation = v
|
|
||||||
}
|
|
||||||
|
|
||||||
get useStartAnimation() {
|
|
||||||
return this.#useStartAnimation
|
|
||||||
}
|
|
||||||
|
|
||||||
open() {
|
|
||||||
this.#el.hidden = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
close() {
|
|
||||||
this.#el.hidden = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
reset() {
|
|
||||||
this.positionReset()
|
|
||||||
this.scaleReset()
|
|
||||||
this.setLogoRatio(this.#defaultRatio)
|
|
||||||
document.getElementById("logo_ratio_slider").value = this.#defaultRatio
|
|
||||||
document.getElementById("logo_ratio_input").value = this.#defaultRatio
|
|
||||||
this.setLogoOpacity(this.#defaultOpacity)
|
|
||||||
document.getElementById("logo_opacity_slider").value = this.#defaultOpacity
|
|
||||||
document.getElementById("logo_opacity_input").value = this.#defaultOpacity
|
|
||||||
this.resetLogoImage()
|
|
||||||
this.logoReset()
|
|
||||||
this.resetBackground()
|
|
||||||
this.resetMusic()
|
|
||||||
this.setLogoDisplay(this.#defaulthideLogo)
|
|
||||||
this.setFPS(this.#defaultFps)
|
|
||||||
document.getElementById("fps_slider").value = this.#defaultFps
|
|
||||||
document.getElementById("fps_input").value = this.#defaultFps
|
|
||||||
this.spinePlayer.play()
|
|
||||||
}
|
|
||||||
|
|
||||||
setMusicFromWE(url) {
|
|
||||||
const type = url.split(".").pop()
|
|
||||||
window.music.setMusic(url, type)
|
|
||||||
document.getElementById("custom_music_clear").disabled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
setMusic(e) {
|
|
||||||
this.#readFile(
|
|
||||||
e,
|
|
||||||
(blobURL, type) => {
|
|
||||||
window.music.setMusic(blobURL, type)
|
|
||||||
document.getElementById("custom_music_clear").disabled = false
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
resetMusic() {
|
|
||||||
document.getElementById("custom_music").value = ""
|
|
||||||
document.getElementById("custom_music_clear").disabled = true
|
|
||||||
window.music.resetMusic()
|
|
||||||
}
|
|
||||||
|
|
||||||
setVideo(e) {
|
|
||||||
this.#readFile(
|
|
||||||
e,
|
|
||||||
(blobURL, type) => {
|
|
||||||
this.#videoEl.src = blobURL
|
|
||||||
this.#videoEl.load()
|
|
||||||
document.getElementById("custom_video_background_clear").disabled = false
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
setVideoVolume(value) {
|
|
||||||
this.#videoEl.volume = value / 100
|
|
||||||
}
|
|
||||||
|
|
||||||
getVideoVolume() {
|
|
||||||
return this.#videoEl.volume * 100
|
|
||||||
}
|
|
||||||
|
|
||||||
setVideoFromWE(url) {
|
|
||||||
this.#videoEl.src = url
|
|
||||||
this.#videoEl.load()
|
|
||||||
document.getElementById("custom_video_background_clear").disabled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
resetVideo() {
|
|
||||||
this.#videoEl.src = ""
|
|
||||||
document.getElementById("custom_video_background").value = ""
|
|
||||||
document.getElementById("custom_video_background_clear").disabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
#insertHTML() {
|
|
||||||
this.#el.innerHTML = `
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<label for="fps">FPS</label>
|
|
||||||
<input type="range" min="1" max="60" value="${this.#fps}" step="1" id="fps_slider"/>
|
|
||||||
<input type="number" id="fps_input" min="1" max="60" name="fps" value="${this.#fps}" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="operator_logo">Operator Logo</label>
|
|
||||||
<input type="checkbox" id="operator_logo" name="operator_logo" checked/>
|
|
||||||
<div id="operator_logo_realted">
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="logo_ratio">Logo Ratio</label>
|
|
||||||
<input type="range" min="0" max="100" step="0.1" id="logo_ratio_slider" value="${this.#ratio}" />
|
|
||||||
<input type="number" id="logo_ratio_input" name="logo_ratio" value="${this.#ratio}" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="logo_opacity">Logo Opacity</label>
|
|
||||||
<input type="range" min="0" max="100" data-css-class="logo" step="1" id="logo_opacity_slider" value="${this.#opacity}" />
|
|
||||||
<input type="number" id="logo_opacity_input" name="logo_opacity" value="${this.#opacity}" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="logo_padding_x">Logo X Position</label>
|
|
||||||
<input type="range" min="0" max="100" id="logo_padding_x_slider" value="${this.#logoX}" />
|
|
||||||
<input type="number" id="logo_padding_x_input" name="logo_padding_x" value="${this.#logoX}" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="logo_padding_y">Logo Y Position</label>
|
|
||||||
<input type="range" min="0" max="100" id="logo_padding_y_slider" value="${this.#logoY}" />
|
|
||||||
<input type="number" id="logo_padding_y_input" name="logo_padding_y" value="${this.#logoY}" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<label for="default_background_select">Choose a default background:</label>
|
|
||||||
<select name="default_backgrounds" id="default_background_select">
|
|
||||||
${this.#updateOptions(null, JSON.parse(import.meta.env.VITE_BACKGROUND_FILES))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="video">Video</label>
|
|
||||||
<input type="checkbox" id="video" name="video" />
|
|
||||||
<div id="video_realted" hidden>
|
|
||||||
<div>
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="video_volume">Video Volume</label>
|
|
||||||
<input type="range" min="0" max="100" step="1" id="video_volume_slider" value="${this.getVideoVolume()}" />
|
|
||||||
<input type="number" id="video_volume_input" min="0" max="100" step="1" name="video_volume" value="${this.getVideoVolume() }" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="voice">Voice</label>
|
|
||||||
<input type="checkbox" id="voice" name="voice"/>
|
|
||||||
<div id="voice_realted" hidden>
|
|
||||||
<div>
|
|
||||||
<label for="voice_lang_select">Choose the language of voice:</label>
|
|
||||||
<select name="voice_lang" id="voice_lang_select">
|
|
||||||
${this.#updateOptions("voice_lang_select", window.voice.languages)}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="voice_idle_duration">Idle Duration (min)</label>
|
|
||||||
<input type="number" id="voice_idle_duration_input" min="0" name="voice_idle_duration" value="${window.voice.idleDuration}" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="voice_next_duration">Next Duration (min)</label>
|
|
||||||
<input type="number" id="voice_next_duration_input" name="voice_next_duration" value="${window.voice.nextDuration}" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="subtitle">Subtitle</label>
|
|
||||||
<input type="checkbox" id="subtitle" name="subtitle"/>
|
|
||||||
<div id="subtitle_realted" hidden>
|
|
||||||
<div>
|
|
||||||
<label for="subtitle_lang_select">Choose the language of subtitle:</label>
|
|
||||||
<select name="subtitle_lang" id="subtitle_lang_select">
|
|
||||||
${this.#updateOptions("subtitle_lang_select", window.voice.subtitleLanguages)}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="subtitle_padding_x">Subtitle X Position</label>
|
|
||||||
<input type="range" min="0" max="100" id="subtitle_padding_x_slider" value="${window.voice.subtitleX}" />
|
|
||||||
<input type="number" id="subtitle_padding_x_input" name="subtitle_padding_x" value="${window.voice.subtitleX}" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="subtitle_padding_y">Subtitle Y Position</label>
|
|
||||||
<input type="range" min="0" max="100" id="subtitle_padding_y_slider" value="${window.voice.subtitleY}" />
|
|
||||||
<input type="number" id="subtitle_padding_y_input" name="subtitle_padding_y" value="${window.voice.subtitleY}" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="voice_actor">Voice Actor</label>
|
|
||||||
<input type="checkbox" id="voice_actor" name="voice_actor"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="music">Music</label>
|
|
||||||
<input type="checkbox" id="music" name="music" />
|
|
||||||
<div id="music_realted" hidden>
|
|
||||||
<div>
|
|
||||||
<label for="music_select">Choose theme music:</label>
|
|
||||||
<select name="music_select" id="music_select">
|
|
||||||
${this.#updateOptions("music_select", window.music.music)}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="music_volume">Music Volume</label>
|
|
||||||
<input type="range" min="0" max="100" step="1" id="music_volume_slider" value="${window.music.volume}" />
|
|
||||||
<input type="number" id="music_volume_input" min="0" max="100" step="1" name="music_volume" value="${window.music.volume}" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="music_switch_offset">Music Swtich Offset</label>
|
|
||||||
<input type="range" min="0" max="1" step="0.01" id="music_switch_offset_slider" value="${window.music.timeOffset}" />
|
|
||||||
<input type="number" id="music_switch_offset_input" min="0" max="1" step="0.01" name="music_switch_offset" value="${window.music.timeOffset}" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="scale">Scale</label>
|
|
||||||
<input type="range" min="0.1" max="10" step="0.1" id="scale_slider" value="${this.#scale}" />
|
|
||||||
<input type="number" id="scale_input" name="scale" value="${this.#scale}" step="0.1"/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="position">Position</label>
|
|
||||||
<input type="checkbox" id="position" name="position" />
|
|
||||||
<div id="position_realted" hidden>
|
|
||||||
<div>
|
|
||||||
<label for="position_padding_left">Padding Left</label>
|
|
||||||
<input type="range" min="-100" max="100" id="position_padding_left_slider" value="${this.#padLeft}" />
|
|
||||||
<input type="number" id="position_padding_left_input" name="position_padding_left" value="${this.#padLeft}" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="position_padding_right">Padding Right</label>
|
|
||||||
<input type="range" min="-100" max="100" id="position_padding_right_slider" value="${this.padRight}" />
|
|
||||||
<input type="number" id="position_padding_right_input" name="position_padding_right" value="${this.#padRight}" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="position_padding_top">Padding Top</label>
|
|
||||||
<input type="range" min="-100" max="100" id="position_padding_top_slider" value="${this.#padTop}" />
|
|
||||||
<input type="number" id="position_padding_top_input" name="position_padding_top" value="${this.#padTop}" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="position_padding_bottom">Padding Bottom</label>
|
|
||||||
<input type="range" min="-100" max="100" id="position_padding_bottom_slider" value="${this.#padBottom}" />
|
|
||||||
<input type="number" id="position_padding_bottom_input" name="position_padding_bottom" value="${this.#padBottom}" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="animation_select">Animation:</label>
|
|
||||||
<select name="animation_select" id="animation_selection"></select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="use_start_animation">Use Start Animation</label>
|
|
||||||
<input type="checkbox" id="use_start_animation" name="use_start_animation" checked/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button type="button" id="settings_play" disabled>Play</button>
|
|
||||||
<button type="button" id="settings_pause">Pause</button>
|
|
||||||
<button type="button" id="settings_reset">Reset</button>
|
|
||||||
<button type="button" id="settings_close">Close</button>
|
|
||||||
<button type="button" id="settings_to_directory">Back to Directory</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
this.#addEventListeners()
|
|
||||||
}
|
|
||||||
|
|
||||||
#sync(source, targetID) {
|
|
||||||
if (typeof source === "string") source = document.getElementById(source);
|
|
||||||
document.getElementById(targetID).value = source.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
#showRelated(e, relatedSettingsID, revert = false) {
|
|
||||||
const eRelatedSettings = document.getElementById(relatedSettingsID)
|
|
||||||
const checked = revert ? !e.checked : e.checked;
|
|
||||||
if (checked) {
|
|
||||||
eRelatedSettings.hidden = false;
|
|
||||||
} else {
|
|
||||||
eRelatedSettings.hidden = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#updateOptions(id, array) {
|
|
||||||
const e = document.getElementById(id);
|
|
||||||
const value = array.map(item => `<option value="${item}">${item}</option>`)
|
|
||||||
if (e) {
|
|
||||||
e.innerHTML = value.join("");
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
#getCurrentOptions(id, value) {
|
|
||||||
const e = document.getElementById(id);
|
|
||||||
const options = [...e]
|
|
||||||
const toSelecteIndex = options.findIndex(i => options.find(o => o.value === value) === i)
|
|
||||||
e.selectedIndex = toSelecteIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
#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: () => _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: () => _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)
|
|
||||||
_this.#getCurrentOptions("subtitle_lang_select", window.voice.subtitleLanguage)
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
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: "subtitle_padding_x_slider", event: "input", handler: e => {
|
|
||||||
_this.#sync(e.currentTarget, "subtitle_padding_x_input");
|
|
||||||
window.voice.subtitleX = e.currentTarget.value
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "subtitle_padding_x_input", event: "change", handler: e => {
|
|
||||||
_this.#sync(e.currentTarget, "subtitle_padding_x_slider");
|
|
||||||
window.voice.subtitleX = e.currentTarget.value
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "subtitle_padding_y_slider", event: "input", handler: e => {
|
|
||||||
_this.#sync(e.currentTarget, "subtitle_padding_y_input");
|
|
||||||
window.voice.subtitleY = e.currentTarget.value
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "subtitle_padding_y_input", event: "change", handler: e => {
|
|
||||||
_this.#sync(e.currentTarget, "subtitle_padding_y_slider");
|
|
||||||
window.voice.subtitleY = e.currentTarget.value
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "voice_actor", event: "click", handler: e => {
|
|
||||||
window.voice.useVoiceActor = e.currentTarget.checked;
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "music", event: "click", handler: e => {
|
|
||||||
_this.#showRelated(e.currentTarget, "music_realted");
|
|
||||||
window.music.useMusic = e.currentTarget.checked;
|
|
||||||
window.music.changeMusic(this.currentBackground)
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "music_select", event: "change", handler: e => window.music.changeMusic(e.currentTarget.value)
|
|
||||||
}, {
|
|
||||||
id: "custom_music", event: "change", handler: e => _this.setMusic(e)
|
|
||||||
}, {
|
|
||||||
id: "custom_music_clear", event: "click", handler: () => _this.resetMusic()
|
|
||||||
}, {
|
|
||||||
id: "music_volume_slider", event: "input", handler: e => {
|
|
||||||
_this.#sync(e.currentTarget, "music_volume_input");
|
|
||||||
window.music.volume = parseInt(e.currentTarget.value)
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "music_volume_input", event: "change", handler: e => {
|
|
||||||
_this.#sync(e.currentTarget, "music_volume_slider");
|
|
||||||
window.music.volume = parseInt(e.currentTarget.value)
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "music_switch_offset_slider", event: "input", handler: e => {
|
|
||||||
_this.#sync(e.currentTarget, "music_switch_offset_input");
|
|
||||||
window.music.timeOffset = parseFloat(e.currentTarget.value)
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "music_switch_offset_input", event: "change", handler: e => {
|
|
||||||
_this.#sync(e.currentTarget, "music_switch_offset_slider");
|
|
||||||
window.music.timeOffset = parseFloat(e.currentTarget.value)
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "video", event: "click", handler: e => {
|
|
||||||
_this.#showRelated(e.currentTarget, "video_realted");
|
|
||||||
if (!e.currentTarget.checked) _this.resetVideo()
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "custom_video_background", event: "change", handler: e => _this.setVideo(e)
|
|
||||||
}, {
|
|
||||||
id: "custom_video_background_clear", event: "click", handler: () => _this.resetVideo()
|
|
||||||
}, {
|
|
||||||
id: "video_volume_slider", event: "input", handler: e => {
|
|
||||||
_this.#sync(e.currentTarget, "video_volume_input");
|
|
||||||
this.setVideoVolume(parseInt(e.currentTarget.value))
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "video_volume_input", event: "change", handler: e => {
|
|
||||||
_this.#sync(e.currentTarget, "video_volume_slider");
|
|
||||||
this.setVideoVolume(parseInt(e.currentTarget.value))
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "position", event: "click", handler: e => {
|
|
||||||
_this.#showRelated(e.currentTarget, "position_realted");
|
|
||||||
if (!e.currentTarget.checked) _this.positionReset();
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "scale_slider", event: "input", handler: e => {
|
|
||||||
_this.#sync(e.currentTarget, "scale_input");
|
|
||||||
_this.setScale(e.currentTarget.value);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "scale_input", event: "change", handler: e => {
|
|
||||||
_this.#sync(e.currentTarget, "scale_slider");
|
|
||||||
_this.setScale(e.currentTarget.value);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
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: () => _this.reset()
|
|
||||||
}, {
|
|
||||||
id: "settings_close", event: "click", handler: () => _this.close()
|
|
||||||
}, {
|
|
||||||
id: "animation_selection", event: "change", handler: e => {
|
|
||||||
this.spinePlayer.animationState.setAnimation(0, e.currentTarget.value, false, 0)
|
|
||||||
this.spinePlayer.animationState.addAnimation(0, "Idle", true, 0);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "use_start_animation", event: "click", handler: e => {
|
|
||||||
this.#useStartAnimation = e.currentTarget.checked;
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
id: "settings_to_directory", event: "click", handler: () => {
|
|
||||||
window.location.href = '/';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
listeners.forEach(listener => {
|
|
||||||
document.getElementById(listener.id).addEventListener(listener.event, e => listener.handler(e))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
@import "https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;500;700&family=Noto+Sans+KR:wght@400;500;700&family=Noto+Sans+SC:wght@400;500;700&family=Noto+Sans:wght@400;500;700&display=swap";
|
@import "https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;500;700&family=Noto+Sans+KR:wght@400;500;700&family=Noto+Sans+SC:wght@400;500;700&family=Noto+Sans:wght@400;500;700&display=swap";
|
||||||
|
|
||||||
#voice_box {
|
#voice-box {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
left: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
@@ -22,35 +22,34 @@
|
|||||||
padding: 2px 8px;
|
padding: 2px 8px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
min-width: 120px;
|
min-width: 120px;
|
||||||
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.5);
|
box-shadow: 0 3px 6px rgb(0 0 0 / 50%);
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.voice-subtitle {
|
.voice-subtitle {
|
||||||
background-color: rgba(0, 0, 0, 0.65);
|
background-color: rgb(0 0 0 / 65%);
|
||||||
color: white;
|
color: white;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
box-shadow: 0px 6px 12px rgba(0, 0, 0, 0.5);
|
box-shadow: 0 6px 12px rgb(0 0 0 / 50%);
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.voice-triangle {
|
.voice-triangle {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0px;
|
bottom: 0;
|
||||||
right: 8px;
|
right: 8px;
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-width: 8px 8px 8px 8px;
|
border-width: 8px;
|
||||||
border-color: white transparent transparent transparent;
|
border-color: white transparent transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.voice-actor {
|
.voice-actor {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-flow: row nowrap;
|
||||||
flex-wrap: nowrap;
|
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
@@ -58,7 +57,7 @@
|
|||||||
.voice-actor-icon {
|
.voice-actor-icon {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
background-color: rgba(0, 0, 0, 1);
|
background-color: rgb(0 0 0);
|
||||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAXCAYAAAAGAx/kAAACGElEQVQ4jY2UO4sUQRSFv+6e3hkf6yqi62LiD1DRwGRFZDUTRTAVMTHzHxhosBgr+IhMzIXFRzKJYiQoCLqroYGCgiDK6K6z8+hj0Kd2yrZn8EJRza06X91761Ynkphgh4ETwBB4BrwZu1NS3WhJui1pTSNblXTLa/9oxoEWNd4W/xc0K6kzAfRd0lxV16jJdg6YBtaAB8AvoPA4D+wEZoEvsSgGJYAiXwf4EEFyYOC1qYqmFhQ2bQEO+MYKILMv1tWCikqKm4CPwKoF00DTa6pqkqiP9gIHgR3AWaDvdJIoip4jewh8BVaAz1XQOeAKcNcp9O0fAqlTLgzsApeBa8BSNbUUaAFvgVdMtnlHmsXiEHrHpw+iaOps4BRlDUASQDnw3uA9QHsCqA3sMmjFmhRJmaSmO/SmpCeSjktarunqd5IWJLUl3bCmKSlLJGWuVQbMAHcoi3oPWAAOOerXwFPgErAVuEjZGkNgkEhKDco9bwOuG/Ac+OS67ANOGngV+OYDewEUqt+gvLWmxxHgFHDapz52fV4C64Z3PW+AUsPyCJYCP4FHPuQMsNlRrHv0DRo2XP3Ccw/4Tdl8U2GTb6trYYimYNQ6Gw0pYDuwn1E7hJR3W3TMvp5hKbAM/IC/n8hR4L6hqSPJGT3QjPIfFX4nDeAC8CIGhTrBqNsz16plWN/R9KJShGzUiCBBnFS+FYmCP41gBaA/cImMsTl24NIAAAAASUVORK5CYII=');
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAAXCAYAAAAGAx/kAAACGElEQVQ4jY2UO4sUQRSFv+6e3hkf6yqi62LiD1DRwGRFZDUTRTAVMTHzHxhosBgr+IhMzIXFRzKJYiQoCLqroYGCgiDK6K6z8+hj0Kd2yrZn8EJRza06X91761Ynkphgh4ETwBB4BrwZu1NS3WhJui1pTSNblXTLa/9oxoEWNd4W/xc0K6kzAfRd0lxV16jJdg6YBtaAB8AvoPA4D+wEZoEvsSgGJYAiXwf4EEFyYOC1qYqmFhQ2bQEO+MYKILMv1tWCikqKm4CPwKoF00DTa6pqkqiP9gIHgR3AWaDvdJIoip4jewh8BVaAz1XQOeAKcNcp9O0fAqlTLgzsApeBa8BSNbUUaAFvgVdMtnlHmsXiEHrHpw+iaOps4BRlDUASQDnw3uA9QHsCqA3sMmjFmhRJmaSmO/SmpCeSjktarunqd5IWJLUl3bCmKSlLJGWuVQbMAHcoi3oPWAAOOerXwFPgErAVuEjZGkNgkEhKDco9bwOuG/Ac+OS67ANOGngV+OYDewEUqt+gvLWmxxHgFHDapz52fV4C64Z3PW+AUsPyCJYCP4FHPuQMsNlRrHv0DRo2XP3Ccw/4Tdl8U2GTb6trYYimYNQ6Gw0pYDuwn1E7hJR3W3TMvp5hKbAM/IC/n8hR4L6hqSPJGT3QjPIfFX4nDeAC8CIGhTrBqNsz16plWN/R9KJShGzUiCBBnFS+FYmCP41gBaA/cImMsTl24NIAAAAASUVORK5CYII=');
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
@@ -68,7 +67,7 @@
|
|||||||
height: 16px;
|
height: 16px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
background-color: rgba(0, 0, 0, 0.3);
|
background-color: rgb(0 0 0 / 30%);
|
||||||
color: white;
|
color: white;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
|||||||
@@ -1,329 +1,568 @@
|
|||||||
|
import {
|
||||||
|
insertHTMLChild,
|
||||||
|
updateElementPosition,
|
||||||
|
updateHTMLOptions,
|
||||||
|
showRelatedHTML,
|
||||||
|
syncHTMLValue
|
||||||
|
} from "@/components/helper";
|
||||||
|
|
||||||
import charword_table from '!/charword_table.json'
|
import charword_table from '!/charword_table.json'
|
||||||
import '@/components/voice.css'
|
import '@/components/voice.css'
|
||||||
|
|
||||||
|
|
||||||
export default class Voice {
|
export default class Voice {
|
||||||
#el
|
#el = document.createElement("div")
|
||||||
|
#parentEl
|
||||||
#widgetEl
|
#widgetEl
|
||||||
#audioEl = new Audio()
|
#default = {
|
||||||
#audioElId = 'voice-audio'
|
region: charword_table.config.default_region,
|
||||||
#defaultRegion = charword_table.config.default_region
|
duration: {
|
||||||
#defaultIdleDuration = 10 * 60 * 1000
|
idle: 10 * 60 * 1000,
|
||||||
#defaultNextDuration = 3 * 60 * 1000
|
next: 3 * 60 * 1000
|
||||||
#voiceLanguages = Object.keys(charword_table.voiceLangs["zh-CN"])
|
},
|
||||||
#defaultVoiceLang = this.#voiceLanguages[0]
|
language: {
|
||||||
#voiceLang = this.#defaultVoiceLang
|
voice: null
|
||||||
#subtitleLang = this.#defaultRegion
|
},
|
||||||
#useSubtitle = false
|
subtitle: {
|
||||||
#useVoice = false
|
x: 0,
|
||||||
#useVoiceActor = false
|
y: 100
|
||||||
#isPlaying = false
|
|
||||||
#currentVoiceId = null
|
|
||||||
#lastVoiceId = null
|
|
||||||
#idleListener = -1
|
|
||||||
#idleDuration = this.#defaultIdleDuration
|
|
||||||
#nextListener = -1
|
|
||||||
#nextDuration = this.#defaultNextDuration
|
|
||||||
#lastClickToNext = false
|
|
||||||
#voiceFolderObject = this.#getVoiceFolderObject()
|
|
||||||
#voiceList = Object.keys(this.#getVoices())
|
|
||||||
#defaultSubtitleX = 0
|
|
||||||
#defaultSubtitleY = 0
|
|
||||||
#subtitleX = this.#defaultSubtitleX
|
|
||||||
#subtitleY = this.#defaultSubtitleY
|
|
||||||
|
|
||||||
constructor(el, widgetEl) {
|
|
||||||
this.#el = el
|
|
||||||
this.#widgetEl = widgetEl
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
this.#insertHTML()
|
|
||||||
this.#audioEl = document.getElementById(this.#audioElId)
|
|
||||||
}
|
|
||||||
|
|
||||||
success() {
|
|
||||||
const audioEndedFunc = () => {
|
|
||||||
this.#isPlaying = false
|
|
||||||
this.#setCurrentSubtitle(null)
|
|
||||||
this.#lastClickToNext = false
|
|
||||||
}
|
}
|
||||||
this.#audioEl.addEventListener('ended', audioEndedFunc)
|
}
|
||||||
this.#playEntryVoice()
|
#voice = {
|
||||||
this.#initNextVoiceTimer()
|
languages: Object.keys(charword_table.voiceLangs[this.#default.region]),
|
||||||
this.#widgetEl.addEventListener('click', () => {
|
id: {
|
||||||
this.#lastClickToNext = true
|
current: null,
|
||||||
this.#nextVoice()
|
last: null
|
||||||
})
|
},
|
||||||
document.addEventListener('mousemove', () => {
|
listener: {
|
||||||
if (this.#idleListener === -1) {
|
idle: -1,
|
||||||
this.#initIdleVoiceTimer()
|
next: -1
|
||||||
}
|
},
|
||||||
})
|
lastClickToNext: false,
|
||||||
|
locations: null,
|
||||||
|
list: null
|
||||||
|
}
|
||||||
|
#audio = {
|
||||||
|
id: "voice-audio",
|
||||||
|
el: new Audio(),
|
||||||
|
isPlaying: false
|
||||||
|
}
|
||||||
|
#config = {
|
||||||
|
useSubtitle: false,
|
||||||
|
useVoice: false,
|
||||||
|
useVoiceActor: false,
|
||||||
|
voiceLang: null,
|
||||||
|
subtitle: {
|
||||||
|
language: this.#default.region,
|
||||||
|
...this.#default.subtitle
|
||||||
|
},
|
||||||
|
duration: {...this.#default.duration}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.#default.language.voice = this.#voice.languages[0]
|
||||||
|
this.#config.voiceLang = this.#default.language.voice
|
||||||
|
this.#voice.locations = this.#getVoiceLocations()
|
||||||
|
this.#voice.list = Object.keys(this.#getVoices())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {boolean} show
|
|
||||||
*/
|
|
||||||
set useSubtitle(show) {
|
set useSubtitle(show) {
|
||||||
this.#useSubtitle = show
|
this.#config.useSubtitle = show
|
||||||
this.#el.hidden = !show
|
this.#el.hidden = !show
|
||||||
}
|
}
|
||||||
|
|
||||||
get useSubtitle() {
|
get useSubtitle() {
|
||||||
return this.#useSubtitle
|
return this.#config.useSubtitle
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {boolean} show
|
|
||||||
*/
|
|
||||||
set useVoice(show) {
|
set useVoice(show) {
|
||||||
this.#useVoice = show
|
this.#config.useVoice = show
|
||||||
this.#playEntryVoice()
|
this.#playEntryVoice()
|
||||||
if (!show && this.#isPlaying) {
|
if (!show && this.#audio.isPlaying) {
|
||||||
this.#audioEl.pause()
|
this.#audio.el.pause()
|
||||||
}
|
}
|
||||||
|
this.#toggleSubtitle(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
get useVoice() {
|
get useVoice() {
|
||||||
return this.#useVoice
|
return this.#config.useVoice
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {boolean} show
|
|
||||||
*/
|
|
||||||
set useVoiceActor(show) {
|
set useVoiceActor(show) {
|
||||||
this.#useVoiceActor = show
|
this.#config.useVoiceActor = show
|
||||||
document.getElementById('voice_actor_box').hidden = !show
|
document.getElementById('voice-actor-box').hidden = !show
|
||||||
}
|
}
|
||||||
|
|
||||||
get useVoiceActor() {
|
get useVoiceActor() {
|
||||||
return this.#useVoiceActor
|
return this.#config.useVoiceActor
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} lang
|
|
||||||
*/
|
|
||||||
set subtitleLanguage(lang) {
|
set subtitleLanguage(lang) {
|
||||||
if (this.#getSubtitleLanguages().includes(lang)) {
|
if (this.#getSubtitleLanguages().includes(lang)) {
|
||||||
this.#subtitleLang = lang
|
this.#config.subtitle.language = lang
|
||||||
} else {
|
} else {
|
||||||
this.#subtitleLang = this.#defaultRegion
|
this.#config.subtitle.language = this.#default.region
|
||||||
}
|
}
|
||||||
|
this.#setCurrentSubtitle(this.#voice.id.current)
|
||||||
}
|
}
|
||||||
|
|
||||||
get subtitleLanguage() {
|
get subtitleLanguage() {
|
||||||
return this.#subtitleLang
|
return this.#config.subtitle.language
|
||||||
}
|
}
|
||||||
|
|
||||||
get subtitleLanguages() {
|
get subtitleLanguages() {
|
||||||
return this.#getSubtitleLanguages()
|
return this.#getSubtitleLanguages()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
get x() {
|
||||||
* @param {int} x
|
return this.position.x
|
||||||
*/
|
}
|
||||||
set subtitleX(x) {
|
|
||||||
this.#subtitleX = x
|
set x(v) {
|
||||||
|
this.position = {
|
||||||
|
x: v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get y() {
|
||||||
|
return this.position.y
|
||||||
|
}
|
||||||
|
|
||||||
|
set y(v) {
|
||||||
|
this.position = {
|
||||||
|
y: v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get position() {
|
||||||
|
return {
|
||||||
|
x: this.#config.subtitle.x,
|
||||||
|
y: this.#config.subtitle.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
this.#updateSubtitlePosition()
|
this.#updateSubtitlePosition()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set subtitleX(x) {
|
||||||
|
// Note: Back Compatibility
|
||||||
|
this.position = {
|
||||||
|
x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get subtitleX() {
|
get subtitleX() {
|
||||||
return this.#subtitleX
|
// Note: Back Compatibility
|
||||||
|
return this.position.x
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {int} y
|
|
||||||
*/
|
|
||||||
set subtitleY(y) {
|
set subtitleY(y) {
|
||||||
this.#subtitleY = y - 100
|
// Note: Back Compatibility
|
||||||
this.#updateSubtitlePosition()
|
this.position = {
|
||||||
|
y
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get subtitleY() {
|
get subtitleY() {
|
||||||
return this.#subtitleY + 100
|
// Note: Back Compatibility
|
||||||
|
return this.position.y
|
||||||
}
|
}
|
||||||
|
|
||||||
#updateSubtitlePosition() {
|
|
||||||
window.settings.elementPosition(this.#el, this.#subtitleX, this.#subtitleY)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} lang
|
|
||||||
*/
|
|
||||||
set language(lang) {
|
set language(lang) {
|
||||||
if (this.#voiceLanguages.includes(lang)) {
|
if (this.#voice.languages.includes(lang)) {
|
||||||
this.#voiceLang = lang
|
this.#config.voiceLang = lang
|
||||||
} else {
|
} else {
|
||||||
this.#voiceLang = this.#defaultVoiceLang
|
this.#config.voiceLang = this.#default.language.voice
|
||||||
}
|
}
|
||||||
const availableSubtitleLang = this.#getSubtitleLanguages()
|
const availableSubtitleLang = this.#getSubtitleLanguages()
|
||||||
if (!availableSubtitleLang.includes(this.#subtitleLang)) {
|
if (!availableSubtitleLang.includes(this.#config.subtitle.language)) {
|
||||||
this.#subtitleLang = availableSubtitleLang[0]
|
this.#config.subtitle.language = availableSubtitleLang[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get language() {
|
get language() {
|
||||||
return this.#voiceLang
|
return this.#config.voiceLang
|
||||||
}
|
}
|
||||||
|
|
||||||
get languages() {
|
get languages() {
|
||||||
return this.#voiceLanguages
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {int} duration
|
|
||||||
*/
|
|
||||||
set idleDuration(duration) {
|
set idleDuration(duration) {
|
||||||
clearInterval(this.#idleListener)
|
// Note: Back Compatibility
|
||||||
if (duration !== 0) {
|
this.duration = {
|
||||||
this.#idleDuration = duration * 60 * 1000
|
idle: duration
|
||||||
this.#initIdleVoiceTimer()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get idleDuration() {
|
get idleDuration() {
|
||||||
return this.#idleDuration / 60 / 1000
|
// Note: Back Compatibility
|
||||||
|
return this.duration.idle
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
set durationNext(duration) {
|
||||||
* @param {int} duration
|
this.duration = {
|
||||||
*/
|
next: duration
|
||||||
set nextDuration(duration) {
|
|
||||||
clearInterval(this.#nextListener)
|
|
||||||
if (duration !== 0) {
|
|
||||||
this.#nextDuration = duration * 60 * 1000
|
|
||||||
this.#initNextVoiceTimer()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set nextDuration(duration) {
|
||||||
|
// Note: Back Compatibility
|
||||||
|
this.duration.next = duration
|
||||||
|
}
|
||||||
|
|
||||||
|
get durationNext() {
|
||||||
|
return this.duration.next
|
||||||
|
}
|
||||||
|
|
||||||
get nextDuration() {
|
get nextDuration() {
|
||||||
return this.#nextDuration / 60 / 1000
|
// Note: Back Compatibility
|
||||||
|
return this.duration.next
|
||||||
}
|
}
|
||||||
|
|
||||||
#initIdleVoiceTimer() {
|
init(el, widgetEl) {
|
||||||
this.#idleListener = setInterval(() => {
|
this.#parentEl = el
|
||||||
this.#playSpecialVoice("闲置")
|
this.#widgetEl = widgetEl
|
||||||
clearInterval(this.#idleListener)
|
this.#el.id = "voice-box"
|
||||||
this.#idleListener = -1
|
this.#el.hidden = true
|
||||||
}, this.#idleDuration)
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
#initNextVoiceTimer() {
|
success() {
|
||||||
this.#nextListener = setInterval(() => {
|
const audioEndedFunc = () => {
|
||||||
if (!this.#lastClickToNext) {
|
this.#audio.isPlaying = false
|
||||||
this.#nextVoice()
|
this.#setCurrentSubtitle(null)
|
||||||
}
|
this.#audio.lastClickToNext = false
|
||||||
}, this.#nextDuration)
|
|
||||||
}
|
|
||||||
|
|
||||||
#nextVoice() {
|
|
||||||
const voiceId = () => {
|
|
||||||
const id = this.#voiceList[Math.floor((Math.random() * this.#voiceList.length))]
|
|
||||||
return id === this.#lastVoiceId ? voiceId() : id
|
|
||||||
}
|
}
|
||||||
this.#playVoice(voiceId())
|
this.#audio.el.addEventListener('ended', audioEndedFunc)
|
||||||
|
this.#playEntryVoice()
|
||||||
|
this.#initNextVoiceTimer()
|
||||||
|
this.#widgetEl.addEventListener('click', () => {
|
||||||
|
this.#audio.lastClickToNext = true
|
||||||
|
this.#nextVoice()
|
||||||
|
})
|
||||||
|
document.addEventListener('mousemove', () => {
|
||||||
|
if (this.#voice.listener.idle === -1) {
|
||||||
|
this.#initIdleVoiceTimer()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#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() {
|
#playEntryVoice() {
|
||||||
this.#playSpecialVoice("问候")
|
this.#playSpecialVoice("问候")
|
||||||
}
|
}
|
||||||
|
|
||||||
#setCurrentSubtitle(id) {
|
|
||||||
if (id === null) {
|
|
||||||
setTimeout(() => {
|
|
||||||
if (this.#isPlaying) return
|
|
||||||
this.#el.style.opacity = 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.#voiceLang]
|
|
||||||
document.getElementById('voice_title').innerText = title
|
|
||||||
document.getElementById('voice_subtitle').innerText = content
|
|
||||||
this.#el.style.opacity = 1
|
|
||||||
document.getElementById('voice_actor_name').innerText = cvInfo.join('')
|
|
||||||
}
|
|
||||||
|
|
||||||
#playVoice(id) {
|
|
||||||
if (!this.useVoice) return
|
|
||||||
this.#lastVoiceId = this.#currentVoiceId
|
|
||||||
this.#currentVoiceId = id
|
|
||||||
this.#audioEl.src = `./assets/${this.#getVoiceFoler()
|
|
||||||
}/${id}.ogg`
|
|
||||||
let startPlayPromise = this.#audioEl.play()
|
|
||||||
if (startPlayPromise !== undefined) {
|
|
||||||
startPlayPromise
|
|
||||||
.then(() => {
|
|
||||||
this.#isPlaying = true
|
|
||||||
this.#setCurrentSubtitle(id)
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
return
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#playSpecialVoice(matcher) {
|
#playSpecialVoice(matcher) {
|
||||||
const voices = this.#getVoices()
|
const voices = this.#getVoices()
|
||||||
const voiceId = Object.keys(voices).find(e => voices[e].title === matcher)
|
const voiceId = Object.keys(voices).find(e => voices[e].title === matcher)
|
||||||
this.#playVoice(voiceId)
|
this.#playVoice(voiceId)
|
||||||
}
|
}
|
||||||
|
|
||||||
#getVoiceFoler() {
|
#playVoice(id) {
|
||||||
const folderObject = this.#voiceFolderObject
|
if (!this.useVoice) return
|
||||||
return `${folderObject.main}/${folderObject.sub.find(e => e.lang === this.#voiceLang).name}`
|
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
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#getVoices() {
|
#getVoiceLocation() {
|
||||||
return charword_table.subtitleLangs[this.#subtitleLang].default
|
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) {
|
#getSubtitleById(id) {
|
||||||
const obj = charword_table.subtitleLangs[this.#subtitleLang]
|
const obj = charword_table.subtitleLangs[this.#config.subtitle.language]
|
||||||
let key = 'default'
|
let key = 'default'
|
||||||
if (obj[this.#voiceLang]) {
|
if (obj[this.#config.voiceLang]) {
|
||||||
key = this.#voiceLang
|
key = this.#config.voiceLang
|
||||||
}
|
}
|
||||||
return obj[key][id]
|
return obj[key][id]
|
||||||
}
|
}
|
||||||
|
|
||||||
#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
|
|
||||||
}
|
|
||||||
|
|
||||||
#getSubtitleLanguages() {
|
#getSubtitleLanguages() {
|
||||||
return Object.keys(charword_table.subtitleLangs)
|
return Object.keys(charword_table.subtitleLangs)
|
||||||
}
|
}
|
||||||
|
|
||||||
#insertHTML() {
|
#updateSubtitlePosition() {
|
||||||
this.#el.innerHTML = `
|
updateElementPosition(this.#el, {
|
||||||
<audio id="${this.#audioElId}" autoplay>
|
x: this.position.x,
|
||||||
<source type="audio/ogg" />
|
y: this.position.y - 100
|
||||||
</audio>
|
})
|
||||||
<div class="voice-wrapper" id="voice_wrapper">
|
}
|
||||||
<div class="voice-title" id="voice_title"></div>
|
|
||||||
<div class="voice-subtitle">
|
#initNextVoiceTimer() {
|
||||||
<div id="voice_subtitle"></div>
|
this.#voice.listener.next = setInterval(() => {
|
||||||
<div class="voice-triangle"></div>
|
if (!this.#voice.lastClickToNext) {
|
||||||
</div>
|
this.#nextVoice()
|
||||||
</div>
|
}
|
||||||
<div id="voice_actor_box" hidden>
|
}, this.#config.duration.next)
|
||||||
<div class="voice-actor">
|
}
|
||||||
<span class="voice-actor-icon"></span>
|
|
||||||
<span id="voice_actor_name" class="voice-actor-name"></span>
|
#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 HTML() {
|
||||||
|
return `
|
||||||
|
<div>
|
||||||
|
<label for="voice">Voice</label>
|
||||||
|
<input type="checkbox" id="voice" name="voice"/>
|
||||||
|
<div id="voice-realted" hidden>
|
||||||
|
<div>
|
||||||
|
<label for="voice-lang-select">Choose the language of voice:</label>
|
||||||
|
<select name="voice-lang" id="voice-lang-select">
|
||||||
|
${updateHTMLOptions(this.languages)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="voice-idle-duration">Idle Duration (min)</label>
|
||||||
|
<input type="number" id="voice-idle-duration-input" min="0" name="voice-idle-duration" value="${this.duration.idle}" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="voice-next-duration">Next Duration (min)</label>
|
||||||
|
<input type="number" id="voice-next-duration-input" name="voice-next-duration" value="${this.duration.next}" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="subtitle">Subtitle</label>
|
||||||
|
<input type="checkbox" id="subtitle" name="subtitle"/>
|
||||||
|
<div id="subtitle-realted" hidden>
|
||||||
|
<div>
|
||||||
|
<label for="subtitle-lang-select">Choose the language of subtitle:</label>
|
||||||
|
<select name="subtitle-lang" id="subtitle-lang-select">
|
||||||
|
${updateHTMLOptions(this.subtitleLanguages)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="subtitle-padding-x">Subtitle X Position</label>
|
||||||
|
<input type="range" min="0" max="100" id="subtitle-padding-x-slider" value="${this.position.x}" />
|
||||||
|
<input type="number" id="subtitle-padding-x-input" name="subtitle-padding-x" value="${this.position.x}" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="subtitle-padding-y">Subtitle Y Position</label>
|
||||||
|
<input type="range" min="0" max="100" id="subtitle-padding-y-slider" value="${this.position.y}" />
|
||||||
|
<input type="number" id="subtitle-padding-y-input" name="subtitle-padding-y" value="${this.position.y}" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="voice-actor">Voice Actor</label>
|
||||||
|
<input type="checkbox" id="voice-actor" name="voice-actor"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get listeners() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
event: "voice-set-usevoice", handler: e => this.useVoice = e.detail
|
||||||
|
}, {
|
||||||
|
event: "voice-set-language", handler: e => this.language = e.detail
|
||||||
|
}, {
|
||||||
|
event: "voice-set-duration", handler: e => this.duration = e.detail
|
||||||
|
}, {
|
||||||
|
event: "voice-set-usesubtitle", handler: e => this.useSubtitle = e.detail
|
||||||
|
}, {
|
||||||
|
event: "voice-set-subtitlelanguage", handler: e => this.subtitleLanguage = e.detail
|
||||||
|
}, {
|
||||||
|
event: "voice-set-subtitleposition", handler: e => this.position = e.detail
|
||||||
|
}, {
|
||||||
|
event: "voice-set-usevoiceactor", handler: e => this.useVoiceActor = e.detail
|
||||||
|
}, {
|
||||||
|
id: "voice", event: "click", handler: e => {
|
||||||
|
showRelatedHTML(e.currentTarget, "voice-realted");
|
||||||
|
this.useVoice = e.currentTarget.checked;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "voice-lang-select", event: "change", handler: e => {
|
||||||
|
this.language = e.currentTarget.value
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "voice-idle-duration-input", event: "change", handler: e => {
|
||||||
|
this.duration = {
|
||||||
|
idle: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "voice-next-duration-input", event: "change", handler: e => {
|
||||||
|
this.duration = {
|
||||||
|
next: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "subtitle", event: "click", handler: e => {
|
||||||
|
showRelatedHTML(e.currentTarget, "subtitle-realted");
|
||||||
|
this.useSubtitle = e.currentTarget.checked;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "subtitle-lang-select", event: "change", handler: e => this.subtitleLanguage = e.currentTarget.value
|
||||||
|
}, {
|
||||||
|
id: "subtitle-padding-x-slider", event: "input", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "subtitle-padding-x-input");
|
||||||
|
this.position = {
|
||||||
|
x: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "subtitle-padding-x-input", event: "change", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "subtitle-padding-x-slider");
|
||||||
|
this.position = {
|
||||||
|
x: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "subtitle-padding-y-slider", event: "input", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "subtitle-padding-y-input");
|
||||||
|
this.position = {
|
||||||
|
y: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "subtitle-padding-y-input", event: "change", handler: e => {
|
||||||
|
syncHTMLValue(e.currentTarget, "subtitle-padding-y-slider");
|
||||||
|
this.position = {
|
||||||
|
y: e.currentTarget.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
id: "voice-actor", event: "click", handler: e => {
|
||||||
|
this.useVoiceActor = e.currentTarget.checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
html {
|
html {
|
||||||
-ms-user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -11,50 +8,15 @@ html {
|
|||||||
body,
|
body,
|
||||||
#app {
|
#app {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background-position: center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: cover;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
touch-action: none;
|
touch-action: none;
|
||||||
-ms-touch-action: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#widget-wrapper {
|
#widget-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.invert-filter {
|
|
||||||
filter: invert(1);
|
|
||||||
opacity: 0.3;
|
|
||||||
}
|
|
||||||
|
|
||||||
#video_background {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
#video_background video {
|
|
||||||
min-width: 100%;
|
|
||||||
min-height: 100%;
|
|
||||||
width: auto;
|
|
||||||
height: auto;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%,-50%);
|
|
||||||
}
|
|
||||||
@@ -1,39 +1,9 @@
|
|||||||
import '@/index.css'
|
import '@/index.css'
|
||||||
import '@/libs/wallpaper_engine'
|
import '@/libs/wallpaper_engine'
|
||||||
import check_web_gl from '@/libs/check_web_gl'
|
import AKLive2D from '@/components/aklive2d'
|
||||||
import Settings from '@/components/settings'
|
|
||||||
import Voice from '@/components/voice'
|
|
||||||
import Music from '@/components/music'
|
|
||||||
|
|
||||||
document.querySelector('#app').innerHTML = `
|
document.getElementById('app').innerHTML = `
|
||||||
<img src="./assets/${import.meta.env.VITE_LOGO_FILENAME}.png" class="logo invert-filter" id="logo" alt="operator logo" />
|
<div id="widget-wrapper" />
|
||||||
<div id="settings" hidden></div>
|
|
||||||
<div id="voice_box" hidden></div>
|
|
||||||
<div id="music_box" hidden></div>
|
|
||||||
<div id="video_background">
|
|
||||||
<video autoplay loop disablepictureinpicture id="video-src" />
|
|
||||||
</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>
|
|
||||||
`
|
`
|
||||||
window.voice = new Voice(document.querySelector('#voice_box'), document.querySelector('#widget-wrapper'))
|
window.aklive2d = new AKLive2D(document.getElementById('app'), document.getElementById('widget-wrapper'))
|
||||||
window.voice.init()
|
window.aklive2d.init()
|
||||||
window.music = new Music(document.querySelector('#music_box'))
|
|
||||||
window.settings = new Settings(document.querySelector('#settings'), document.querySelector('#logo'))
|
|
||||||
document.title = import.meta.env.VITE_TITLE
|
|
||||||
console.log("All resources are extracted from Arknights. Github: https://gura.ch/aklive2d-gh")
|
|
||||||
|
|
||||||
if (check_web_gl()) {
|
|
||||||
import('@/components/player').then(({ default: spinePlayer }) => {
|
|
||||||
window.settings.spinePlayer = spinePlayer(document.querySelector('#player'))
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
import('@/components/fallback').then(({ default: fallback }) => {
|
|
||||||
fallback(document.querySelector('#fallback'))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
export default function check_web_gl() {
|
|
||||||
try {
|
|
||||||
const canvas = document.createElement("canvas");
|
|
||||||
const ctx = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
|
|
||||||
return ctx != null;
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9669,10 +9669,10 @@ var spine;
|
|||||||
var canvas = this.canvas;
|
var canvas = this.canvas;
|
||||||
var w = canvas.clientWidth;
|
var w = canvas.clientWidth;
|
||||||
var h = canvas.clientHeight;
|
var h = canvas.clientHeight;
|
||||||
var devicePixelRatio = window.devicePixelRatio || 1;
|
var devicePixelRatio = () => window.devicePixelRatio || 1;
|
||||||
if (canvas.width != Math.floor(w * devicePixelRatio) || canvas.height != Math.floor(h * devicePixelRatio)) {
|
if (canvas.width != Math.floor(w * devicePixelRatio()) || canvas.height != Math.floor(h * devicePixelRatio())) {
|
||||||
canvas.width = Math.floor(w * devicePixelRatio);
|
canvas.width = Math.floor(w * devicePixelRatio());
|
||||||
canvas.height = Math.floor(h * devicePixelRatio);
|
canvas.height = Math.floor(h * devicePixelRatio());
|
||||||
}
|
}
|
||||||
this.context.gl.viewport(0, 0, canvas.width, canvas.height);
|
this.context.gl.viewport(0, 0, canvas.width, canvas.height);
|
||||||
if (resizeMode === ResizeMode.Stretch) {
|
if (resizeMode === ResizeMode.Stretch) {
|
||||||
@@ -11084,16 +11084,16 @@ var spine;
|
|||||||
config.showControls = true;
|
config.showControls = true;
|
||||||
if (typeof config.defaultMix === "undefined")
|
if (typeof config.defaultMix === "undefined")
|
||||||
config.defaultMix = 0.25;
|
config.defaultMix = 0.25;
|
||||||
config.devicePixelRatio = window.devicePixelRatio || 1;
|
config.devicePixelRatio = () => window.devicePixelRatio || 1;
|
||||||
config.settingsScale = 1;
|
if (typeof config.scale === "undefined")
|
||||||
if (typeof window.settings !== "undefined")
|
config.scale = 1;
|
||||||
config.settingsScale = window.settings.scale;
|
|
||||||
return config;
|
return config;
|
||||||
};
|
};
|
||||||
|
SpinePlayer.prototype.setOperatorScale = function (v) {
|
||||||
|
this.config.scale = v
|
||||||
|
};
|
||||||
SpinePlayer.prototype.getOperatorScale = function () {
|
SpinePlayer.prototype.getOperatorScale = function () {
|
||||||
if (typeof window.settings !== "undefined")
|
return this.config.scale
|
||||||
return window.settings.scale;
|
|
||||||
return this.config.settingsScale
|
|
||||||
};
|
};
|
||||||
SpinePlayer.prototype.showError = function (error) {
|
SpinePlayer.prototype.showError = function (error) {
|
||||||
var errorDom = findWithClass(this.dom, "spine-player-error")[0];
|
var errorDom = findWithClass(this.dom, "spine-player-error")[0];
|
||||||
@@ -11416,7 +11416,7 @@ var spine;
|
|||||||
height: oldViewport.height + (viewport.height - oldViewport.height) * transitionAlpha
|
height: oldViewport.height + (viewport.height - oldViewport.height) * transitionAlpha
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
var devicePixelRatio = this.config.devicePixelRatio;
|
var devicePixelRatio = this.config.devicePixelRatio();
|
||||||
var viewportSize = this.scale(viewport.width, viewport.height, this.canvas.width, this.canvas.height);
|
var viewportSize = this.scale(viewport.width, viewport.height, this.canvas.width, this.canvas.height);
|
||||||
// this.sceneRenderer.camera.zoom = viewport.width * devicePixelRatio / viewportSize.x;
|
// this.sceneRenderer.camera.zoom = viewport.width * devicePixelRatio / viewportSize.x;
|
||||||
|
|
||||||
|
|||||||
@@ -1,133 +1,155 @@
|
|||||||
|
import * as Event from "@/components/event"
|
||||||
|
|
||||||
window.wallpaperPropertyListener = {
|
window.wallpaperPropertyListener = {
|
||||||
applyGeneralProperties: function (properties) {
|
applyGeneralProperties: function (properties) {
|
||||||
if (properties.fps) {
|
if (properties.fps) {
|
||||||
window.settings.setFPS(properties.fps)
|
document.dispatchEvent(Event.PlayerSetFPSEventFn(properties.fps))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
applyUserProperties: function (properties) {
|
applyUserProperties: function (properties) {
|
||||||
if (properties.privacydonottrack) {
|
if (properties.privacydonottrack) {
|
||||||
window.settings.insight(true, !properties.privacydonottrack.value)
|
document.dispatchEvent(Event.InsightRegisterEventFn(!properties.privacydonottrack.value))
|
||||||
}
|
}
|
||||||
if (properties.logo) {
|
if (properties.logo) {
|
||||||
window.settings.setLogoDisplay(!properties.logo.value)
|
document.dispatchEvent(Event.LogoSetHiddenEventFn(!properties.logo.value))
|
||||||
}
|
}
|
||||||
if (properties.logoratio) {
|
if (properties.logoratio) {
|
||||||
if (properties.logoratio.value) {
|
if (properties.logoratio.value) {
|
||||||
window.settings.setLogoRatio(properties.logoratio.value)
|
document.dispatchEvent(Event.LogoSetRatioEventFn(properties.logoratio.value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (properties.logoopacity) {
|
if (properties.logoopacity) {
|
||||||
if (properties.logoopacity.value) {
|
if (properties.logoopacity.value) {
|
||||||
window.settings.setLogoOpacity(properties.logoopacity.value)
|
document.dispatchEvent(Event.LogoSetOpacityEventFn(properties.logoopacity.value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (properties.logoimage) {
|
if (properties.logoimage) {
|
||||||
if (properties.logoimage.value) {
|
if (properties.logoimage.value) {
|
||||||
window.settings.setLogo('file:///' + properties.logoimage.value)
|
document.dispatchEvent(Event.LogoSetImageEventFn('file:///' + properties.logoimage.value))
|
||||||
} else {
|
} else {
|
||||||
window.settings.resetLogoImage()
|
document.dispatchEvent(Event.LogoResetImageEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (properties.logox) {
|
if (properties.logox) {
|
||||||
window.settings.logoPadding("x", properties.logox.value)
|
document.dispatchEvent(Event.LogoSetPositionEventFn({
|
||||||
}
|
x: properties.logox.value
|
||||||
if (properties.logoy) {
|
}))
|
||||||
window.settings.logoPadding("y", properties.logoy.value)
|
}
|
||||||
}
|
if (properties.logoy) {
|
||||||
if (properties.defaultbackground) {
|
document.dispatchEvent(Event.LogoSetPositionEventFn({
|
||||||
if (properties.defaultbackground.value) {
|
y: properties.logoy.value
|
||||||
window.settings.setDefaultBackground(properties.defaultbackground.value)
|
}))
|
||||||
}
|
}
|
||||||
}
|
if (properties.defaultbackground) {
|
||||||
if (properties.background) {
|
if (properties.defaultbackground.value) {
|
||||||
if (properties.background.value) {
|
document.dispatchEvent(Event.BackgroundSetDefaultEventFn(properties.defaultbackground.value))
|
||||||
window.settings.setBackgoundImage(`url('file:///${properties.background.value}')`)
|
}
|
||||||
} else {
|
}
|
||||||
window.settings.resetBackground()
|
if (properties.background) {
|
||||||
}
|
if (properties.background.value) {
|
||||||
}
|
document.dispatchEvent(Event.BackgroundSetCustomEventFn(`file:///${properties.background.value}`))
|
||||||
if (properties.voicetitle) {
|
} else {
|
||||||
window.voice.useVoice = properties.voicetitle.value
|
document.dispatchEvent(Event.BackgroundResetImageEvent)
|
||||||
}
|
}
|
||||||
if (properties.voicelanguage) {
|
}
|
||||||
window.voice.language = properties.voicelanguage.value
|
if (properties.voicetitle) {
|
||||||
}
|
document.dispatchEvent(Event.VoiceSetUseVoiceEventFn(properties.voicetitle.value))
|
||||||
if (properties.voiceidle) {
|
}
|
||||||
window.voice.idleDuration = parseInt(properties.voiceidle.value)
|
if (properties.voicelanguage) {
|
||||||
}
|
document.dispatchEvent(Event.VoiceSetLanguageEventFn(properties.voicelanguage.value))
|
||||||
if (properties.voicenext) {
|
}
|
||||||
window.voice.nextDuration = parseInt(properties.voicenext.value)
|
if (properties.voiceidle) {
|
||||||
}
|
document.dispatchEvent(Event.VoiceSetDurationEventFn({
|
||||||
if (properties.voicesubtitle) {
|
idle: properties.voiceidle.value
|
||||||
window.voice.useSubtitle = properties.voicesubtitle.value
|
}))
|
||||||
}
|
}
|
||||||
if (properties.voicesubtitlelanguage) {
|
if (properties.voicenext) {
|
||||||
window.voice.subtitleLanguage = properties.voicesubtitlelanguage.value
|
document.dispatchEvent(Event.VoiceSetDurationEventFn({
|
||||||
}
|
next: properties.voicenext.value
|
||||||
if (properties.voicesubtitlex) {
|
}))
|
||||||
window.voice.subtitleX = properties.voicesubtitlex.value
|
}
|
||||||
}
|
if (properties.voicesubtitle) {
|
||||||
if (properties.voicesubtitley) {
|
document.dispatchEvent(Event.VoiceSetUseSubtitleEventFn(properties.voicesubtitle.value))
|
||||||
window.voice.subtitleY = properties.voicesubtitley.value
|
}
|
||||||
}
|
if (properties.voicesubtitlelanguage) {
|
||||||
if (properties.voiceactor) {
|
document.dispatchEvent(Event.VoiceSetSubtitleLanguageEventFn(properties.voicesubtitlelanguage.value))
|
||||||
window.voice.useVoiceActor = properties.voiceactor.value
|
}
|
||||||
}
|
if (properties.voicesubtitlex) {
|
||||||
if (properties.music_selection) {
|
document.dispatchEvent(Event.VoiceSetSubtitlePositionEventFn({
|
||||||
window.music.changeMusic(properties.music_selection.value)
|
x: properties.voicesubtitlex.value
|
||||||
}
|
}))
|
||||||
if (properties.music_title) {
|
}
|
||||||
window.music.useMusic = properties.music_title.value
|
if (properties.voicesubtitley) {
|
||||||
}
|
document.dispatchEvent(Event.VoiceSetSubtitlePositionEventFn({
|
||||||
if (properties.music_volume) {
|
y: properties.voicesubtitley.value
|
||||||
window.music.volume = properties.music_volume.value
|
}))
|
||||||
}
|
}
|
||||||
if (properties.custom_music) {
|
if (properties.voiceactor) {
|
||||||
if (properties.custom_music.value) {
|
document.dispatchEvent(Event.VoiceSetUseVoiceActorEventFn(properties.voiceactor.value))
|
||||||
window.settings.setMusicFromWE(`file:///${properties.custom_music.value}`)
|
}
|
||||||
} else {
|
if (properties.music_selection) {
|
||||||
window.settings.resetMusic()
|
document.dispatchEvent(Event.MusicSetMusicEventFn(properties.music_selection.value))
|
||||||
}
|
}
|
||||||
}
|
if (properties.music_title) {
|
||||||
if (properties.custom_video) {
|
document.dispatchEvent(Event.MusicSetUseMusicEventFn(properties.music_title.value))
|
||||||
if (properties.custom_video.value) {
|
}
|
||||||
window.settings.setVideoFromWE(`file:///${properties.custom_video.value}`)
|
if (properties.music_volume) {
|
||||||
} else {
|
document.dispatchEvent(Event.MusicSetVolumeEventFn(properties.music_volume.value))
|
||||||
window.settings.resetVideo()
|
}
|
||||||
}
|
if (properties.custom_music) {
|
||||||
}
|
if (properties.custom_music.value) {
|
||||||
if (properties.video_volume) {
|
document.dispatchEvent(Event.MusicSetCustomEventFn(`file:///${properties.custom_music.value}`))
|
||||||
window.settings.setVideoVolume(properties.video_volume.value)
|
} else {
|
||||||
}
|
document.dispatchEvent(Event.MusicResetEvent)
|
||||||
if (properties.scale) {
|
}
|
||||||
window.settings.setScale(properties.scale.value)
|
}
|
||||||
}
|
if (properties.custom_video) {
|
||||||
if (properties.position) {
|
if (properties.custom_video.value) {
|
||||||
if (!properties.position.value) {
|
document.dispatchEvent(Event.BackgroundSetVideoEventFn(`file:///${properties.custom_video.value}`))
|
||||||
window.settings.positionReset()
|
} else {
|
||||||
} else {
|
document.dispatchEvent(Event.BackgroundResetVideoEvent)
|
||||||
window.settings.positionPadding(null, {
|
}
|
||||||
left: properties.paddingleft.value,
|
}
|
||||||
right: properties.paddingright.value,
|
if (properties.video_volume) {
|
||||||
top: properties.paddingtop.value,
|
document.dispatchEvent(Event.BackgroundSetVolumeEventFn(properties.video_volume.value))
|
||||||
bottom: properties.paddingbottom.value,
|
}
|
||||||
})
|
if (properties.scale) {
|
||||||
}
|
document.dispatchEvent(Event.PlayerSetScaleEventFn(properties.scale.value))
|
||||||
}
|
}
|
||||||
if (properties.paddingleft) {
|
if (properties.position) {
|
||||||
window.settings.positionPadding("left", properties.paddingleft.value)
|
if (!properties.position.value) {
|
||||||
}
|
document.dispatchEvent(Event.PlayerResetPaddingEvent)
|
||||||
if (properties.paddingright) {
|
} else {
|
||||||
window.settings.positionPadding("right", properties.paddingright.value)
|
document.dispatchEvent(Event.PlayerSetPaddingEventFn({
|
||||||
}
|
left: properties.paddingleft.value,
|
||||||
if (properties.paddingtop) {
|
right: properties.paddingright.value,
|
||||||
window.settings.positionPadding("top", properties.paddingtop.value)
|
top: properties.paddingtop.value,
|
||||||
}
|
bottom: properties.paddingbottom.value,
|
||||||
if (properties.paddingbottom) {
|
}))
|
||||||
window.settings.positionPadding("bottom", properties.paddingbottom.value)
|
}
|
||||||
}
|
}
|
||||||
if (properties.useStartAnimation) {
|
if (properties.paddingleft) {
|
||||||
window.settings.useStartAnimation = properties.useStartAnimation.value
|
document.dispatchEvent(Event.PlayerSetPaddingEventFn({
|
||||||
}
|
left: properties.paddingleft.value,
|
||||||
},
|
}))
|
||||||
|
}
|
||||||
|
if (properties.paddingright) {
|
||||||
|
document.dispatchEvent(Event.PlayerSetPaddingEventFn({
|
||||||
|
right: properties.paddingright.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
if (properties.paddingtop) {
|
||||||
|
document.dispatchEvent(Event.PlayerSetPaddingEventFn({
|
||||||
|
top: properties.paddingtop.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
if (properties.paddingbottom) {
|
||||||
|
document.dispatchEvent(Event.PlayerSetPaddingEventFn({
|
||||||
|
bottom: properties.paddingbottom.value,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
if (properties.useStartAnimation) {
|
||||||
|
document.dispatchEvent(Event.PlayerSetUseStartAnimationEventFn(properties.useStartAnimation.value))
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user