Changed look of song loading, fix custom game assets and song skins, fix auth error

- Change the way a selected song appears while it is loading the metadata
- Fix custom taikowebskin
- Fix importing custom game assets (local only)
- Get the oauth token again on auth error
This commit is contained in:
LoveEevee 2020-10-31 14:47:42 +03:00
parent c5ce5104f1
commit 180ec58adb
10 changed files with 103 additions and 59 deletions

View File

@ -138,7 +138,7 @@
if(gamepads[i]){ if(gamepads[i]){
var gamepadDiag = [] var gamepadDiag = []
gamepadDiag.push(gamepads[i].id) gamepadDiag.push(gamepads[i].id)
gamepadDiag.push("buttons: " + gamepads[i].buttons.length) gamepadDiag.push("buttons: " + gamepads[i].buttons.length)
gamepadDiag.push("axes: " + gamepads[i].axes.length) gamepadDiag.push("axes: " + gamepads[i].axes.length)
diag.push("Gamepad #" + (i + 1) + ": " + gamepadDiag.join(", ")) diag.push("Gamepad #" + (i + 1) + ": " + gamepadDiag.join(", "))
} }

View File

@ -1,3 +1,9 @@
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{ class RemoteFile{
constructor(url){ constructor(url){
this.url = url this.url = url
@ -22,13 +28,14 @@ class RemoteFile{
} }
read(encoding){ read(encoding){
if(encoding){ if(encoding){
return this.arrayBuffer().then(response => return this.blob().then(blob => readFile(blob, false, encoding))
new TextDecoder(encoding).decode(response)
)
}else{ }else{
return loader.ajax(this.url) return loader.ajax(this.url)
} }
} }
blob(){
return this.arrayBuffer().then(response => new Blob([response]))
}
} }
class LocalFile{ class LocalFile{
constructor(file){ constructor(file){
@ -38,16 +45,13 @@ class LocalFile{
this.name = file.name this.name = file.name
} }
arrayBuffer(){ arrayBuffer(){
var reader = new FileReader() return readFile(this.file, true)
var promise = pageEvents.load(reader).then(event => event.target.result)
reader.readAsArrayBuffer(this.file)
return promise
} }
read(encoding){ read(encoding){
var reader = new FileReader() return readFile(this.file, false, encoding)
var promise = pageEvents.load(reader).then(event => event.target.result) }
reader.readAsText(this.file, encoding) blob(){
return promise return Promise.resolve(this.file)
} }
} }
class GdriveFile{ class GdriveFile{
@ -62,16 +66,14 @@ class GdriveFile{
} }
read(encoding){ read(encoding){
if(encoding){ if(encoding){
return this.arrayBuffer().then(response => { return this.blob().then(blob => readFile(blob, false, encoding))
var reader = new FileReader()
var promise = pageEvents.load(reader).then(event => event.target.result)
reader.readAsText(new Blob([response]), encoding)
return promise
})
}else{ }else{
return gpicker.downloadFile(this.id) return gpicker.downloadFile(this.id)
} }
} }
blob(){
return this.arrayBuffer().then(response => new Blob([response]))
}
} }
class CachedFile{ class CachedFile{
constructor(contents, oldFile){ constructor(contents, oldFile){
@ -87,4 +89,7 @@ class CachedFile{
read(encoding){ read(encoding){
return this.arrayBuffer() return this.arrayBuffer()
} }
blob(){
return this.arrayBuffer().then(response => new Blob([response]))
}
} }

View File

@ -40,12 +40,12 @@ class Controller{
this.parsedSongData = new ParseOsu(songData, selectedSong.difficulty, selectedSong.stars, selectedSong.offset) this.parsedSongData = new ParseOsu(songData, selectedSong.difficulty, selectedSong.stars, selectedSong.offset)
} }
this.offset = this.parsedSongData.soundOffset this.offset = this.parsedSongData.soundOffset
var maxCombo = this.parsedSongData.circles.filter(circle => ["don", "ka", "daiDon", "daiKa"].indexOf(circle.type) > -1 && (!circle.branch || circle.branch.name == "master")).length var maxCombo = this.parsedSongData.circles.filter(circle => ["don", "ka", "daiDon", "daiKa"].indexOf(circle.type) > -1 && (!circle.branch || circle.branch.name == "master")).length
if (maxCombo >= 50) { if (maxCombo >= 50) {
var comboVoices = ["v_combo_50"].concat([...Array(Math.floor(maxCombo/100)).keys()].map(i => "v_combo_" + (i + 1)*100)) var comboVoices = ["v_combo_50"].concat(Array.from(Array(Math.min(50, Math.floor(maxCombo / 100))), (d, i) => "v_combo_" + ((i + 1) * 100)))
var promises = [] var promises = []
comboVoices.forEach(name => { comboVoices.forEach(name => {
if (!assets.sounds[name + "_p1"]) { if (!assets.sounds[name + "_p1"]) {
promises.push(loader.loadSound(name + ".wav", snd.sfxGain).then(sound => { promises.push(loader.loadSound(name + ".wav", snd.sfxGain).then(sound => {
@ -54,7 +54,7 @@ class Controller{
})) }))
} }
}) })
Promise.all(promises) Promise.all(promises)
} }

View File

@ -136,10 +136,12 @@ class CustomSongs{
} }
} }
songsLoaded(songs){ songsLoaded(songs){
var length = songs.length if(songs){
assets.songs = songs var length = songs.length
assets.customSongs = true assets.songs = songs
assets.customSelected = 0 assets.customSongs = true
assets.customSelected = 0
}
assets.sounds["se_don"].play() assets.sounds["se_don"].play()
this.clean() this.clean()
setTimeout(() => { setTimeout(() => {

View File

@ -84,7 +84,7 @@ class Gpicker{
gapi.client.load("drive", "v3").then(resolve, reject) gapi.client.load("drive", "v3").then(resolve, reject)
)) ))
} }
getToken(lockedCallback){ getToken(lockedCallback=()=>{}){
if(this.oauthToken){ if(this.oauthToken){
return Promise.resolve() return Promise.resolve()
} }
@ -156,13 +156,31 @@ class Gpicker{
.build() .build()
.setVisible(true) .setVisible(true)
} }
downloadFile(id, arrayBuffer){ downloadFile(id, arrayBuffer, retry){
return this.queue().then(() => var url = this.filesUrl + id + "?alt=media"
loader.ajax(this.filesUrl + id + "?alt=media", request => { return this.queue().then(this.getToken.bind(this)).then(() =>
loader.ajax(url, request => {
if(arrayBuffer){ if(arrayBuffer){
request.responseType = "arraybuffer" request.responseType = "arraybuffer"
} }
request.setRequestHeader("Authorization", "Bearer " + this.oauthToken) request.setRequestHeader("Authorization", "Bearer " + this.oauthToken)
}, true).then(event => {
var request = event.target
var reject = () => Promise.reject(`${url} (${request.status})`)
if(request.status === 200){
return request.response
}else if(request.status === 401 && !retry){
return new Response(request.response).json().then(response => {
var e = response.error
if(e && e.errors[0].reason === "authError"){
delete this.oauthToken
return this.downloadFile(id, arrayBuffer, true)
}else{
return reject()
}
}, reject)
}
return reject()
}) })
) )
} }

View File

@ -7,7 +7,7 @@
this.otherFiles = otherFiles || {} this.otherFiles = otherFiles || {}
this.songs = [] this.songs = []
this.stylesheet = [] this.stylesheet = []
this.songTitle = {} this.songTitle = this.otherFiles.songTitle || {}
this.uraRegex = /\s*[\(]裏[\)]$/ this.uraRegex = /\s*[\(]裏[\)]$/
this.courseTypes = { this.courseTypes = {
"easy": 0, "easy": 0,
@ -42,6 +42,7 @@
"bg_stage_2": ".song-stage-2", "bg_stage_2": ".song-stage-2",
"bg_stage_3": ".song-stage-3" "bg_stage_3": ".song-stage-3"
} }
this.comboVoices = ["v_combo_50"].concat(Array.from(Array(50), (d, i) => "v_combo_" + ((i + 1) * 100)))
} }
load(files){ load(files){
var extensionRegex = /\.[^\/]+$/ var extensionRegex = /\.[^\/]+$/
@ -66,13 +67,13 @@
file: file, file: file,
index: i index: i
}) })
}else if(!this.limited && (name === "genre.ini" || name === "box.def" || name === "songtitle.txt")){ }else if(!this.limited && (name === "genre.ini" || name === "box.def") || name === "songtitle.txt"){
var level = (file.path.match(/\//g) || []).length var level = (file.path.match(/\//g) || []).length
metaFiles.push({ metaFiles.push({
file: file, file: file,
level: (level * 2) + (name === "genre.ini" ? 1 : 0) level: (level * 2) + (name === "genre.ini" ? 1 : 0)
}) })
}else if(!this.limited && path.indexOf("/taiko-web assets/") !== -1){ }else if(!this.limited && (path.indexOf("/taiko-web assets/") !== -1 || path.indexOf("taiko-web assets/") === 0)){
if(!(name in this.assetFiles)){ if(!(name in this.assetFiles)){
this.assetFiles[name] = file this.assetFiles[name] = file
} }
@ -401,12 +402,13 @@
for(let name in this.assetFiles){ for(let name in this.assetFiles){
let id = this.getFilename(name) let id = this.getFilename(name)
var file = this.assetFiles[name] var file = this.assetFiles[name]
var index = name.lastIndexOf(".")
if(name === "vectors.json"){ if(name === "vectors.json"){
promises.push(file.read().then(() => response => { promises.push(file.read().then(response => {
vectors = JSON.parse(response) vectors = JSON.parse(response)
})) }))
} }
if(assets.img.indexOf(name) !== -1){ if(name.endsWith(".png")){
let image = document.createElement("img") let image = document.createElement("img")
promises.push(pageEvents.load(image).then(() => { promises.push(pageEvents.load(image).then(() => {
if(id in this.assetSelectors){ if(id in this.assetSelectors){
@ -415,9 +417,12 @@
} }
})) }))
image.id = name image.id = name
image.src = URL.createObjectURL(file) image.src = URL.createObjectURL(file.blob())
loader.assetsDiv.appendChild(image) loader.assetsDiv.appendChild(image)
assets.image[id].parentNode.removeChild(assets.image[id]) var oldImage = assets.image[id]
if(oldImage && oldImage.parentNode){
oldImage.parentNode.removeChild(oldImage)
}
assets.image[id] = image assets.image[id] = image
} }
if(assets.audioSfx.indexOf(name) !== -1){ if(assets.audioSfx.indexOf(name) !== -1){
@ -440,6 +445,13 @@
assets.sounds[id].clean() assets.sounds[id].clean()
promises.push(this.loadSound(file, name, snd.sfxLoudGain)) promises.push(this.loadSound(file, name, snd.sfxLoudGain))
} }
if(this.comboVoices.indexOf(id) !== -1){
promises.push(snd.sfxGain.load(file).then(sound => {
assets.sounds[id] = sound
assets.sounds[id + "_p1"] = assets.sounds[id].copy(snd.sfxGainL)
assets.sounds[id + "_p2"] = assets.sounds[id].copy(snd.sfxGainR)
}))
}
} }
return Promise.all(promises) return Promise.all(promises)
} }
@ -525,8 +537,11 @@
if(this.songs.length){ if(this.songs.length){
if(this.limited){ if(this.limited){
assets.otherFiles = this.otherFiles assets.otherFiles = this.otherFiles
assets.otherFiles.songTitle = this.songTitle
} }
return Promise.resolve(this.songs) return Promise.resolve(this.songs)
}else if(Object.keys(this.assetFiles).length){
return Promise.resolve()
}else{ }else{
return Promise.reject("cancel") return Promise.reject("cancel")
} }
@ -571,6 +586,7 @@
delete this.songs delete this.songs
delete this.tjaFiles delete this.tjaFiles
delete this.osuFiles delete this.osuFiles
delete this.assetFiles
delete this.otherFiles delete this.otherFiles
} }
} }

