mirror of
https://github.com/yuukiwww/taiko-web.git
synced 2024-10-22 17:05:49 +02:00
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:
parent
c5ce5104f1
commit
180ec58adb
@ -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(", "))
|
||||||
}
|
}
|
||||||
|
@ -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]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(() => {
|
||||||
|
@ -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()
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user