taiko_web/plugins/userscripts/plugins-in-old-taiko-web.us...

1734 lines
50 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ==UserScript==
// @name Plugins in Old Taiko Web
// @namespace plugins-in-old-taiko-web
// @icon https://gitlab.com/uploads/-/system/project/avatar/36006078/taiko-web-plugins.png?width=64
// @version 2023.1.20
// @author Katie Frogs
// @description Implements the plugin interface in older versions of taiko-web
// @homepage https://github.com/KatieFrogs/taiko-web-plugins
// @supportURL https://github.com/KatieFrogs/taiko-web-plugins/issues
// @match https://*.lv5.ac/
// @grant none
// @run-at document-start
// ==/UserScript==
var pluginsTranslations = {
title: {
ja: "プラグイン",
en: "Plugins",
ko: "플러그인"
},
unloadAll: {
ja: "すべて無効にする",
en: "Unload All",
ko: "모두 해제"
},
warning: {
ja: "%sを読み込もうとしています。プラグインは信頼できる場合のみ読み込むようにしてください。続行しますか",
en: "You are about to load %s. Plugins should only be loaded if you trust them. Continue?",
ko: "%s을 로드하려고 합니다. 신뢰할 수 있는 플러그인만 로드하시기 바랍니다. 계속할까요?"
},
plugin: {
ja: {
one: "%sつのプラグイン",
other: "%sつのプラグイン"
},
en: {
one: "%s plugin",
other: "%s plugins"
},
ko: {
one: "%s 플러그인",
other: "%s 플러그인들"
}
},
author: {
ja: "作成者:%s",
en: "By %s",
ko: "제작자:%s"
},
version: {
ja: "Ver. %s",
en: "Version %s",
ko: "버전 %s"
},
browse: {
ja: "参照する…",
en: "Browse...",
cn: "浏览…",
tw: "開啟檔案…",
ko: "찾아보기…"
},
noPlugins: {
ja: null,
en: "No .taikoweb.js plugin files have been found in the provided file list.",
ko: "주어진 파일 리스트에서 .taikoweb.js 플러그인 파일들을 발견할 수 없습니다."
}
}
var pluginsStrings = {}
var languageList = ["ja", "en", "cn", "tw", "ko"]
function separateStrings(){
for(var j in languageList){
var lang = languageList[j]
pluginsStrings[lang] = {
id: lang
}
var str = pluginsStrings[lang]
var translateObj = function(obj, name, str){
if("en" in obj){
for(var i in obj){
str[name] = obj[lang] || obj.en
}
}else if(obj){
str[name] = {}
for(var i in obj){
translateObj(obj[i], i, str[name])
}
}
}
for(var i in pluginsTranslations){
translateObj(pluginsTranslations[i], i, str)
}
}
}
separateStrings()
function pluginsStr(lang){
if(!lang){
lang = strings.id
}
return pluginsStrings[lang] || allStrings[lang].plugins || pluginsStrings.en
}
class Plugins{
constructor(...args){
this.init(...args)
}
init(){
this.allPlugins = []
this.pluginMap = {}
this.hashes = []
this.startOrder = []
}
add(script, options){
options = options || {}
var hash = md5.base64(script.toString())
var isUrl = typeof script === "string" && !options.raw
if(isUrl){
hash = "url " + hash
}else if(typeof script !== "string"){
hash = "class " + hash
}
var name = options.name
if(!name && isUrl){
name = script
var index = name.lastIndexOf("?")
if(index !== -1){
name = name.slice(0, index)
}
var index = name.lastIndexOf("/")
if(index !== -1){
name = name.slice(index + 1)
}
if(name.endsWith(".taikoweb.js")){
name = name.slice(0, -".taikoweb.js".length)
}else if(name.endsWith(".js")){
name = name.slice(0, -".js".length)
}
}
name = name || "plugin"
if(this.hashes.indexOf(hash) !== -1){
console.warn("Skip adding an already addded plugin: " + name)
return
}
var baseName = name
for(var i = 2; name in this.pluginMap; i++){
name = baseName + i.toString()
}
var plugin = new PluginLoader(script, name, hash, options.raw)
plugin.hide = !!options.hide
this.allPlugins.push({
name: name,
plugin: plugin
})
this.pluginMap[name] = plugin
this.hashes.push(hash)
return plugin
}
remove(name){
if(name in this.pluginMap){
var hash = this.pluginMap[name].hash
if(hash){
var index = this.hashes.indexOf(hash)
if(index !== -1){
this.hashes.splice(index, 1)
}
}
this.unload(name)
}
var index = this.allPlugins.findIndex(obj => obj.name === name)
if(index !== -1){
this.allPlugins.splice(index, 1)
}
var index = this.startOrder.indexOf(name)
if(index !== -1){
this.startOrder.splice(index, 1)
}
delete this.pluginMap[name]
}
load(name){
return this.pluginMap[name].load()
}
loadAll(){
for(var i = 0; i < this.allPlugins.length; i++){
this.allPlugins[i].plugin.load()
}
}
start(name){
return this.pluginMap[name].start()
}
startAll(){
for(var i = 0; i < this.allPlugins.length; i++){
this.allPlugins[i].plugin.start()
}
}
stop(name){
return this.pluginMap[name].stop()
}
stopAll(){
for(var i = this.startOrder.length; i--;){
this.pluginMap[this.startOrder[i]].stop()
}
}
unload(name){
return this.pluginMap[name].unload()
}
unloadAll(){
for(var i = this.startOrder.length; i--;){
this.pluginMap[this.startOrder[i]].unload()
}
for(var i = this.allPlugins.length; i--;){
this.allPlugins[i].plugin.unload()
}
}
unloadImported(){
for(var i = this.startOrder.length; i--;){
var plugin = this.pluginMap[this.startOrder[i]]
if(plugin.imported){
plugin.unload()
}
}
for(var i = this.allPlugins.length; i--;){
var obj = this.allPlugins[i]
if(obj.plugin.imported){
obj.plugin.unload()
}
}
}
strFromFunc(func){
var output = func.toString()
return output.slice(output.indexOf("{") + 1, output.lastIndexOf("}"))
}
argsFromFunc(func){
var output = func.toString()
output = output.slice(0, output.indexOf("{"))
output = output.slice(output.indexOf("(") + 1, output.lastIndexOf(")"))
return output.split(",").map(str => str.trim()).filter(Boolean)
}
insertBefore(input, insertedText, searchString){
var index = input.indexOf(searchString)
if(index === -1){
throw new Error("searchString not found: " + searchString)
}
return input.slice(0, index) + insertedText + input.slice(index)
}
insertAfter(input, searchString, insertedText){
var index = input.indexOf(searchString)
if(index === -1){
throw new Error("searchString not found: " + searchString)
}
var length = searchString.length
return input.slice(0, index + length) + insertedText + input.slice(index + length)
}
strReplace(input, searchString, insertedText, repeat=1){
var position = 0
for(var i = 0; i < repeat; i++){
var index = input.indexOf(searchString, position)
if(index === -1){
if(repeat === Infinity){
break
}else{
throw new Error("searchString not found: " + searchString)
}
}
input = input.slice(0, index) + insertedText + input.slice(index + searchString.length)
position = index + insertedText.length
}
return input
}
isObject(input){
return input && typeof input === "object" && input.constructor === Object
}
deepMerge(target, ...sources){
sources.forEach(source => {
if(this.isObject(target) && this.isObject(source)){
for(var i in source){
if(this.isObject(source[i])){
if(!target[i]){
target[i] = {}
}
this.deepMerge(target[i], source[i])
}else if(source[i]){
target[i] = source[i]
}
}
}
})
return target
}
arrayDel(array, item){
var index = array.indexOf(item)
if(index !== -1){
array.splice(index, 1)
return true
}
return false
}
hasSettings(){
for(var i = 0; i < this.allPlugins.length; i++){
var plugin = this.allPlugins[i].plugin
if(plugin.loaded && (!plugin.hide || plugin.settings())){
return true
}
}
return false
}
getSettings(){
var items = []
for(var i = 0; i < this.allPlugins.length; i++){
var obj = this.allPlugins[i]
let plugin = obj.plugin
if(!plugin.loaded){
continue
}
if(!plugin.hide){
let description
let description_lang
var module = plugin.module
if(module){
description = [
module.description,
module.author ? pluginsStr().author.replace("%s", module.author) : null,
module.version ? pluginsStr().version.replace("%s", module.version) : null
].filter(Boolean).join("\n")
description_lang = {}
languageList.forEach(lang => {
description_lang[lang] = [
this.getLocalTitle(module.description, module.description_lang, lang),
module.author ? pluginsStr(lang).author.replace("%s", module.author) : null,
module.version ? pluginsStr(lang).version.replace("%s", module.version) : null
].filter(Boolean).join("\n")
})
}
var name = module && module.name || obj.name
var name_lang = module && module.name_lang
items.push({
name: name,
name_lang: name_lang,
description: description,
description_lang: description_lang,
type: "toggle",
default: true,
getItem: () => plugin.started,
setItem: value => {
if(plugin.name in this.pluginMap){
if(plugin.started && !value){
this.stop(plugin.name)
}else if(!plugin.started && value){
this.start(plugin.name)
}
}
}
})
}
var settings = plugin.settings()
if(settings){
settings.forEach(setting => {
if(!setting.name){
setting.name = name
if(!setting.name_lang){
setting.name_lang = name_lang
}
}
if(typeof setting.getItem !== "function"){
setting.getItem = () => {}
}
if(typeof setting.setItem !== "function"){
setting.setItem = () => {}
}
if(!("indent" in setting) && !plugin.hide){
setting.indent = 1
}
items.push(setting)
})
}
}
return items
}
getLocalTitle(title, titleLang, lang){
if(titleLang){
for(var id in titleLang){
if(id === (lang || strings.id) && titleLang[id]){
return titleLang[id]
}
}
}
return title
}
}
class PluginLoader{
constructor(...args){
this.init(...args)
}
init(script, name, hash, raw){
this.name = name
this.hash = hash
if(typeof script === "string"){
if(raw){
this.url = URL.createObjectURL(new Blob([script], {
type: "application/javascript"
}))
}else{
this.url = script
}
}else{
this.class = script
}
}
load(loadErrors){
if(this.loaded){
return Promise.resolve()
}else if(!this.url && !this.class){
if(loadErrors){
return Promise.reject()
}else{
return Promise.resolve()
}
}else{
return (this.url ? import(this.url) : Promise.resolve({
default: this.class
})).then(module => {
if(this.url){
URL.revokeObjectURL(this.url)
delete this.url
}else{
delete this.class
}
this.loaded = true
try{
this.module = new module.default()
}catch(e){
this.error()
var error = new Error()
error.stack = "Error initializing plugin: " + this.name + "\n" + e.stack
if(loadErrors){
return Promise.reject(error)
}else{
console.error(error)
return Promise.resolve()
}
}
var output
try{
if(this.module.beforeLoad){
this.module.beforeLoad(this)
}
if(this.module.load){
output = this.module.load(this)
}
}catch(e){
this.error()
var error = new Error()
error.stack = "Error in plugin load: " + this.name + "\n" + e.stack
if(loadErrors){
return Promise.reject(error)
}else{
console.error(error)
return Promise.resolve()
}
}
if(typeof output === "object" && output.constructor === Promise){
return output.catch(e => {
this.error()
var error = new Error()
error.stack = "Error in plugin load promise: " + this.name + (e ? "\n" + e.stack : "")
if(loadErrors){
return Promise.reject(error)
}else{
console.error(error)
return Promise.resolve()
}
})
}
}, e => {
this.error()
plugins.remove(this.name)
if(e.name === "SyntaxError"){
var error = new SyntaxError()
error.stack = "Error in plugin syntax: " + this.name + "\n" + e.stack
}else{
var error = e
}
if(loadErrors){
return Promise.reject(error)
}else{
console.error(error)
return Promise.resolve()
}
})
}
}
start(orderChange, startErrors){
if(!orderChange){
plugins.startOrder.push(this.name)
}
return this.load().then(() => {
if(!this.started && this.module){
this.started = true
try{
if(this.module.beforeStart){
this.module.beforeStart()
}
if(this.module.start){
this.module.start()
}
}catch(e){
this.error()
var error = new Error()
error.stack = "Error in plugin start: " + this.name + "\n" + e.stack
if(startErrors){
return Promise.reject(error)
}else{
console.error(error)
return Promise.resolve()
}
}
}
})
}
stop(orderChange, noError){
if(this.loaded && this.started){
if(!orderChange){
var stopIndex = plugins.startOrder.indexOf(this.name)
if(stopIndex !== -1){
plugins.startOrder.splice(stopIndex, 1)
for(var i = plugins.startOrder.length; i-- > stopIndex;){
plugins.pluginMap[plugins.startOrder[i]].stop(true)
}
}
}
this.started = false
try{
if(this.module.beforeStop){
this.module.beforeStop()
}
if(this.module.stop){
this.module.stop()
}
}catch(e){
var error = new Error()
error.stack = "Error in plugin stop: " + this.name + "\n" + e.stack
console.error(error)
if(!noError){
this.error()
}
}
if(!orderChange && stopIndex !== -1){
for(var i = stopIndex; i < plugins.startOrder.length; i++){
plugins.pluginMap[plugins.startOrder[i]].start(true)
}
}
}
}
unload(error){
if(this.loaded){
if(this.started){
this.stop(false, error)
}
this.loaded = false
plugins.remove(this.name)
if(this.module){
try{
if(this.module.beforeUnload){
this.module.beforeUnload()
}
if(this.module.unload){
this.module.unload()
}
}catch(e){
var error = new Error()
error.stack = "Error in plugin unload: " + this.name + "\n" + e.stack
console.error(error)
}
delete this.module
}
}
}
error(){
if(this.module && this.module.error){
try{
this.module.error()
}catch(e){
var error = new Error()
error.stack = "Error in plugin error: " + this.name + "\n" + e.stack
console.error(error)
}
}
this.unload(true)
}
settings(){
if(this.module && this.module.settings){
try{
var settings = this.module.settings()
}catch(e){
console.error(e)
this.error()
return
}
if(Array.isArray(settings)){
return settings
}
}
}
}
class EditValue{
constructor(...args){
this.init(...args)
}
init(parent, name){
if(name){
if(!parent){
throw new Error("Parent is not defined")
}
this.name = [parent, name]
this.delete = !(name in parent)
}else{
this.original = parent
}
}
load(callback){
this.loadCallback = callback
return this
}
start(){
if(this.name){
this.original = this.name[0][this.name[1]]
}
try{
var output = this.loadCallback(this.original)
}catch(e){
console.error(this.loadCallback)
var error = new Error()
error.stack = "Error editing the value of " + this.getName() + "\n" + e.stack
throw error
}
if(typeof output === "undefined"){
console.error(this.loadCallback)
throw new Error("Error editing the value of " + this.getName() + ": A value is expected to be returned")
}
if(this.name){
this.name[0][this.name[1]] = output
}
return output
}
stop(){
if(this.name){
if(this.delete){
delete this.name[0][this.name[1]]
}else{
this.name[0][this.name[1]] = this.original
}
}
return this.original
}
getName(){
var name = "unknown"
try{
if(this.name){
var name = (
typeof this.name[0] === "function" && this.name[0].name
|| (
typeof this.name[0] === "object" && typeof this.name[0].constructor === "function" && (
this.name[0] instanceof this.name[0].constructor ? (() => {
var consName = this.name[0].constructor.name || ""
return consName.slice(0, 1).toLowerCase() + consName.slice(1)
})() : this.name[0].constructor.name + ".prototype"
)
) || name
) + (this.name[1] ? "." + this.name[1] : "")
}
}catch(e){
name = "error"
}
return name
}
unload(){
delete this.name
delete this.original
delete this.loadCallback
}
}
class EditFunction extends EditValue{
start(){
if(this.name){
this.original = this.name[0][this.name[1]]
}
if(typeof this.original !== "function"){
console.error(this.loadCallback)
var error = new Error()
error.stack = "Error editing the function value of " + this.getName() + ": Original value is not a function"
throw error
}
var args = plugins.argsFromFunc(this.original)
try{
var output = this.loadCallback(plugins.strFromFunc(this.original), args)
}catch(e){
console.error(this.loadCallback)
var error = new Error()
error.stack = "Error editing the function value of " + this.getName() + "\n" + e.stack
throw error
}
if(typeof output === "undefined"){
console.error(this.loadCallback)
throw new Error("Error editing the function value of " + this.getName() + ": A value is expected to be returned")
}
try{
var output = Function(...args, output)
}catch(e){
console.error(this.loadCallback)
var error = new SyntaxError()
var blob = new Blob([output], {
type: "application/javascript"
})
var url = URL.createObjectURL(blob)
error.stack = "Error editing the function value of " + this.getName() + ": Could not evaluate string, check the full string for errors: " + url + "\n" + e.stack
setTimeout(() => {
URL.revokeObjectURL(url)
}, 5 * 60 * 1000)
throw error
}
if(this.name){
this.name[0][this.name[1]] = output
}
return output
}
}
class Patch{
constructor(...args){
this.init(...args)
}
init(){
this.edits = []
this.addedLanguages = []
}
addEdits(...args){
args.forEach(arg => this.edits.push(arg))
}
addLanguage(lang, forceSet, fallback="en"){
if(fallback){
lang = plugins.deepMerge({}, allStrings[fallback], lang)
}
this.addedLanguages.push({
lang: lang,
forceSet: forceSet
})
}
beforeStart(){
this.edits.forEach(edit => edit.start())
this.addedLanguages.forEach(obj => {
settings.addLang(obj.lang, obj.forceSet)
})
}
beforeStop(){
for(var i = this.edits.length; i--;){
this.edits[i].stop()
}
for(var i = this.addedLanguages.length; i--;){
settings.removeLang(this.addedLanguages[i].lang)
}
}
beforeUnload(){
this.edits.forEach(edit => edit.unload())
}
log(...args){
var name = this.name || "Plugin"
console.log(
"%c[" + name + "]",
"font-weight: bold;",
...args
)
}
}
function readFile(file, arrayBuffer, encoding){
var reader = new FileReader()
var promise = pageEvents.load(reader).then(event => event.target.result)
reader[arrayBuffer ? "readAsArrayBuffer" : "readAsText"](file, encoding)
return promise
}
class RemoteFile{
constructor(...args){
this.init(...args)
}
init(url){
this.url = url
try{
this.path = new URL(url).pathname
}catch(e){
this.path = url
}
if(this.path.startsWith("/")){
this.path = this.path.slice(1)
}
if(this.url.startsWith("data:")){
this.name = "datauri"
if(this.url.startsWith("data:audio/ogg")){
this.name += ".ogg"
}
}else{
this.name = this.path
var index = this.name.lastIndexOf("/")
if(index !== -1){
this.name = this.name.slice(index + 1)
}
}
}
arrayBuffer(){
return loader.ajax(this.url, request => {
request.responseType = "arraybuffer"
})
}
read(encoding){
if(encoding){
return this.blob().then(blob => readFile(blob, false, encoding))
}else{
return loader.ajax(this.url)
}
}
blob(){
return loader.ajax(this.url, request => {
request.responseType = "blob"
})
}
}
class LocalFile{
constructor(...args){
this.init(...args)
}
init(file, path){
this.file = file
this.path = path || file.webkitRelativePath || file.name
this.webkitRelativePath = this.path
this.url = this.path
this.name = file.name
}
arrayBuffer(){
return readFile(this.file, true)
}
read(encoding){
return readFile(this.file, false, encoding)
}
blob(){
return Promise.resolve(this.file)
}
}
class CustomSongs2{
constructor(...args){
this.init(...args)
}
init(touchEnabled, noPage){
this.loaderDiv = document.createElement("div")
this.loaderDiv.innerHTML = assets.pages["loadsong"]
var loadingText = this.loaderDiv.querySelector("#loading-text")
this.setAltText(loadingText, strings.loading)
this.locked = false
this.mode = "main"
}
setAltText(element, text){
element.innerText = text
element.setAttribute("alt", text)
}
importLocal(files){
if(!files.length){
return Promise.reject("cancel")
}
this.locked = true
this.loading(true)
var importSongs = new ImportSongs()
return importSongs.load(files).then(this.songsLoaded.bind(this), e => {
this.locked = false
this.loading(false)
if(e === "nosongs"){
this.showError(strings.customSongs.noSongs, "nosongs")
}else if(e !== "cancel"){
return Promise.reject(e)
}
return false
})
}
loading(show){
if(show){
loader.screen.appendChild(this.loaderDiv)
}else if(this.loaderDiv.parentNode){
this.loaderDiv.parentNode.removeChild(this.loaderDiv)
}
}
songsLoaded(songs){
if(songs){
var length = songs.length
assets.songs = songs
assets.customSongs = true
assets.customSelected = +localStorage.getItem("customSelected")
}
pageEvents.send("import-songs", length)
this.clean()
return songs && songs.length
}
showError(text, errorName){
this.locked = false
this.loading(false)
var error = new Error(text)
error.name = errorName
throw error
}
hideError(confirm){
if(this.mode !== "error"){
return
}
this.mode = "main"
this.errorDiv.style.display = ""
assets.sounds[confirm ? "se_don" : "se_cancel"].play()
}
clean(){
delete this.loaderDiv
}
}
class Search{
onClick(){
var songId = parseInt(songEl.dataset.songId)
}
keyPress(){
this.proceed(parseInt(this.results[this.active].dataset.songId))
}
}
class PluginsInOld extends Patch{
name = "Plugins in Old Taiko Web"
load(){
this.style = document.createElement("style")
this.style.appendChild(document.createTextNode(`
.plugin-browse-button{
position: relative;
overflow: hidden;
}
#plugin-browse{
position: absolute;
font-size: inherit;
top: -0.1em;
left: -0.1em;
right: -0.1em;
bottom: -0.1em;
border-radius: 0.5em;
opacity: 0;
cursor: pointer;
}
#plugin-browse::-webkit-file-upload-button{
cursor: pointer;
}
.setting-value{
position: relative;
}`))
this.addEdits(
new EditValue(allStrings.ja, "intl").load(() => "ja"),
new EditValue(allStrings.en, "intl").load(() => "en-GB"),
new EditValue(allStrings.cn, "intl").load(() => "zh-Hans"),
new EditValue(allStrings.tw, "intl").load(() => "zh-Hant"),
new EditValue(allStrings.ko, "intl").load(() => "ko"),
new EditValue(strings, "plural").load(() => new Intl.PluralRules(strings.intl)),
new EditFunction(settings, "setLang").load(str => {
return plugins.insertBefore(str,
`strings.plural = new Intl.PluralRules(lang.intl)
`, 'if(!noEvent){')
}),
new EditValue(settings, "addLang").load(() => this.addLang),
new EditValue(settings, "removeLang").load(() => this.removeLang),
new EditValue(SettingsView.prototype, "pluginsStr").load(() => pluginsStr),
new EditFunction(SettingsView.prototype, "init").load((str, args) => {
args.push("settingsItems", "noSoundStart")
str = plugins.insertAfter(str, 'this.songId = songId', `
this.customSettings = !!settingsItems
this.settingsItems = settingsItems || settings.items
this.locked = false`)
str = plugins.insertBefore(str,
`if(!noSoundStart)
`, 'assets.sounds["bgm_settings"].playLoop')
str = plugins.insertBefore(str,
`if(this.customSettings){
pageEvents.add(window, "language-change", event => this.setLang(), this.windowSymbol)
}
`, 'var gamepadEnabled = false')
str = plugins.strReplace(str, 'for(let i in settings.items){\n\t\t\tvar current = settings.items[i]',
`for(let i in this.settingsItems){
var current = this.settingsItems[i]`)
str = plugins.insertAfter(str, 'settingBox.classList.add("setting-box")', `
if(current.indent){
settingBox.style.marginLeft = (2 * current.indent || 0).toString() + "em"
}`)
str = plugins.strReplace(str, 'var name = strings.settings[i].name\n\t\t\tthis.setAltText(nameDiv, name)',
`if(current.name || current.name_lang){
var name = this.getLocalTitle(current.name, current.name_lang)
}else{
var name = strings.settings[i].name
}
this.setAltText(nameDiv, name)
if(current.description || current.description_lang){
settingBox.title = this.getLocalTitle(current.description, current.description_lang) || ""
}`)
str = plugins.strReplace(str, 'this.getValue(i, valueDiv)',
`let outputObject = {
id: i,
settingBox: settingBox,
nameDiv: nameDiv,
valueDiv: valueDiv,
name: current.name,
name_lang: current.name_lang,
description: current.description,
description_lang: current.description_lang
}
if(current.type === "number"){
["min", "max", "fixedPoint", "step", "sign", "format", "format_lang"].forEach(opt => {
if(opt in current){
outputObject[opt] = current[opt]
}
})
outputObject.valueText = document.createTextNode("")
valueDiv.appendChild(outputObject.valueText)
var buttons = document.createElement("div")
buttons.classList.add("latency-buttons")
buttons.title = ""
var buttonMinus = document.createElement("span")
buttonMinus.innerText = "-"
buttons.appendChild(buttonMinus)
this.addTouchRepeat(buttonMinus, event => {
this.numberAdjust(outputObject, -1)
})
var buttonPlus = document.createElement("span")
buttonPlus.innerText = "+"
buttons.appendChild(buttonPlus)
this.addTouchRepeat(buttonPlus, event => {
this.numberAdjust(outputObject, 1)
})
valueDiv.appendChild(buttons)
this.addTouch(settingBox, event => {
if(event.target.tagName !== "SPAN"){
this.setValue(i)
}
}, true)
}else{
this.addTouchEnd(settingBox, event => this.setValue(i))
}`)
str = plugins.strReplace(str, 'this.addTouchEnd(settingBox, event => this.setValue(i))\n\t\t\tthis.items.push({\n\t\t\t\tid: i,\n\t\t\t\tsettingBox: settingBox,\n\t\t\t\tnameDiv: nameDiv,\n\t\t\t\tvalueDiv: valueDiv\n\t\t\t})\n\t\t}\n\t\tthis.items.push({\n\t\t\tid: "default",\n\t\t\tsettingBox: this.defaultButton\n\t\t})\n\t\tthis.addTouch(this.defaultButton, this.defaultSettings.bind(this))',
` this.items.push(outputObject)
this.getValue(i, valueDiv)
}
var selectBack = this.items.length === 0
if(this.customSettings){
var form = document.createElement("form")
this.browse = document.createElement("input")
this.browse.id = "plugin-browse"
this.browse.type = "file"
this.browse.multiple = true
this.browse.accept = ".taikoweb.js"
pageEvents.add(this.browse, "change", this.browseChange.bind(this))
form.appendChild(this.browse)
this.browseButton = document.createElement("div")
this.browseButton.classList.add("taibtn", "stroke-sub", "plugin-browse-button")
this.browseText = document.createTextNode("")
this.browseButton.appendChild(this.browseText)
this.browseButton.appendChild(form)
this.defaultButton.parentNode.insertBefore(this.browseButton, this.defaultButton)
this.items.push({
id: "browse",
settingBox: this.browseButton
})
}
this.showDefault = !this.customSettings || plugins.allPlugins.filter(obj => obj.plugin.imported).length
if(this.showDefault){
this.items.push({
id: "default",
settingBox: this.defaultButton
})
this.addTouch(this.defaultButton, this.defaultSettings.bind(this))
}else{
this.defaultButton.parentNode.removeChild(this.defaultButton)
}`)
str = plugins.insertAfter(str, 'this.addTouch(this.endButton, this.onEnd.bind(this))', `
if(selectBack){
this.selected = this.items.length - 1
this.endButton.classList.add("selected")
}
if(!this.customSettings){`)
str = plugins.strReplace(str, 'this.latencySetValue(current, event.type === "touchstart")', `this.latencySetValue(current, event.type === "touchend")`)
str = plugins.insertBefore(str, `, true`, ')\n\t\t\tif(current !== "calibration"){')
str = plugins.insertBefore(str,
`}
`, 'this.setStrings()')
return plugins.strReplace(str, 'pageEvents.send("settings")',
`if(this.customSettings){
pageEvents.send("plugins")
}else{
pageEvents.send("settings")
}`)
}),
new EditFunction(SettingsView.prototype, "addTouch").load(str => {
return plugins.insertBefore(str,
`if(event.cancelable)
`, 'event.preventDefault()')
}),
new EditFunction(SettingsView.prototype, "getValue").load(str => {
str = plugins.strReplace(str,
'var current = settings.items[name]\n\t\tvar value = settings.getItem(name)',
`if(!this.items){
return
}
var current = this.settingsItems[name]
if(current.getItem){
var value = current.getItem()
}else{
var value = settings.getItem(name)
}`)
str = plugins.strReplace(str,
'value = strings.settings[name][value]',
`if(current.options_lang && current.options_lang[value]){
value = this.getLocalTitle(value, current.options_lang[value])
}else if(!current.getItem){
value = strings.settings[name][value]
}`)
str = plugins.insertBefore(str,
`else if(current.type === "number"){
var mul = Math.pow(10, current.fixedPoint || 0)
this.items[name].value = value * mul
value = Intl.NumberFormat(strings.intl, current.sign ? {
signDisplay: "always"
} : undefined).format(value)
if(current.format || current.format_lang){
value = this.getLocalTitle(current.format, current.format_lang).replace("%s", value)
}
this.items[name].valueText.data = value
return
}
`, 'valueDiv.innerText = value')
return str
}),
new EditFunction(SettingsView.prototype, "setValue").load(str => {
str = plugins.strReplace(str,
'var current = settings.items[name]\n\t\tvar value = settings.getItem(name)',
`if(this.locked){
return
}
var promise
var current = this.settingsItems[name]
if(current.getItem){
var value = current.getItem()
}else{
var value = settings.getItem(name)
}`)
str = plugins.insertBefore(str,
`if(this.mode === "number"){
return this.numberBack(this.items[this.selected])
}
`, 'if(this.selected === selectedIndex){')
str = plugins.strReplace(str, 'settings.setItem(name, value)',
`else if(current.type === "number"){
this.mode = "number"
selected.settingBox.style.animation = "none"
selected.valueDiv.classList.add("selected")
this.playSound("se_don")
return
}
if(current.setItem){
promise = current.setItem(value)
}else{
settings.setItem(name, value)
}
(promise || Promise.resolve()).then(() => {`)
return plugins.insertAfter(str, 'this.setLang(allStrings[value])\n\t\t}', `
})`)
}),
new EditFunction(SettingsView.prototype, "keyPressed").load(str => {
str = plugins.insertBefore(str,
`if(this.locked){
return
}
`, 'if(pressed){')
str = plugins.insertAfter(str, 'this.defaultSettings()', `
}else if(selected.id === "browse"){
if(event){
this.playSound("se_don")
this.browse.click()
}`)
str = plugins.strReplace(str,
'}while(this.items[this.selected].id === "default" && name !== "left")',
`}while((this.items[this.selected].id === "default" || this.items[this.selected].id === "browse") && name !== "left")`)
return plugins.insertAfter(str,
'this.latencySetAdjust(latencySelected, (name === "up" || name === "right") ? 1 : -1)', `
if(event){
event.preventDefault()
}
}
}else if(this.mode === "number"){
if(name === "confirm" || name === "back"){
this.numberBack(selected)
this.playSound(name === "confirm" ? "se_don" : "se_cancel")
}else if(name === "up" || name === "right" || name === "down" || name === "left"){
this.numberAdjust(selected, (name === "up" || name === "right") ? 1 : -1)
if(event){
event.preventDefault()
}`)
}),
new EditFunction(SettingsView.prototype, "keyboardSet").load(str => {
return plugins.strReplace(str, 'settings.items', `this.settingsItems`)
}),
new EditFunction(SettingsView.prototype, "gamepadSet").load(str => {
return plugins.strReplace(str, 'settings.items', `this.settingsItems`)
}),
new EditFunction(SettingsView.prototype, "gamepadBack").load(str => {
return plugins.strReplace(str, 'settings.items', `this.settingsItems`)
}),
new EditFunction(SettingsView.prototype, "latencySet").load(str => {
return plugins.strReplace(str, 'settings.items', `this.settingsItems`)
}),
new EditFunction(SettingsView.prototype, "latencyBack").load(str => {
return plugins.strReplace(str, 'settings.items', `this.settingsItems`)
}),
new EditValue(SettingsView.prototype, "numberAdjust").load(() => this.numberAdjust),
new EditValue(SettingsView.prototype, "numberBack").load(() => this.numberBack),
new EditFunction(SettingsView.prototype, "defaultSettings").load(str => {
str = plugins.insertBefore(str,
`if(this.customSettings){
plugins.unloadImported()
this.clean(true)
this.playSound("se_don")
return setTimeout(() => this.restart(), 500)
}
`, 'if(this.mode === "keyboard"){')
return plugins.strReplace(str, 'settings.items', `this.settingsItems`)
}),
new EditValue(SettingsView.prototype, "browseChange").load(() => this.browseChange),
new EditFunction(SettingsView.prototype, "onEnd").load(str => {
str = plugins.insertBefore(str,
`if(this.mode === "number"){
this.numberBack(this.items[this.selected])
}
`, 'this.clean()')
return plugins.strReplace(str, '"settings"', `this.customSettings ? "plugins" : "settings"`)
}),
new EditValue(SettingsView.prototype, "restart").load(() => this.restart),
new EditValue(SettingsView.prototype, "getLocalTitle").load(() => this.getLocalTitle),
new EditFunction(SettingsView.prototype, "setLang").load(str => {
str = plugins.insertBefore(str,
`if(lang)
`, 'settings.setLang(lang)')
return plugins.strReplace(str, 'var name = strings.settings[item.id].name\n\t\t\t\tthis.setAltText(item.nameDiv, name)',
`if(item.name || item.name_lang){
var name = this.getLocalTitle(item.name, item.name_lang)
}else{
var name = strings.settings[item.id].name
}
this.setAltText(item.nameDiv, name)
if(item.description || item.description_lang){
item.settingBox.title = this.getLocalTitle(item.description, item.description_lang) || ""
}`)
}),
new EditFunction(SettingsView.prototype, "setStrings").load(str => {
str = plugins.insertBefore(str, `this.customSettings ? this.pluginsStr().title : `, 'strings.gameSettings')
str = plugins.insertAfter(str, 'this.setAltText(this.endButton, strings.settings.ok)', `
if(this.customSettings){
this.browseText.data = this.pluginsStr().browse
this.browseButton.setAttribute("alt", this.pluginsStr().browse)
}else{`)
return plugins.strReplace(str,
'this.setAltText(this.defaultButton, strings.settings.default)',
`}
if(this.showDefault){
this.setAltText(this.defaultButton, this.customSettings ? this.pluginsStr().unloadAll : strings.settings.default)
}`)
}),
new EditFunction(SettingsView.prototype, "clean").load((str, args) => {
args.push("noSoundStop")
str = plugins.insertBefore(str,
`if(this.customSettings){
pageEvents.remove(window, "language-change", this.windowSymbol)
}
if(!noSoundStop)
`, 'assets.sounds["bgm_settings"].stop()')
str = plugins.insertBefore(str,
`if(this.customSettings){
pageEvents.remove(this.browse, "change")
delete this.browse
delete this.browseButton
delete this.browseText
}else{
`, 'this.removeTouch(this.gamepadSettings)')
str = plugins.insertAfter(str, 'this.removeTouch(this.latencyEndButton)', `
}`)
return plugins.strReplace(str,
'){\n\t\t\t\t\tURL.revokeObjectURL(assets.image[i].src)',
` || i.startsWith("results_")){
var img = assets.image[i]
URL.revokeObjectURL(img.src)
if(img.parentNode){
img.parentNode.removeChild(img)
}`)
}),
new EditValue(SongSelect.prototype, "pluginsStr").load(() => pluginsStr),
new EditFunction(SongSelect.prototype, "init").load(str => {
str = plugins.insertBefore(str,
`"plugins": {
sort: 0,
background: "#f6bba1",
border: ["#fde9df", "#ce7553"],
outline: "#ce7553"
}, `, '"default": {')
str = plugins.insertAfter(str, 'music: song.music,', `
chart: song.chart,
lyricsFile: song.lyricsFile,`)
str = plugins.insertAfter(str, 'action: "browse",\n\t\t\t\tcategory: strings.random\n\t\t\t})\n\t\t}',
`this.songs.push({
title: this.pluginsStr().title,
skin: this.songSkin.plugins,
action: "plugins",
category: strings.random
})`)
return plugins.strReplace(str, 'speed: 800', `speed: 400 * 2`)
}),
new EditFunction(SongSelect.prototype, "toSelectDifficulty").load(str => {
return plugins.insertAfter(str,
'this.toBrowse()', `
}else if(currentSong.action === "plugins"){
this.toPlugins()`)
}),
new EditValue(SongSelect.prototype, "toPlugins").load(() => this.toPlugins),
new EditValue(ImportSongs.prototype, "pluginsStr").load(() => pluginsStr),
new EditFunction(SongSelect.prototype, "diffSelMouse").load(str => {
return plugins.strReplace(str,
'if(223 < x && x < 367 && 132 < y && y < 436){\n\t\t\t\treturn Math.floor((x - 223) / ((367 - 223) / 2))',
`if(223 < x && x < 223 + 72 * this.diffOptions.length && 132 < y && y < 436){
return Math.floor((x - 223) / 72)`)
}),
new EditFunction(SongSelect.prototype, "redraw").load(str => {
return plugins.strReplace(str,
'ms >= this.pressedKeys[key] + 50',
`ms >= this.pressedKeys[key] + (this.state.screen === "song" && (key === "right" || key === "left") ? 20 : 50)`)
}),
new EditFunction(ImportSongs.prototype, "init").load((str, args) => {
args.push("otherFiles")
str = plugins.insertBefore(str,
`if(!songSelect && !otherFiles){
return
}
if(songSelect){
`, 'this.songSelect = songSelect')
str = plugins.insertBefore(str,
`}else{
var files = otherFiles
}
this.pluginFiles = []
this.plugins = []
`, 'this.tjaFiles = []')
str = plugins.insertBefore(str,
`if(name.endsWith(".taikoweb.js")){
this.pluginFiles.push({
file: file,
index: i
})
}else `, 'if(name.endsWith(".tja")){')
str = plugins.insertBefore(str,
`this.pluginAmount = 0
if(this.pluginFiles.length){
var pluginPromises = []
this.pluginFiles.forEach(fileObj => {
pluginPromises.push(this.addPlugin(fileObj).catch(e => console.warn(e)))
})
return Promise.all(pluginPromises).then(() => {
var startPromises = []
if(this.plugins.length && confirm(this.pluginsStr().warning.replace("%s",
this.pluginsStr().plugin[strings.plural.select(this.plugins.length)].replace("%s",
this.plugins.length.toString()
)
))){
this.plugins.forEach(obj => {
var plugin = plugins.add(obj.data, {
name: obj.name,
raw: true
})
if(plugin){
this.pluginAmount++
plugin.imported = true
startPromises.push(plugin.start())
}
})
}
return Promise.all(startPromises).then(this.loaded.bind(this))
})
}
`, 'var metaPromises = []')
str = plugins.insertBefore(str, `return `, 'Promise.all(metaPromises)')
return plugins.insertBefore(str, `return `, 'Promise.all(songPromises)')
}),
new EditValue(ImportSongs.prototype, "load").load(() => this.importSongsLoad),
new EditValue(ImportSongs.prototype, "addPlugin").load(() => this.addPlugin),
new EditFunction(ImportSongs.prototype, "loaded").load(str => {
return plugins.insertBefore(str,
`if(!this.songSelect){
if(this.songs.length){
return Promise.resolve(this.songs)
}else{
if(this.pluginAmount || Object.keys(this.assetFiles).length){
return Promise.resolve()
}else{
return Promise.reject("nosongs")
}
}
return this.clean()
}
`, 'if(this.stylesheet.length){')
}),
new EditValue(loader, "cssRuleset").load(() => this.cssRuleset),
new EditValue(p2, "disabled").load(() => 0),
new EditFunction(p2, "open").load(str => {
return plugins.insertBefore(str,
`if(!this.closed || this.disabled){
return
}
`, 'this.closed = false')
}),
new EditValue(p2, "enable").load(() => this.p2enable),
new EditValue(p2, "disable").load(() => this.p2disable),
new EditFunction(snd.sfxGain.soundBuffer, "load").load(str => {
return plugins.insertBefore(str,
`if(typeof url.arrayBuffer === "function"){
var loadPromise = url.arrayBuffer()
}else `, 'if(local){')
}),
new EditFunction(SongSelect.prototype, "getLocalTitle").load(str => {
return plugins.strReplace(str,
'if(id === strings.id && titleLang[id]){',
`if(id === "en" && strings.preferEn && !(strings.id in titleLang) && titleLang.en || id === strings.id && titleLang[id]){`)
}),
new EditFunction(Account.prototype, "accountForm").load(str => {
return plugins.insertAfter(str,
'this.redrawRunning = true', `
this.redrawPaused = 'matchMedia("(prefers-reduced-motion: reduce)").matches' === 'true'`)
}),
new EditFunction(Account.prototype, "customdonRedraw").load(str => {
return plugins.insertAfter(str,
'var frame = ', `this.redrawPaused ? 0 : `)
}),
new EditFunction(LoadSong.prototype, "run").load(str => {
str = plugins.strReplace(str,
'if(songObj.chart){',
`if(songObj.chart && !songObj.chart.separateDiff && !(songObj.chart instanceof RemoteFile)){`)
return plugins.strReplace(str,
'if(songObj.music){',
`if(songObj.music && !(songObj.chart instanceof RemoteFile)){`)
}),
new EditFunction(Controller.prototype, "restartSong").load(str => {
str = plugins.strReplace(str,
'if(songObj.chart &&',
`if(songObj.chart && !songObj.chart.separateDiff && !(songObj.chart instanceof RemoteFile) &&`)
return plugins.strReplace(str,
'if(songObj.lyricsFile){',
`if(songObj.lyricsFile && !(songObj.lyricsFile instanceof RemoteFile)){`)
}),
)
}
start(){
document.head.appendChild(this.style)
if(assets && assets.songsDefault){
assets.songsDefault.forEach(song => {
var directory = gameConfig.songs_baseurl + song.id + "/"
var songExt = song.music_type ? song.music_type : "mp3"
song.music = new RemoteFile(directory + "main." + songExt)
if(song.type === "tja"){
song.chart = new RemoteFile(directory + "main.tja")
}else{
song.chart = {separateDiff: true}
for(var diff in song.courses){
if(song.courses[diff]){
song.chart[diff] = new RemoteFile(directory + diff + ".osu")
}
}
}
if(song.lyrics){
song.lyricsFile = new RemoteFile(directory + "main.vtt")
}
})
}
}
stop(){
if(this.style.parentNode){
this.style.parentNode.removeChild(this.style)
}
if(assets && assets.songsDefault){
assets.songsDefault.forEach(song => {
if(song.music instanceof RemoteFile){
delete song.music
}
delete song.chart
delete song.lyricsFile
})
}
}
addLang(lang, forceSet){
allStrings[lang.id] = lang
if(lang.categories){
assets.categories.forEach(category => {
if("title_lang" in category && lang.categories[category.title_lang.en]){
category.title_lang[lang.id] = lang.categories[category.title_lang.en]
}
})
}
languageList.push(lang.id)
this.allLanguages.push(lang.id)
this.items.language.default = this.getLang()
if(forceSet){
this.storage.language = lang.id
}else{
try{
this.storage.language = localStorage.getItem("lang")
}catch(e){}
if(this.items.language.options.indexOf(this.storage.language) === -1){
this.storage.language = null
}
}
if(settings.getItem("language") === lang.id){
settings.setLang(lang)
}
}
removeLang(lang){
delete allStrings[lang.id]
assets.categories.forEach(category => {
if("title_lang" in category){
delete category.title_lang[lang.id]
}
})
var index = languageList.indexOf(lang.id)
if(index !== -1){
languageList.splice(index, 1)
}
var index = this.allLanguages.indexOf(lang.id)
if(index !== -1){
this.allLanguages.splice(index, 1)
}
this.items.language.default = this.getLang()
try{
this.storage.language = localStorage.getItem("lang")
}catch(e){}
if(this.items.language.options.indexOf(this.storage.language) === -1){
this.storage.language = null
}
if(lang.id === strings.id){
settings.setLang(allStrings[this.getItem("language")])
}
}
numberAdjust(selected, add){
var selectedItem = this.items[this.selected]
var mul = Math.pow(10, selected.fixedPoint || 0)
selectedItem.value += add * ("step" in selected ? selected.step : 1)
if("max" in selected && selectedItem.value > selected.max * mul){
selectedItem.value = selected.max * mul
}else if("min" in selected && selectedItem.value < selected.min * mul){
selectedItem.value = selected.min * mul
}else{
this.playSound("se_ka")
}
var valueText = Intl.NumberFormat(strings.intl, selected.sign ? {
signDisplay: "always"
} : undefined).format(selectedItem.value / mul)
if(selected.format || selected.format_lang){
valueText = this.getLocalTitle(selected.format, selected.format_lang).replace("%s", valueText)
}
selectedItem.valueText.data = valueText
}
numberBack(selected){
this.mode = "settings"
selected.settingBox.style.animation = ""
selected.valueDiv.classList.remove("selected")
var current = this.settingsItems[selected.id]
var promise
var mul = Math.pow(10, selected.fixedPoint || 0)
var value = selected.value / mul
if(current.setItem){
promise = current.setItem(value)
}else{
settings.setItem(selected.id, value)
}
(promise || Promise.resolve()).then(() => {
this.getValue(selected.id, selected.valueText)
})
}
browseChange(event){
this.locked = true
var files = []
for(var i = 0; i < event.target.files.length; i++){
files.push(new LocalFile(event.target.files[i]))
}
var customSongs = new CustomSongs(this.touchEnabled, true)
customSongs.importLocal(files).then(() => {
this.clean(true)
return this.restart()
}).catch(e => {
if(e){
var message = e.message
if(e.name === "nosongs"){
message = this.pluginsStr().noPlugins
}
if(message){
alert(message)
}
}
this.locked = false
this.browse.form.reset()
return Promise.resolve()
})
}
restart(){
if(this.mode === "number"){
this.numberBack(this.items[this.selected])
}
return new SettingsView(this.touchEnabled, this.tutorial, this.songId, undefined, this.customSettings ? plugins.getSettings() : undefined, true)
}
getLocalTitle(title, titleLang){
if(titleLang){
for(var id in titleLang){
if(id === strings.id && titleLang[id]){
return titleLang[id]
}
}
}
return title
}
toPlugins(){
this.playSound("se_don")
this.clean()
setTimeout(() => {
new SettingsView(this.touchEnabled, false, undefined, undefined, plugins.getSettings())
}, 500)
}
importSongsLoad(files){
return this.init(null, null, files)
}
addPlugin(fileObj){
var file = fileObj.file
var filePromise = file.read()
return filePromise.then(dataRaw => {
var name = file.name.slice(0, file.name.lastIndexOf(".taikoweb.js"))
this.plugins.push({
name: name,
data: dataRaw
})
})
}
cssRuleset(rulesets){
var css = []
for(var selector in rulesets){
var declarationsObj = rulesets[selector]
var declarations = []
for(var property in declarationsObj){
var value = declarationsObj[property]
declarations.push("\t" + property + ": " + value + ";")
}
css.push(selector + "{\n" + declarations.join("\n") + "\n}")
}
return css.join("\n")
}
p2enable(){
this.disabled = Math.max(0, this.disabled - 1)
setTimeout(this.open.bind(this), 100)
}
p2disable(){
this.disabled++
this.close()
}
}
function ready(){
if(typeof CustomSongs !== "undefined"){
console.error("[Plugins in Old Taiko Web] Cannot run on new taiko-web")
return
}
window.Plugins = Plugins
window.PluginLoader = PluginLoader
window.EditValue = EditValue
window.EditFunction = EditFunction
window.Patch = Patch
window.readFile = readFile
window.RemoteFile = RemoteFile
window.LocalFile = LocalFile
window.CustomSongs = CustomSongs2
window.Search = Search
var classes = [
About, Account, Settings, SongSelect, AutoScore, CanvasAsset, CanvasCache, CanvasDraw, CanvasTest, Circle, Controller, Debug, InputSlider,
Game, GameInput, Gamepad, GameRules, ImportSongs, Keyboard, LoadSong, Logo, Lyrics, Mekadon, P2Connection, ParseOsu, ParseTja, Scoresheet,
ScoreStorage, Session, Settings, SettingsView, SongSelect, SoundBuffer, SoundGain, Sound, Titlescreen, Tutorial, View, ViewAssets
]
classes.forEach(cls => {
var str = cls.toString()
var needle1 = "class "
var index1 = str.indexOf(needle1)
if(index1 !== -1){
var pos = index1 + needle1.length
var needle2 = "{"
var index2 = str.indexOf(needle2, pos)
if(index2 !== -1){
var name = str.slice(pos, index2).trim()
if(name){
pos = index2 + needle2.length
var needle3 = "constructor"
var index3 = str.indexOf(needle3, pos)
if(index3 !== -1){
var str = name + " = " + str.slice(0, index3 + needle3.length) + "(...args){\n\t\tthis.init(...args)\n\t}\n\tinit" + str.slice(index3 + needle3.length)
return window.eval(str)
}
}
}
}
throw new Error("Error attempting to fix class:", cls)
})
window.plugins = new Plugins()
var plugin = plugins.add(PluginsInOld, {
name: PluginsInOld.name,
hide: true
})
plugin?.start()
}
if(typeof perf !== "undefined" && perf.allImg){
ready()
}else{
addEventListener("ready", ready, {once: true})
}