View File

@ -433,16 +433,19 @@ class Loader{
this.screen.innerHTML = assets.pages[name] this.screen.innerHTML = assets.pages[name]
this.screen.classList[patternBg ? "add" : "remove"]("pattern-bg") this.screen.classList[patternBg ? "add" : "remove"]("pattern-bg")
} }
ajax(url, customRequest){ ajax(url, customRequest, customResponse){
var request = new XMLHttpRequest() var request = new XMLHttpRequest()
request.open("GET", url) request.open("GET", url)
var promise = pageEvents.load(request).then(() => { var promise = pageEvents.load(request)
if(request.status === 200){ if(!customResponse){
return request.response promise = promise.then(() => {
}else{ if(request.status === 200){
return Promise.reject(`${url} (${request.status})`) return request.response
} }else{
}) return Promise.reject(`${url} (${request.status})`)
}
})
}
if(customRequest){ if(customRequest){
customRequest(request) customRequest(request)
} }

View File

@ -108,7 +108,9 @@ class LoadSong{
return this.scaleImg(img, filename, prefix, force) return this.scaleImg(img, filename, prefix, force)
}), songObj.custom ? filename + ".png" : skinBase + filename + ".png") }), songObj.custom ? filename + ".png" : skinBase + filename + ".png")
if(songObj.custom){ if(songObj.custom){
img.src = URL.createObjectURL(song.songSkin[filename + ".png"]) this.addPromise(song.songSkin[filename + ".png"].blob().then(blob => {
img.src = URL.createObjectURL(blob)
}))
}else{ }else{
img.src = skinBase + filename + ".png" img.src = skinBase + filename + ".png"
} }

