- Change song select mouse wheel song scrolling to be instant - Clicking on don chan in account settings toggles the animation - If the music is too long for the chart, the results screen is shown earlier - Fix weird BPM values freezing the browser (zero, negative, and very large) - Add a warning to the page when JavaScript is disabled in the browser - Fix Chrome auto dark mode by forcing light mode on the page - Add a meta keywords tag to the page - Fix plugin names getting cut off in the menu - Delay the function editing of the EditFunction class in plugins to the start() function instead of load() - When stopping one of the plugins, all the plugins have to be stopped in reverse order and started again so that patched code of a stopped plugin does not linger around - Fix importing plugins that have a SyntaxError - Fix plugins getting the same internal name when added without one, causing them to not appear in the plugin settings - Support editing args in EditFunction for plugins - Prevent multiple websockets from being opened - Fix page freezing after selecting Random song with no songs - Fix the back button being repeated twice when there are no songs - Fix /admin/users not accepting case insensitive usernames - Pressing enter on the Delete Account field does the expected action instead of refreshing the page - Better error message when custom folder access is denied - Fix being able to start netplay in custom songs after refreshing the page (#383) - Fix an error when importing songs from previous session and clicking on the white spot where you normally start multiplayer session - Fix canvas elements becoming smaller than 1x1 resolution and crashing the game (#390) - Fix song frame shadow cache on song select not being cleared when resizing the browser window, causing it to become blurry - Fix a pause-restart error when you hit both confirm keys on the restart button
143 lines
2.9 KiB
JavaScript
143 lines
2.9 KiB
JavaScript
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
|
|
}
|
|
function filePermission(file){
|
|
return file.queryPermission().then(response => {
|
|
if(response === "granted"){
|
|
return file
|
|
}else{
|
|
return file.requestPermission().then(response => {
|
|
if(response === "granted"){
|
|
return file
|
|
}else{
|
|
return Promise.reject(strings.accessNotGrantedError)
|
|
}
|
|
})
|
|
}
|
|
})
|
|
}
|
|
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)
|
|
}
|
|
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 this.arrayBuffer().then(response => new Blob([response]))
|
|
}
|
|
}
|
|
class LocalFile{
|
|
constructor(...args){
|
|
this.init(...args)
|
|
}
|
|
init(file, path){
|
|
this.file = file
|
|
this.path = path || file.webkitRelativePath
|
|
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 FilesystemFile{
|
|
constructor(...args){
|
|
this.init(...args)
|
|
}
|
|
init(file, path){
|
|
this.file = file
|
|
this.path = path
|
|
this.url = this.path
|
|
this.name = file.name
|
|
}
|
|
arrayBuffer(){
|
|
return this.blob().then(blob => blob.arrayBuffer())
|
|
}
|
|
read(encoding){
|
|
return this.blob().then(blob => readFile(blob, false, encoding))
|
|
}
|
|
blob(){
|
|
return filePermission(this.file).then(file => file.getFile())
|
|
}
|
|
}
|
|
class GdriveFile{
|
|
constructor(...args){
|
|
this.init(...args)
|
|
}
|
|
init(fileObj){
|
|
this.path = fileObj.path
|
|
this.name = fileObj.name
|
|
this.id = fileObj.id
|
|
this.url = gpicker.filesUrl + this.id + "?alt=media"
|
|
}
|
|
arrayBuffer(){
|
|
return gpicker.downloadFile(this.id, true)
|
|
}
|
|
read(encoding){
|
|
if(encoding){
|
|
return this.blob().then(blob => readFile(blob, false, encoding))
|
|
}else{
|
|
return gpicker.downloadFile(this.id)
|
|
}
|
|
}
|
|
blob(){
|
|
return this.arrayBuffer().then(response => new Blob([response]))
|
|
}
|
|
}
|
|
class CachedFile{
|
|
constructor(...args){
|
|
this.init(...args)
|
|
}
|
|
init(contents, oldFile){
|
|
this.contents = contents
|
|
this.oldFile = oldFile
|
|
this.path = oldFile.path
|
|
this.name = oldFile.name
|
|
this.url = oldFile.url
|
|
}
|
|
arrayBuffer(){
|
|
return Promise.resolve(this.contents)
|
|
}
|
|
read(encoding){
|
|
return this.arrayBuffer()
|
|
}
|
|
blob(){
|
|
return this.arrayBuffer().then(response => new Blob([response]))
|
|
}
|
|
}
|