View File

@ -1090,7 +1090,7 @@ class SongSelect{
} }
if(screen === "song"){ if(screen === "song"){
if(this.songs[this.selectedSong].courses){ if(this.songs[this.selectedSong].courses && !this.songs[this.selectedSong].unloaded){
selectedWidth = this.songAsset.selectedWidth selectedWidth = this.songAsset.selectedWidth
} }
@ -1101,11 +1101,11 @@ class SongSelect{
var resize2 = changeSpeed - resize var resize2 = changeSpeed - resize
var scroll = resize2 - resize - scrollDelay * 2 var scroll = resize2 - resize - scrollDelay * 2
var elapsed = ms - this.state.moveMS var elapsed = ms - this.state.moveMS
if(this.state.catJump || (this.state.move && ms > this.state.moveMS + resize2 - scrollDelay)){ if(this.state.catJump || (this.state.move && ms > this.state.moveMS + resize2 - scrollDelay)){
var isJump = this.state.catJump var isJump = this.state.catJump
var previousSelectedSong = this.selectedSong var previousSelectedSong = this.selectedSong
if(!isJump){ if(!isJump){
this.playSound("se_ka", 0, this.lastMoveBy) this.playSound("se_ka", 0, this.lastMoveBy)
this.selectedSong = this.mod(this.songs.length, this.selectedSong + this.state.move) this.selectedSong = this.mod(this.songs.length, this.selectedSong + this.state.move)
@ -1165,7 +1165,7 @@ class SongSelect{
if(this.songs[this.selectedSong].action !== "back"){ if(this.songs[this.selectedSong].action !== "back"){
var cat = this.songs[this.selectedSong].originalCategory var cat = this.songs[this.selectedSong].originalCategory
this.drawBackground(cat) this.drawBackground(cat)
} }
} }
if(this.state.moveMS && ms < this.state.moveMS + changeSpeed){ if(this.state.moveMS && ms < this.state.moveMS + changeSpeed){
@ -1291,7 +1291,7 @@ class SongSelect{
highlight = 1 highlight = 1
} }
var selectedSkin = this.songSkin.selected var selectedSkin = this.songSkin.selected
if(screen === "title" || screen === "titleFadeIn" || this.state.locked === 3){ if(screen === "title" || screen === "titleFadeIn" || this.state.locked === 3 || currentSong.unloaded){
selectedSkin = currentSong.skin selectedSkin = currentSong.skin
highlight = 2 highlight = 2
}else if(songSelMoving){ }else if(songSelMoving){
@ -2278,7 +2278,7 @@ class SongSelect{
}else{ }else{
this.songSelect.style.backgroundImage = "url('" + assets.image["bg_genre_def"].src + "')" this.songSelect.style.backgroundImage = "url('" + assets.image["bg_genre_def"].src + "')"
} }
} }
drawClosedSong(config){ drawClosedSong(config){
var ctx = config.ctx var ctx = config.ctx
@ -2476,20 +2476,18 @@ class SongSelect{
currentSong.chart = new CachedFile(data, file) currentSong.chart = new CachedFile(data, file)
return importSongs[currentSong.type === "tja" ? "addTja" : "addOsu"]({ return importSongs[currentSong.type === "tja" ? "addTja" : "addOsu"]({
file: currentSong.chart, file: currentSong.chart,
index: 0 index: currentSong.id
}) })
}).then(() => { }).then(() => {
var imported = importSongs.songs[0] var imported = importSongs.songs[currentSong.id]
importSongs.clean() importSongs.clean()
imported.id = currentSong.id
imported.order = currentSong.order
delete imported.song_skin
songObj.preview_time = imported.preview songObj.preview_time = imported.preview
var index = assets.songs.findIndex(song => song.id === currentSong.id) var index = assets.songs.findIndex(song => song.id === currentSong.id)
if(index !== -1){ if(index !== -1){
assets.songs[index] = imported assets.songs[index] = imported
} }
this.songs[selectedSong] = this.addSong(imported) this.songs[selectedSong] = this.addSong(imported)
this.state.moveMS = this.getMS() - this.songSelecting.speed * this.songSelecting.resize
if(imported.music && currentId === this.previewId){ if(imported.music && currentId === this.previewId){
return snd.previewGain.load(imported.music).then(sound => { return snd.previewGain.load(imported.music).then(sound => {
imported.sound = sound imported.sound = sound

View File

@ -308,8 +308,8 @@
w: _w, h: _h, w: _w, h: _h,
radius: 11 radius: 11
}) })
ctx.fill() ctx.fill()
this.draw.layeredText({ this.draw.layeredText({
ctx: ctx, ctx: ctx,
text: selectedSong.category, text: selectedSong.category,