mirror of
https://github.com/jiojciojsioe3/a3cjroijsiojiorj.git
synced 2024-11-15 15:31:51 +08:00
ImportSongs: Add Google Drive support
- Adds a new page for importing custom songs, where it is possible to pick a local folder (desktop only) or a Google Drive folder (desktop and Android) - This feature is disabled on iOS due to the lack of OGG audio support in the browser - In order to not get rate limited, a TJA file is parsed for metadata only when the song is clicked in the song selection, rather than all at once at import time - The instance maintainer will need to provide the API credentials in the config.py file to enable this feature - This requires a new project to be created at console.cloud.google.com - Drive API will have to be enabled - API and OAuth keys should be created - API key can be restricted to only have Google Drive and Google Picker APIs - OAuth Client ID should have Web Application type and JavaScript origins set - Editing the OAuth consent screen to have a name and icon is recommended - It is semi-required to submit the consent screen for verification as the permission to download all of the Drive files will be asked. - Note that the email of the maintainer is publicly visible on the consent screen - The project number can be found in the IAM & Admin settings page
This commit is contained in:
parent
224bf25fc0
commit
3fea149353
3
app.py
3
app.py
@ -119,7 +119,8 @@ def get_config():
|
|||||||
'assets_baseurl': config.ASSETS_BASEURL,
|
'assets_baseurl': config.ASSETS_BASEURL,
|
||||||
'email': config.EMAIL,
|
'email': config.EMAIL,
|
||||||
'accounts': config.ACCOUNTS,
|
'accounts': config.ACCOUNTS,
|
||||||
'custom_js': config.CUSTOM_JS
|
'custom_js': config.CUSTOM_JS,
|
||||||
|
'google_credentials': config.GOOGLE_CREDENTIALS
|
||||||
}
|
}
|
||||||
|
|
||||||
if not config_out.get('songs_baseurl'):
|
if not config_out.get('songs_baseurl'):
|
||||||
|
@ -33,3 +33,11 @@ SECRET_KEY = 'change-me'
|
|||||||
|
|
||||||
# Git repository base URL.
|
# Git repository base URL.
|
||||||
URL = 'https://github.com/bui/taiko-web/'
|
URL = 'https://github.com/bui/taiko-web/'
|
||||||
|
|
||||||
|
# Google Drive API.
|
||||||
|
GOOGLE_CREDENTIALS = {
|
||||||
|
'gdrive_enabled': False,
|
||||||
|
'api_key': '',
|
||||||
|
'oauth_client_id': '',
|
||||||
|
'project_number': ''
|
||||||
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
border: 3px solid white;
|
border: 3px solid white;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
#loading-don{
|
#loading-don{
|
||||||
width: 10vw;
|
width: 10vw;
|
||||||
|
87
public/src/js/abstractfile.js
Normal file
87
public/src/js/abstractfile.js
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
class RemoteFile{
|
||||||
|
constructor(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.arrayBuffer().then(response =>
|
||||||
|
new TextDecoder(encoding).decode(response)
|
||||||
|
)
|
||||||
|
}else{
|
||||||
|
return loader.ajax(this.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class LocalFile{
|
||||||
|
constructor(file){
|
||||||
|
this.file = file
|
||||||
|
this.path = file.webkitRelativePath
|
||||||
|
this.url = this.path
|
||||||
|
this.name = file.name
|
||||||
|
}
|
||||||
|
arrayBuffer(){
|
||||||
|
var reader = new FileReader()
|
||||||
|
var promise = pageEvents.load(reader).then(event => event.target.result)
|
||||||
|
reader.readAsArrayBuffer(this.file)
|
||||||
|
return promise
|
||||||
|
}
|
||||||
|
read(encoding){
|
||||||
|
var reader = new FileReader()
|
||||||
|
var promise = pageEvents.load(reader).then(event => event.target.result)
|
||||||
|
reader.readAsText(this.file, encoding)
|
||||||
|
return promise
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class GdriveFile{
|
||||||
|
constructor(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.arrayBuffer().then(response =>
|
||||||
|
new TextDecoder(encoding).decode(response)
|
||||||
|
)
|
||||||
|
}else{
|
||||||
|
return gpicker.downloadFile(this.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class CachedFile{
|
||||||
|
constructor(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()
|
||||||
|
}
|
||||||
|
}
|
@ -33,7 +33,9 @@ var assets = {
|
|||||||
"settings.js",
|
"settings.js",
|
||||||
"scorestorage.js",
|
"scorestorage.js",
|
||||||
"account.js",
|
"account.js",
|
||||||
"lyrics.js"
|
"lyrics.js",
|
||||||
|
"customsongs.js",
|
||||||
|
"abstractfile.js"
|
||||||
],
|
],
|
||||||
"css": [
|
"css": [
|
||||||
"main.css",
|
"main.css",
|
||||||
@ -144,7 +146,8 @@ var assets = {
|
|||||||
"session.html",
|
"session.html",
|
||||||
"settings.html",
|
"settings.html",
|
||||||
"account.html",
|
"account.html",
|
||||||
"login.html"
|
"login.html",
|
||||||
|
"customsongs.html"
|
||||||
],
|
],
|
||||||
|
|
||||||
"songs": [],
|
"songs": [],
|
||||||
|
@ -246,23 +246,15 @@ class Controller{
|
|||||||
var songObj = assets.songs.find(song => song.id === this.selectedSong.folder)
|
var songObj = assets.songs.find(song => song.id === this.selectedSong.folder)
|
||||||
var promises = []
|
var promises = []
|
||||||
if(songObj.chart && songObj.chart !== "blank"){
|
if(songObj.chart && songObj.chart !== "blank"){
|
||||||
var reader = new FileReader()
|
promises.push(songObj.chart.read(this.selectedSong.type === "tja" ? "sjis" : undefined).then(data => {
|
||||||
promises.push(pageEvents.load(reader).then(event => {
|
this.songData = data.replace(/\0/g, "").split("\n")
|
||||||
this.songData = event.target.result.replace(/\0/g, "").split("\n")
|
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
}))
|
}))
|
||||||
if(this.selectedSong.type === "tja"){
|
|
||||||
reader.readAsText(songObj.chart, "sjis")
|
|
||||||
}else{
|
|
||||||
reader.readAsText(songObj.chart)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(songObj.lyricsFile){
|
if(songObj.lyricsFile){
|
||||||
var reader = new FileReader()
|
promises.push(songObj.lyricsFile.read().then(event => {
|
||||||
promises.push(pageEvents.load(reader).then(event => {
|
|
||||||
songObj.lyricsData = event.target.result
|
songObj.lyricsData = event.target.result
|
||||||
}, () => Promise.resolve()), songObj.lyricsFile.webkitRelativePath)
|
}, () => Promise.resolve()), songObj.lyricsFile.path)
|
||||||
reader.readAsText(songObj.lyricsFile)
|
|
||||||
}
|
}
|
||||||
Promise.all(promises).then(resolve)
|
Promise.all(promises).then(resolve)
|
||||||
}
|
}
|
||||||
|
216
public/src/js/customsongs.js
Normal file
216
public/src/js/customsongs.js
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
class CustomSongs{
|
||||||
|
constructor(touchEnabled){
|
||||||
|
this.touchEnabled = touchEnabled
|
||||||
|
loader.changePage("customsongs", true)
|
||||||
|
if(touchEnabled){
|
||||||
|
this.getElement("view-outer").classList.add("touch-enabled")
|
||||||
|
}
|
||||||
|
this.locked = false
|
||||||
|
|
||||||
|
var tutorialTitle = this.getElement("view-title")
|
||||||
|
this.setAltText(tutorialTitle, strings.customSongs.title)
|
||||||
|
|
||||||
|
var tutorialContent = this.getElement("view-content")
|
||||||
|
strings.customSongs.description.forEach(string => {
|
||||||
|
tutorialContent.appendChild(document.createTextNode(string))
|
||||||
|
tutorialContent.appendChild(document.createElement("br"))
|
||||||
|
})
|
||||||
|
|
||||||
|
this.items = []
|
||||||
|
this.linkLocalFolder = document.getElementById("link-localfolder")
|
||||||
|
this.hasLocal = "webkitdirectory" in HTMLInputElement.prototype && !(/Android/.test(navigator.userAgent))
|
||||||
|
if(this.hasLocal){
|
||||||
|
this.browse = document.getElementById("browse")
|
||||||
|
pageEvents.add(this.browse, "change", this.browseChange.bind(this))
|
||||||
|
this.setAltText(this.linkLocalFolder, strings.customSongs.localFolder)
|
||||||
|
pageEvents.add(this.linkLocalFolder, ["mousedown", "touchstart"], this.localFolder.bind(this))
|
||||||
|
this.items.push(this.linkLocalFolder)
|
||||||
|
}else{
|
||||||
|
this.linkLocalFolder.parentNode.removeChild(this.linkLocalFolder)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.linkGdriveFolder = document.getElementById("link-gdrivefolder")
|
||||||
|
if(gameConfig.google_credentials.gdrive_enabled){
|
||||||
|
this.setAltText(this.linkGdriveFolder, strings.customSongs.gdriveFolder)
|
||||||
|
pageEvents.add(this.linkGdriveFolder, ["mousedown", "touchstart"], this.gdriveFolder.bind(this))
|
||||||
|
this.items.push(this.linkGdriveFolder)
|
||||||
|
}else{
|
||||||
|
this.linkGdriveFolder.parentNode.removeChild(this.linkGdriveFolder)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.endButton = this.getElement("view-end-button")
|
||||||
|
this.setAltText(this.endButton, strings.session.cancel)
|
||||||
|
pageEvents.add(this.endButton, ["mousedown", "touchstart"], this.onEnd.bind(this))
|
||||||
|
this.items.push(this.endButton)
|
||||||
|
this.selected = this.items.length - 1
|
||||||
|
|
||||||
|
this.loaderDiv = document.createElement("div")
|
||||||
|
this.loaderDiv.innerHTML = assets.pages["loadsong"]
|
||||||
|
var loadingText = this.loaderDiv.querySelector("#loading-text")
|
||||||
|
loadingText.appendChild(document.createTextNode(strings.loading))
|
||||||
|
loadingText.setAttribute("alt", strings.loading)
|
||||||
|
|
||||||
|
this.keyboard = new Keyboard({
|
||||||
|
confirm: ["enter", "space", "don_l", "don_r"],
|
||||||
|
previous: ["left", "up", "ka_l"],
|
||||||
|
next: ["right", "down", "ka_r"],
|
||||||
|
back: ["escape"]
|
||||||
|
}, this.keyPressed.bind(this))
|
||||||
|
this.gamepad = new Gamepad({
|
||||||
|
confirmPad: ["b", "ls", "rs"],
|
||||||
|
previous: ["u", "l", "lb", "lt", "lsu", "lsl"],
|
||||||
|
next: ["d", "r", "rb", "rt", "lsd", "lsr"],
|
||||||
|
back: ["start", "a"]
|
||||||
|
}, this.keyPressed.bind(this))
|
||||||
|
|
||||||
|
pageEvents.send("custom-songs")
|
||||||
|
}
|
||||||
|
getElement(name){
|
||||||
|
return loader.screen.getElementsByClassName(name)[0]
|
||||||
|
}
|
||||||
|
setAltText(element, text){
|
||||||
|
element.innerText = text
|
||||||
|
element.setAttribute("alt", text)
|
||||||
|
}
|
||||||
|
localFolder(){
|
||||||
|
if(this.locked){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.browse.click()
|
||||||
|
}
|
||||||
|
browseChange(event){
|
||||||
|
var files = []
|
||||||
|
for(var i = 0; i < event.target.files.length; i++){
|
||||||
|
files.push(new LocalFile(event.target.files[i]))
|
||||||
|
}
|
||||||
|
if(!files.length){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.locked = true
|
||||||
|
this.loading(true)
|
||||||
|
|
||||||
|
var importSongs = new ImportSongs()
|
||||||
|
importSongs.load(files).then(this.songsLoaded.bind(this), e => {
|
||||||
|
this.browse.parentNode.reset()
|
||||||
|
this.locked = false
|
||||||
|
this.loading(false)
|
||||||
|
if(e !== "cancel"){
|
||||||
|
return Promise.reject(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
gdriveFolder(){
|
||||||
|
if(this.locked){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.locked = true
|
||||||
|
this.loading(true)
|
||||||
|
var importSongs = new ImportSongs(true)
|
||||||
|
if(!gpicker){
|
||||||
|
var gpickerPromise = loader.loadScript("/src/js/gpicker.js").then(() => {
|
||||||
|
gpicker = new Gpicker()
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
var gpickerPromise = Promise.resolve()
|
||||||
|
}
|
||||||
|
gpickerPromise.then(() => {
|
||||||
|
return gpicker.browse(locked => {
|
||||||
|
this.locked = locked
|
||||||
|
this.loading(locked)
|
||||||
|
})
|
||||||
|
}).then(files => importSongs.load(files))
|
||||||
|
.then(this.songsLoaded.bind(this))
|
||||||
|
.catch(e => {
|
||||||
|
this.locked = false
|
||||||
|
this.loading(false)
|
||||||
|
if(e !== "cancel"){
|
||||||
|
return Promise.reject(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
loading(show){
|
||||||
|
if(show){
|
||||||
|
loader.screen.appendChild(this.loaderDiv)
|
||||||
|
}else{
|
||||||
|
loader.screen.removeChild(this.loaderDiv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
songsLoaded(songs){
|
||||||
|
var length = songs.length
|
||||||
|
assets.songs = songs
|
||||||
|
assets.customSongs = true
|
||||||
|
assets.customSelected = 0
|
||||||
|
assets.sounds["se_don"].play()
|
||||||
|
this.clean()
|
||||||
|
setTimeout(() => {
|
||||||
|
new SongSelect("customSongs", false, this.touchEnabled)
|
||||||
|
pageEvents.send("import-songs", length)
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
keyPressed(pressed, name){
|
||||||
|
if(!pressed || this.locked){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var selected = this.items[this.selected]
|
||||||
|
if(name === "confirm" || name === "confirmPad"){
|
||||||
|
if(selected === this.endButton){
|
||||||
|
this.onEnd()
|
||||||
|
}else if(name !== "confirmPad"){
|
||||||
|
if(selected === this.linkLocalFolder){
|
||||||
|
assets.sounds["se_don"].play()
|
||||||
|
this.localFolder()
|
||||||
|
}else if(selected === this.linkGdriveFolder){
|
||||||
|
assets.sounds["se_don"].play()
|
||||||
|
this.gdriveFolder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else if(name === "previous" || name === "next"){
|
||||||
|
selected.classList.remove("selected")
|
||||||
|
this.selected = this.mod(this.items.length, this.selected + (name === "next" ? 1 : -1))
|
||||||
|
this.items[this.selected].classList.add("selected")
|
||||||
|
assets.sounds["se_ka"].play()
|
||||||
|
}else if(name === "back"){
|
||||||
|
this.onEnd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mod(length, index){
|
||||||
|
return ((index % length) + length) % length
|
||||||
|
}
|
||||||
|
onEnd(event){
|
||||||
|
if(this.locked){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var touched = false
|
||||||
|
if(event){
|
||||||
|
if(event.type === "touchstart"){
|
||||||
|
event.preventDefault()
|
||||||
|
touched = true
|
||||||
|
}else if(event.which !== 1){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.clean()
|
||||||
|
assets.sounds["se_don"].play()
|
||||||
|
setTimeout(() => {
|
||||||
|
new SongSelect("customSongs", false, touched)
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
clean(){
|
||||||
|
this.keyboard.clean()
|
||||||
|
this.gamepad.clean()
|
||||||
|
pageEvents.remove(this.browse, "change")
|
||||||
|
if(this.hasLocal){
|
||||||
|
pageEvents.remove(this.linkLocalFolder, ["mousedown", "touchstart"])
|
||||||
|
}
|
||||||
|
if(gameConfig.google_credentials.gdrive_enabled){
|
||||||
|
pageEvents.remove(this.linkGdriveFolder, ["mousedown", "touchstart"])
|
||||||
|
}
|
||||||
|
pageEvents.remove(this.endButton, ["mousedown", "touchstart"])
|
||||||
|
delete this.browse
|
||||||
|
delete this.linkLocalFolder
|
||||||
|
delete this.linkGdriveFolder
|
||||||
|
delete this.endButton
|
||||||
|
delete this.items
|
||||||
|
delete this.loaderDiv
|
||||||
|
}
|
||||||
|
}
|
185
public/src/js/gpicker.js
Normal file
185
public/src/js/gpicker.js
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
class Gpicker{
|
||||||
|
constructor(){
|
||||||
|
this.apiKey = gameConfig.google_credentials.api_key
|
||||||
|
this.oauthClientId = gameConfig.google_credentials.oauth_client_id
|
||||||
|
this.projectNumber = gameConfig.google_credentials.project_number
|
||||||
|
this.scope = "https://www.googleapis.com/auth/drive.readonly"
|
||||||
|
this.folder = "application/vnd.google-apps.folder"
|
||||||
|
this.filesUrl = "https://www.googleapis.com/drive/v3/files/"
|
||||||
|
this.resolveQueue = []
|
||||||
|
this.queueActive = false
|
||||||
|
}
|
||||||
|
browse(lockedCallback){
|
||||||
|
return this.loadApi()
|
||||||
|
.then(() => this.getToken(lockedCallback))
|
||||||
|
.then(() => new Promise((resolve, reject) => {
|
||||||
|
this.displayPicker(data => {
|
||||||
|
if(data.action === "picked"){
|
||||||
|
var file = data.docs[0]
|
||||||
|
var walk = (files, output=[]) => {
|
||||||
|
var batch = null
|
||||||
|
for(var i = 0; i < files.length; i++){
|
||||||
|
var path = files[i].path ? files[i].path + "/" : ""
|
||||||
|
var list = files[i].list
|
||||||
|
for(var j = 0; j < list.length; j++){
|
||||||
|
var file = list[j]
|
||||||
|
if(file.mimeType === this.folder){
|
||||||
|
if(!batch){
|
||||||
|
batch = gapi.client.newBatch()
|
||||||
|
}
|
||||||
|
batch.add(gapi.client.drive.files.list({
|
||||||
|
q: "'" + file.id + "' in parents",
|
||||||
|
orderBy: "name_natural"
|
||||||
|
}), {
|
||||||
|
id: path + file.name
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
output.push(new GdriveFile({
|
||||||
|
path: path + file.name,
|
||||||
|
name: file.name,
|
||||||
|
id: file.id
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(batch){
|
||||||
|
return this.queue()
|
||||||
|
.then(() => batch.then(responses => {
|
||||||
|
var files = []
|
||||||
|
for(var path in responses.result){
|
||||||
|
files.push({path: path, list: responses.result[path].result.files})
|
||||||
|
}
|
||||||
|
return walk(files, output)
|
||||||
|
}))
|
||||||
|
}else{
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(file.mimeType === this.folder){
|
||||||
|
return walk([{list: [file]}]).then(resolve, reject)
|
||||||
|
}else{
|
||||||
|
return reject("cancel")
|
||||||
|
}
|
||||||
|
}else if(data.action === "cancel"){
|
||||||
|
return reject("cancel")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
loadApi(){
|
||||||
|
if(window.gapi && gapi.client && gapi.client.drive){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return loader.loadScript("https://apis.google.com/js/api.js")
|
||||||
|
.then(() => new Promise((resolve, reject) =>
|
||||||
|
gapi.load("auth2:picker:client", {
|
||||||
|
callback: resolve,
|
||||||
|
onerror: reject
|
||||||
|
})
|
||||||
|
))
|
||||||
|
.then(() => new Promise((resolve, reject) =>
|
||||||
|
gapi.client.load("drive", "v3").then(resolve, reject)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
getToken(lockedCallback){
|
||||||
|
if(this.oauthToken){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(!this.auth){
|
||||||
|
var authPromise = gapi.auth2.init({
|
||||||
|
clientId: this.oauthClientId,
|
||||||
|
fetch_basic_profile: false,
|
||||||
|
scope: this.scope
|
||||||
|
}).then(() => {
|
||||||
|
this.auth = gapi.auth2.getAuthInstance()
|
||||||
|
}, e => {
|
||||||
|
if(e.details){
|
||||||
|
alert(strings.gpicker.authError.replace("%s", e.details))
|
||||||
|
}
|
||||||
|
return Promise.reject(e)
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
var authPromise = Promise.resolve()
|
||||||
|
}
|
||||||
|
return authPromise.then(() => {
|
||||||
|
var user = this.auth.currentUser.get()
|
||||||
|
if(!this.checkScope(user)){
|
||||||
|
lockedCallback(false)
|
||||||
|
this.auth.signIn().then(user => {
|
||||||
|
if(this.checkScope(user)){
|
||||||
|
lockedCallback(true)
|
||||||
|
}else{
|
||||||
|
return Promise.reject("cancel")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
checkScope(user){
|
||||||
|
if(user.hasGrantedScopes(this.scope)){
|
||||||
|
this.oauthToken = user.getAuthResponse(true).access_token
|
||||||
|
return this.oauthToken
|
||||||
|
}else{
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
displayPicker(callback){
|
||||||
|
var picker = gapi.picker.api
|
||||||
|
new picker.PickerBuilder()
|
||||||
|
.setDeveloperKey(this.apiKey)
|
||||||
|
.setAppId(this.projectNumber)
|
||||||
|
.setOAuthToken(this.oauthToken)
|
||||||
|
.hideTitleBar()
|
||||||
|
.addView(new picker.DocsView("folders")
|
||||||
|
.setLabel(strings.gpicker.myDrive)
|
||||||
|
.setParent("root")
|
||||||
|
.setSelectFolderEnabled(true)
|
||||||
|
.setMode("grid")
|
||||||
|
)
|
||||||
|
.addView(new picker.DocsView("folders")
|
||||||
|
.setLabel(strings.gpicker.starred)
|
||||||
|
.setStarred(true)
|
||||||
|
.setSelectFolderEnabled(true)
|
||||||
|
.setMode("grid")
|
||||||
|
)
|
||||||
|
.addView(new picker.DocsView("folders")
|
||||||
|
.setLabel(strings.gpicker.sharedWithMe)
|
||||||
|
.setOwnedByMe(false)
|
||||||
|
.setSelectFolderEnabled(true)
|
||||||
|
.setMode("list")
|
||||||
|
)
|
||||||
|
.setCallback(callback)
|
||||||
|
.setSize(Infinity, Infinity)
|
||||||
|
.build()
|
||||||
|
.setVisible(true)
|
||||||
|
}
|
||||||
|
downloadFile(id, arrayBuffer){
|
||||||
|
return this.queue().then(() =>
|
||||||
|
loader.ajax(this.filesUrl + id + "?alt=media", request => {
|
||||||
|
if(arrayBuffer){
|
||||||
|
request.responseType = "arraybuffer"
|
||||||
|
}
|
||||||
|
request.setRequestHeader("Authorization", "Bearer " + this.oauthToken)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
queue(){
|
||||||
|
return new Promise(resolve => {
|
||||||
|
this.resolveQueue.push(resolve)
|
||||||
|
if(!this.queueActive){
|
||||||
|
this.queueActive = true
|
||||||
|
this.queueTimer = setInterval(this.parseQueue.bind(this), 100)
|
||||||
|
this.parseQueue()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
parseQueue(){
|
||||||
|
if(this.resolveQueue.length){
|
||||||
|
var resolve = this.resolveQueue.shift()
|
||||||
|
resolve()
|
||||||
|
}else{
|
||||||
|
this.queueActive = false
|
||||||
|
clearInterval(this.queueTimer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,32 +1,10 @@
|
|||||||
class ImportSongs{
|
class ImportSongs{
|
||||||
constructor(songSelect, event){
|
constructor(limited, otherFiles){
|
||||||
this.songSelect = songSelect
|
this.limited = limited
|
||||||
this.songSelect.redrawRunning = false
|
|
||||||
this.songSelect.pointer(false)
|
|
||||||
|
|
||||||
this.loaderDiv = document.createElement("div")
|
|
||||||
this.loaderDiv.innerHTML = assets.pages["loadsong"]
|
|
||||||
loader.screen.appendChild(this.loaderDiv)
|
|
||||||
var loadingText = document.getElementById("loading-text")
|
|
||||||
loadingText.appendChild(document.createTextNode(strings.loading))
|
|
||||||
loadingText.setAttribute("alt", strings.loading)
|
|
||||||
|
|
||||||
var files = []
|
|
||||||
for(var i = 0; i < event.target.files.length; i++){
|
|
||||||
files.push(event.target.files[i])
|
|
||||||
}
|
|
||||||
var extensionRegex = /\.[^\/]+$/
|
|
||||||
files.sort((a, b) => {
|
|
||||||
var path1 = a.webkitRelativePath.replace(extensionRegex, "")
|
|
||||||
var path2 = b.webkitRelativePath.replace(extensionRegex, "")
|
|
||||||
return path1 > path2 ? 1 : -1
|
|
||||||
})
|
|
||||||
|
|
||||||
this.tjaFiles = []
|
this.tjaFiles = []
|
||||||
this.osuFiles = []
|
this.osuFiles = []
|
||||||
this.assetFiles = {}
|
this.assetFiles = {}
|
||||||
var metaFiles = []
|
this.otherFiles = otherFiles || {}
|
||||||
this.otherFiles = {}
|
|
||||||
this.songs = []
|
this.songs = []
|
||||||
this.stylesheet = []
|
this.stylesheet = []
|
||||||
this.songTitle = {}
|
this.songTitle = {}
|
||||||
@ -38,7 +16,6 @@
|
|||||||
"oni": 3,
|
"oni": 3,
|
||||||
"ura": 4
|
"ura": 4
|
||||||
}
|
}
|
||||||
|
|
||||||
this.categoryAliases = {}
|
this.categoryAliases = {}
|
||||||
assets.categories.forEach(cat => {
|
assets.categories.forEach(cat => {
|
||||||
this.categoryAliases[cat.title.toLowerCase()] = cat.id
|
this.categoryAliases[cat.title.toLowerCase()] = cat.id
|
||||||
@ -53,7 +30,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.assetSelectors = {
|
this.assetSelectors = {
|
||||||
"bg-pattern-1": ".pattern-bg",
|
"bg-pattern-1": ".pattern-bg",
|
||||||
"bg_genre_0": "#song-select",
|
"bg_genre_0": "#song-select",
|
||||||
@ -66,11 +42,20 @@
|
|||||||
"bg_stage_2": ".song-stage-2",
|
"bg_stage_2": ".song-stage-2",
|
||||||
"bg_stage_3": ".song-stage-3"
|
"bg_stage_3": ".song-stage-3"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
load(files){
|
||||||
|
var extensionRegex = /\.[^\/]+$/
|
||||||
|
files.sort((a, b) => {
|
||||||
|
var path1 = a.path.replace(extensionRegex, "")
|
||||||
|
var path2 = b.path.replace(extensionRegex, "")
|
||||||
|
return path1 > path2 ? 1 : -1
|
||||||
|
})
|
||||||
|
|
||||||
|
var metaFiles = []
|
||||||
for(var i = 0; i < files.length; i++){
|
for(var i = 0; i < files.length; i++){
|
||||||
var file = files[i]
|
var file = files[i]
|
||||||
var name = file.name.toLowerCase()
|
var name = file.name.toLowerCase()
|
||||||
var path = file.webkitRelativePath.toLowerCase()
|
var path = file.path.toLowerCase()
|
||||||
if(name.endsWith(".tja")){
|
if(name.endsWith(".tja")){
|
||||||
this.tjaFiles.push({
|
this.tjaFiles.push({
|
||||||
file: file,
|
file: file,
|
||||||
@ -81,13 +66,13 @@
|
|||||||
file: file,
|
file: file,
|
||||||
index: i
|
index: i
|
||||||
})
|
})
|
||||||
}else if(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.webkitRelativePath.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(path.indexOf("/taiko-web assets/") !== -1){
|
}else if(!this.limited && path.indexOf("/taiko-web assets/") !== -1){
|
||||||
if(!(name in this.assetFiles)){
|
if(!(name in this.assetFiles)){
|
||||||
this.assetFiles[name] = file
|
this.assetFiles[name] = file
|
||||||
}
|
}
|
||||||
@ -97,32 +82,30 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
var metaPromises = []
|
var metaPromises = []
|
||||||
|
|
||||||
metaFiles.forEach(fileObj => {
|
metaFiles.forEach(fileObj => {
|
||||||
metaPromises.push(this.addMeta(fileObj))
|
metaPromises.push(this.addMeta(fileObj))
|
||||||
})
|
})
|
||||||
|
|
||||||
Promise.all(metaPromises).then(() => {
|
return Promise.all(metaPromises).then(() => {
|
||||||
var songPromises = []
|
var songPromises = []
|
||||||
|
|
||||||
this.tjaFiles.forEach(fileObj => {
|
this.tjaFiles.forEach(fileObj => {
|
||||||
songPromises.push(this.addTja(fileObj))
|
songPromises.push(this.addTja(fileObj).catch(e => console.warn(e)))
|
||||||
})
|
})
|
||||||
this.osuFiles.forEach(fileObj => {
|
this.osuFiles.forEach(fileObj => {
|
||||||
songPromises.push(this.addOsu(fileObj))
|
songPromises.push(this.addOsu(fileObj).catch(e => console.warn(e)))
|
||||||
})
|
})
|
||||||
songPromises.push(this.addAssets())
|
songPromises.push(this.addAssets())
|
||||||
Promise.all(songPromises).then(this.loaded.bind(this))
|
return Promise.all(songPromises)
|
||||||
})
|
}).then(this.loaded.bind(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
addMeta(fileObj){
|
addMeta(fileObj){
|
||||||
var file = fileObj.file
|
var file = fileObj.file
|
||||||
var level = fileObj.level
|
var level = fileObj.level
|
||||||
var name = file.name.toLowerCase()
|
var name = file.name.toLowerCase()
|
||||||
var reader = new FileReader()
|
return file.read(name === "songtitle.txt" ? undefined : "sjis").then(data => {
|
||||||
var promise = pageEvents.load(reader).then(event => {
|
var data = data.replace(/\0/g, "").split("\n")
|
||||||
var data = event.target.result.replace(/\0/g, "").split("\n")
|
|
||||||
var category
|
var category
|
||||||
if(name === "genre.ini"){
|
if(name === "genre.ini"){
|
||||||
var key
|
var key
|
||||||
@ -177,9 +160,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(category){
|
if(category){
|
||||||
var metaPath = file.webkitRelativePath.toLowerCase().slice(0, file.name.length * -1)
|
var metaPath = file.path.toLowerCase().slice(0, file.name.length * -1)
|
||||||
var filesLoop = fileObj => {
|
var filesLoop = fileObj => {
|
||||||
var tjaPath = fileObj.file.webkitRelativePath.toLowerCase().slice(0, fileObj.file.name.length * -1)
|
var tjaPath = fileObj.file.path.toLowerCase().slice(0, fileObj.file.name.length * -1)
|
||||||
if(tjaPath.startsWith(metaPath) && (!("categoryLevel" in fileObj) || fileObj.categoryLevel < level)){
|
if(tjaPath.startsWith(metaPath) && (!("categoryLevel" in fileObj) || fileObj.categoryLevel < level)){
|
||||||
if(category.toLowerCase() in this.categoryAliases){
|
if(category.toLowerCase() in this.categoryAliases){
|
||||||
fileObj.category_id = this.categoryAliases[category.toLowerCase()]
|
fileObj.category_id = this.categoryAliases[category.toLowerCase()]
|
||||||
@ -192,13 +175,9 @@
|
|||||||
this.tjaFiles.forEach(filesLoop)
|
this.tjaFiles.forEach(filesLoop)
|
||||||
this.osuFiles.forEach(filesLoop)
|
this.osuFiles.forEach(filesLoop)
|
||||||
}
|
}
|
||||||
}).catch(() => {})
|
}).catch(e => {
|
||||||
if(name === "songtitle.txt"){
|
console.warn(e)
|
||||||
reader.readAsText(file)
|
})
|
||||||
}else{
|
|
||||||
reader.readAsText(file, "sjis")
|
|
||||||
}
|
|
||||||
return promise
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addTja(fileObj){
|
addTja(fileObj){
|
||||||
@ -206,24 +185,33 @@
|
|||||||
var index = fileObj.index
|
var index = fileObj.index
|
||||||
var category = fileObj.category
|
var category = fileObj.category
|
||||||
var category_id = fileObj.category_id
|
var category_id = fileObj.category_id
|
||||||
var reader = new FileReader()
|
if(!this.limited){
|
||||||
var promise = pageEvents.load(reader).then(event => {
|
var filePromise = file.read("sjis")
|
||||||
var data = event.target.result.replace(/\0/g, "").split("\n")
|
}else{
|
||||||
|
var filePromise = Promise.resolve()
|
||||||
|
}
|
||||||
|
return filePromise.then(dataRaw => {
|
||||||
|
var data = dataRaw ? dataRaw.replace(/\0/g, "").split("\n") : []
|
||||||
var tja = new ParseTja(data, "oni", 0, 0, true)
|
var tja = new ParseTja(data, "oni", 0, 0, true)
|
||||||
var songObj = {
|
var songObj = {
|
||||||
id: index + 1,
|
id: index + 1,
|
||||||
order: index + 1,
|
order: index + 1,
|
||||||
|
title: file.name.slice(0, file.name.lastIndexOf(".")),
|
||||||
type: "tja",
|
type: "tja",
|
||||||
chart: file,
|
chart: file,
|
||||||
courses: {},
|
courses: {},
|
||||||
music: "muted"
|
music: "muted",
|
||||||
|
custom: true
|
||||||
|
}
|
||||||
|
if(this.limited){
|
||||||
|
songObj.unloaded = true
|
||||||
}
|
}
|
||||||
var coursesAdded = false
|
var coursesAdded = false
|
||||||
var titleLang = {}
|
var titleLang = {}
|
||||||
var titleLangAdded = false
|
var titleLangAdded = false
|
||||||
var subtitleLangAdded = false
|
var subtitleLangAdded = false
|
||||||
var subtitleLang = {}
|
var subtitleLang = {}
|
||||||
var dir = file.webkitRelativePath.toLowerCase()
|
var dir = file.path.toLowerCase()
|
||||||
dir = dir.slice(0, dir.lastIndexOf("/") + 1)
|
dir = dir.slice(0, dir.lastIndexOf("/") + 1)
|
||||||
for(var diff in tja.metadata){
|
for(var diff in tja.metadata){
|
||||||
var meta = tja.metadata[diff]
|
var meta = tja.metadata[diff]
|
||||||
@ -321,19 +309,19 @@
|
|||||||
songObj.category_id = category_id
|
songObj.category_id = category_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(coursesAdded){
|
if(coursesAdded || songObj.unloaded){
|
||||||
this.songs[index] = songObj
|
this.songs[index] = songObj
|
||||||
}
|
}
|
||||||
var hash = md5.base64(event.target.result).slice(0, -2)
|
if(!this.limited){
|
||||||
songObj.hash = hash
|
var hash = md5.base64(dataRaw).slice(0, -2)
|
||||||
scoreStorage.songTitles[songObj.title] = hash
|
songObj.hash = hash
|
||||||
var score = scoreStorage.get(hash, false, true)
|
scoreStorage.songTitles[songObj.title] = hash
|
||||||
if(score){
|
var score = scoreStorage.get(hash, false, true)
|
||||||
score.title = songObj.title
|
if(score){
|
||||||
|
score.title = songObj.title
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}).catch(() => {})
|
})
|
||||||
reader.readAsText(file, "sjis")
|
|
||||||
return promise
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addOsu(fileObj){
|
addOsu(fileObj){
|
||||||
@ -341,11 +329,15 @@
|
|||||||
var index = fileObj.index
|
var index = fileObj.index
|
||||||
var category = fileObj.category
|
var category = fileObj.category
|
||||||
var category_id = fileObj.category_id
|
var category_id = fileObj.category_id
|
||||||
var reader = new FileReader()
|
if(!this.limited){
|
||||||
var promise = pageEvents.load(reader).then(event => {
|
var filePromise = file.read()
|
||||||
var data = event.target.result.replace(/\0/g, "").split("\n")
|
}else{
|
||||||
var osu = new ParseOsu(data, "oni", 0, 0, true);
|
var filePromise = Promise.resolve()
|
||||||
var dir = file.webkitRelativePath.toLowerCase()
|
}
|
||||||
|
return filePromise.then(dataRaw => {
|
||||||
|
var data = dataRaw ? dataRaw.replace(/\0/g, "").split("\n") : []
|
||||||
|
var osu = new ParseOsu(data, "oni", 0, 0, true)
|
||||||
|
var dir = file.path.toLowerCase()
|
||||||
dir = dir.slice(0, dir.lastIndexOf("/") + 1)
|
dir = dir.slice(0, dir.lastIndexOf("/") + 1)
|
||||||
var songObj = {
|
var songObj = {
|
||||||
id: index + 1,
|
id: index + 1,
|
||||||
@ -356,14 +348,17 @@
|
|||||||
subtitle_lang: {
|
subtitle_lang: {
|
||||||
en: osu.metadata.Artist || osu.metadata.ArtistUnicode
|
en: osu.metadata.Artist || osu.metadata.ArtistUnicode
|
||||||
},
|
},
|
||||||
preview: osu.generalInfo.PreviewTime / 1000,
|
preview: osu.generalInfo.PreviewTime ? osu.generalInfo.PreviewTime / 1000 : 0,
|
||||||
courses: {
|
courses: {},
|
||||||
oni:{
|
music: (osu.generalInfo.AudioFilename ? this.otherFiles[dir + osu.generalInfo.AudioFilename.toLowerCase()] : "") || "muted"
|
||||||
stars: parseInt(osu.difficulty.overallDifficulty) || 0,
|
}
|
||||||
branch: false
|
if(!this.limited){
|
||||||
}
|
songObj.courses.oni = {
|
||||||
},
|
stars: parseInt(osu.difficulty.overallDifficulty) || 0,
|
||||||
music: this.otherFiles[dir + osu.generalInfo.AudioFilename.toLowerCase()] || "muted"
|
branch: false
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
songObj.unloaded = true
|
||||||
}
|
}
|
||||||
var filename = file.name.slice(0, file.name.lastIndexOf("."))
|
var filename = file.name.slice(0, file.name.lastIndexOf("."))
|
||||||
var title = osu.metadata.TitleUnicode || osu.metadata.Title || file.name.slice(0, file.name.lastIndexOf("."))
|
var title = osu.metadata.TitleUnicode || osu.metadata.Title || file.name.slice(0, file.name.lastIndexOf("."))
|
||||||
@ -375,7 +370,7 @@
|
|||||||
}
|
}
|
||||||
songObj.title = title + suffix
|
songObj.title = title + suffix
|
||||||
songObj.title_lang = {
|
songObj.title_lang = {
|
||||||
en: (osu.metadata.Title || osu.metadata.TitleUnicode) + suffix
|
en: (osu.metadata.Title || osu.metadata.TitleUnicode || title) + suffix
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
songObj.title = filename
|
songObj.title = filename
|
||||||
@ -389,72 +384,68 @@
|
|||||||
}else{
|
}else{
|
||||||
songObj.category_id = category_id
|
songObj.category_id = category_id
|
||||||
}
|
}
|
||||||
var hash = md5.base64(event.target.result).slice(0, -2)
|
if(!this.limited){
|
||||||
songObj.hash = hash
|
var hash = md5.base64(dataRaw).slice(0, -2)
|
||||||
scoreStorage.songTitles[songObj.title] = hash
|
songObj.hash = hash
|
||||||
var score = scoreStorage.get(hash, false, true)
|
scoreStorage.songTitles[songObj.title] = hash
|
||||||
if(score){
|
var score = scoreStorage.get(hash, false, true)
|
||||||
score.title = songObj.title
|
if(score){
|
||||||
|
score.title = songObj.title
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}).catch(() => {})
|
})
|
||||||
reader.readAsText(file)
|
|
||||||
return promise
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addAssets(){
|
addAssets(){
|
||||||
return new Promise((resolve, reject) => {
|
var promises = []
|
||||||
var promises = []
|
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]
|
if(name === "vectors.json"){
|
||||||
if(name === "vectors.json"){
|
promises.push(file.read().then(() => response => {
|
||||||
var reader = new FileReader()
|
vectors = JSON.parse(response)
|
||||||
promises.push(pageEvents.load(reader).then(() => response => {
|
}))
|
||||||
vectors = JSON.parse(response)
|
|
||||||
}))
|
|
||||||
reader.readAsText(file)
|
|
||||||
}
|
|
||||||
if(assets.img.indexOf(name) !== -1){
|
|
||||||
let image = document.createElement("img")
|
|
||||||
promises.push(pageEvents.load(image).then(() => {
|
|
||||||
if(id in this.assetSelectors){
|
|
||||||
var selector = this.assetSelectors[id]
|
|
||||||
this.stylesheet.push(selector + '{background-image:url("' + image.src + '")}')
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
image.id = name
|
|
||||||
image.src = URL.createObjectURL(file)
|
|
||||||
loader.assetsDiv.appendChild(image)
|
|
||||||
assets.image[id].parentNode.removeChild(assets.image[id])
|
|
||||||
assets.image[id] = image
|
|
||||||
}
|
|
||||||
if(assets.audioSfx.indexOf(name) !== -1){
|
|
||||||
assets.sounds[id].clean()
|
|
||||||
promises.push(this.loadSound(file, name, snd.sfxGain))
|
|
||||||
}
|
|
||||||
if(assets.audioMusic.indexOf(name) !== -1){
|
|
||||||
assets.sounds[id].clean()
|
|
||||||
promises.push(this.loadSound(file, name, snd.musicGain))
|
|
||||||
}
|
|
||||||
if(assets.audioSfxLR.indexOf(name) !== -1){
|
|
||||||
assets.sounds[id + "_p1"].clean()
|
|
||||||
assets.sounds[id + "_p2"].clean()
|
|
||||||
promises.push(this.loadSound(file, name, snd.sfxGain).then(sound => {
|
|
||||||
assets.sounds[id + "_p1"] = assets.sounds[id].copy(snd.sfxGainL)
|
|
||||||
assets.sounds[id + "_p2"] = assets.sounds[id].copy(snd.sfxGainR)
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
if(assets.audioSfxLoud.indexOf(name) !== -1){
|
|
||||||
assets.sounds[id].clean()
|
|
||||||
promises.push(this.loadSound(file, name, snd.sfxLoudGain))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Promise.all(promises).then(resolve, reject)
|
if(assets.img.indexOf(name) !== -1){
|
||||||
})
|
let image = document.createElement("img")
|
||||||
|
promises.push(pageEvents.load(image).then(() => {
|
||||||
|
if(id in this.assetSelectors){
|
||||||
|
var selector = this.assetSelectors[id]
|
||||||
|
this.stylesheet.push(selector + '{background-image:url("' + image.src + '")}')
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
image.id = name
|
||||||
|
image.src = URL.createObjectURL(file)
|
||||||
|
loader.assetsDiv.appendChild(image)
|
||||||
|
assets.image[id].parentNode.removeChild(assets.image[id])
|
||||||
|
assets.image[id] = image
|
||||||
|
}
|
||||||
|
if(assets.audioSfx.indexOf(name) !== -1){
|
||||||
|
assets.sounds[id].clean()
|
||||||
|
promises.push(this.loadSound(file, name, snd.sfxGain))
|
||||||
|
}
|
||||||
|
if(assets.audioMusic.indexOf(name) !== -1){
|
||||||
|
assets.sounds[id].clean()
|
||||||
|
promises.push(this.loadSound(file, name, snd.musicGain))
|
||||||
|
}
|
||||||
|
if(assets.audioSfxLR.indexOf(name) !== -1){
|
||||||
|
assets.sounds[id + "_p1"].clean()
|
||||||
|
assets.sounds[id + "_p2"].clean()
|
||||||
|
promises.push(this.loadSound(file, name, snd.sfxGain).then(sound => {
|
||||||
|
assets.sounds[id + "_p1"] = assets.sounds[id].copy(snd.sfxGainL)
|
||||||
|
assets.sounds[id + "_p2"] = assets.sounds[id].copy(snd.sfxGainR)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
if(assets.audioSfxLoud.indexOf(name) !== -1){
|
||||||
|
assets.sounds[id].clean()
|
||||||
|
promises.push(this.loadSound(file, name, snd.sfxLoudGain))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.all(promises)
|
||||||
}
|
}
|
||||||
loadSound(file, name, gain){
|
loadSound(file, name, gain){
|
||||||
var id = this.getFilename(name)
|
var id = this.getFilename(name)
|
||||||
return gain.load(file, true).then(sound => {
|
return gain.load(file).then(sound => {
|
||||||
assets.sounds[id] = sound
|
assets.sounds[id] = sound
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -463,7 +454,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
getCategory(file, exclude){
|
getCategory(file, exclude){
|
||||||
var path = file.webkitRelativePath.toLowerCase().split("/")
|
var path = file.path.toLowerCase().split("/")
|
||||||
for(var i = path.length - 2; i >= 0; i--){
|
for(var i = path.length - 2; i >= 0; i--){
|
||||||
var hasTitle = false
|
var hasTitle = false
|
||||||
for(var j in exclude){
|
for(var j in exclude){
|
||||||
@ -532,24 +523,14 @@
|
|||||||
document.head.appendChild(style)
|
document.head.appendChild(style)
|
||||||
}
|
}
|
||||||
if(this.songs.length){
|
if(this.songs.length){
|
||||||
var length = this.songs.length
|
if(this.limited){
|
||||||
assets.songs = this.songs
|
assets.otherFiles = this.otherFiles
|
||||||
assets.customSongs = true
|
}
|
||||||
assets.customSelected = 0
|
return Promise.resolve(this.songs)
|
||||||
assets.sounds["se_don"].play()
|
|
||||||
this.songSelect.clean()
|
|
||||||
setTimeout(() => {
|
|
||||||
loader.screen.removeChild(this.loaderDiv)
|
|
||||||
this.clean()
|
|
||||||
new SongSelect("browse", false, this.songSelect.touchEnabled)
|
|
||||||
pageEvents.send("import-songs", length)
|
|
||||||
}, 500)
|
|
||||||
}else{
|
}else{
|
||||||
loader.screen.removeChild(this.loaderDiv)
|
return Promise.reject("cancel")
|
||||||
this.songSelect.browse.parentNode.reset()
|
|
||||||
this.songSelect.redrawRunning = true
|
|
||||||
this.clean()
|
|
||||||
}
|
}
|
||||||
|
this.clean()
|
||||||
}
|
}
|
||||||
|
|
||||||
joinPath(){
|
joinPath(){
|
||||||
@ -587,7 +568,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
clean(){
|
clean(){
|
||||||
delete this.loaderDiv
|
|
||||||
delete this.songs
|
delete this.songs
|
||||||
delete this.tjaFiles
|
delete this.tjaFiles
|
||||||
delete this.osuFiles
|
delete this.osuFiles
|
||||||
|
@ -25,21 +25,13 @@ class Loader{
|
|||||||
this.loaderPercentage = document.querySelector("#loader .percentage")
|
this.loaderPercentage = document.querySelector("#loader .percentage")
|
||||||
this.loaderProgress = document.querySelector("#loader .progress")
|
this.loaderProgress = document.querySelector("#loader .progress")
|
||||||
|
|
||||||
var queryString = gameConfig._version.commit_short ? "?" + gameConfig._version.commit_short : ""
|
this.queryString = gameConfig._version.commit_short ? "?" + gameConfig._version.commit_short : ""
|
||||||
|
|
||||||
if(gameConfig.custom_js){
|
if(gameConfig.custom_js){
|
||||||
var script = document.createElement("script")
|
this.addPromise(this.loadScript(gameConfig.custom_js), gameConfig.custom_js)
|
||||||
var url = gameConfig.custom_js + queryString
|
|
||||||
this.addPromise(pageEvents.load(script), url)
|
|
||||||
script.src = url
|
|
||||||
document.head.appendChild(script)
|
|
||||||
}
|
}
|
||||||
assets.js.forEach(name => {
|
assets.js.forEach(name => {
|
||||||
var script = document.createElement("script")
|
this.addPromise(this.loadScript("/src/js/" + name), "/src/js/" + name)
|
||||||
var url = "/src/js/" + name + queryString
|
|
||||||
this.addPromise(pageEvents.load(script), url)
|
|
||||||
script.src = url
|
|
||||||
document.head.appendChild(script)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
var pageVersion = versionLink.href
|
var pageVersion = versionLink.href
|
||||||
@ -53,20 +45,19 @@ class Loader{
|
|||||||
gameConfig._version.commit &&
|
gameConfig._version.commit &&
|
||||||
versionLink.href.indexOf(gameConfig._version.commit) === -1
|
versionLink.href.indexOf(gameConfig._version.commit) === -1
|
||||||
){
|
){
|
||||||
// Version in the config does not match version on the page
|
reject("Version on the page and config does not match\n(page: " + pageVersion + ",\nconfig: "+ gameConfig._version.commit + ")")
|
||||||
reject()
|
|
||||||
}
|
}
|
||||||
var cssCount = document.styleSheets.length + assets.css.length
|
var cssCount = document.styleSheets.length + assets.css.length
|
||||||
assets.css.forEach(name => {
|
assets.css.forEach(name => {
|
||||||
var stylesheet = document.createElement("link")
|
var stylesheet = document.createElement("link")
|
||||||
stylesheet.rel = "stylesheet"
|
stylesheet.rel = "stylesheet"
|
||||||
stylesheet.href = "/src/css/" + name + queryString
|
stylesheet.href = "/src/css/" + name + this.queryString
|
||||||
document.head.appendChild(stylesheet)
|
document.head.appendChild(stylesheet)
|
||||||
})
|
})
|
||||||
assets.assetsCss.forEach(name => {
|
assets.assetsCss.forEach(name => {
|
||||||
var stylesheet = document.createElement("link")
|
var stylesheet = document.createElement("link")
|
||||||
stylesheet.rel = "stylesheet"
|
stylesheet.rel = "stylesheet"
|
||||||
stylesheet.href = gameConfig.assets_baseurl + name + queryString
|
stylesheet.href = gameConfig.assets_baseurl + name + this.queryString
|
||||||
document.head.appendChild(stylesheet)
|
document.head.appendChild(stylesheet)
|
||||||
})
|
})
|
||||||
var checkStyles = () => {
|
var checkStyles = () => {
|
||||||
@ -77,7 +68,7 @@ class Loader{
|
|||||||
}
|
}
|
||||||
var interval = setInterval(checkStyles, 100)
|
var interval = setInterval(checkStyles, 100)
|
||||||
checkStyles()
|
checkStyles()
|
||||||
}), "Version on the page and config does not match\n(page: " + pageVersion + ",\nconfig: "+ gameConfig._version.commit + ")")
|
}))
|
||||||
|
|
||||||
for(var name in assets.fonts){
|
for(var name in assets.fonts){
|
||||||
var url = gameConfig.assets_baseurl + "fonts/" + assets.fonts[name]
|
var url = gameConfig.assets_baseurl + "fonts/" + assets.fonts[name]
|
||||||
@ -99,7 +90,7 @@ class Loader{
|
|||||||
|
|
||||||
assets.views.forEach(name => {
|
assets.views.forEach(name => {
|
||||||
var id = this.getFilename(name)
|
var id = this.getFilename(name)
|
||||||
var url = "/src/views/" + name + queryString
|
var url = "/src/views/" + name + this.queryString
|
||||||
this.addPromise(this.ajax(url).then(page => {
|
this.addPromise(this.ajax(url).then(page => {
|
||||||
assets.pages[id] = page
|
assets.pages[id] = page
|
||||||
}), url)
|
}), url)
|
||||||
@ -114,7 +105,7 @@ class Loader{
|
|||||||
cat.songSkin.infoFill = cat.songSkin.info_fill
|
cat.songSkin.infoFill = cat.songSkin.info_fill
|
||||||
delete cat.songSkin.info_fill
|
delete cat.songSkin.info_fill
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
assets.categories.push({
|
assets.categories.push({
|
||||||
title: "default",
|
title: "default",
|
||||||
@ -127,18 +118,17 @@ class Loader{
|
|||||||
})
|
})
|
||||||
}), "/api/categories")
|
}), "/api/categories")
|
||||||
|
|
||||||
this.addPromise(this.ajax("/api/songs").then(songs => {
|
var url = gameConfig.assets_baseurl + "img/vectors.json" + this.queryString
|
||||||
assets.songsDefault = JSON.parse(songs)
|
|
||||||
assets.songs = assets.songsDefault
|
|
||||||
}), "/api/songs")
|
|
||||||
|
|
||||||
var url = gameConfig.assets_baseurl + "img/vectors.json" + queryString
|
|
||||||
this.addPromise(this.ajax(url).then(response => {
|
this.addPromise(this.ajax(url).then(response => {
|
||||||
vectors = JSON.parse(response)
|
vectors = JSON.parse(response)
|
||||||
}), url)
|
}), url)
|
||||||
|
|
||||||
this.afterJSCount =
|
this.afterJSCount =
|
||||||
["blurPerformance"].length +
|
[
|
||||||
|
"/api/songs",
|
||||||
|
"blurPerformance",
|
||||||
|
"categories"
|
||||||
|
].length +
|
||||||
assets.audioSfx.length +
|
assets.audioSfx.length +
|
||||||
assets.audioMusic.length +
|
assets.audioMusic.length +
|
||||||
assets.audioSfxLR.length +
|
assets.audioSfxLR.length +
|
||||||
@ -150,19 +140,49 @@ class Loader{
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.addPromise(this.ajax("/api/songs").then(songs => {
|
||||||
|
songs = JSON.parse(songs)
|
||||||
|
songs.forEach(song => {
|
||||||
|
var directory = gameConfig.songs_baseurl + song.id + "/"
|
||||||
|
song.music = new RemoteFile(directory + "main.mp3")
|
||||||
|
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(gameConfig.songs_baseurl + song.id + "main.vtt")
|
||||||
|
}
|
||||||
|
if(song.preview > 0){
|
||||||
|
song.previewMusic = new RemoteFile(directory + "preview.mp3")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
assets.songsDefault = songs
|
||||||
|
assets.songs = assets.songsDefault
|
||||||
|
}), "/api/songs")
|
||||||
|
|
||||||
|
var categoryPromises = []
|
||||||
assets.categories //load category backgrounds to DOM
|
assets.categories //load category backgrounds to DOM
|
||||||
.filter(cat=>cat.songSkin && cat.songSkin.bg_img)
|
.filter(cat => cat.songSkin && cat.songSkin.bg_img)
|
||||||
.forEach(cat=>{
|
.forEach(cat => {
|
||||||
let name = cat.songSkin.bg_img
|
let name = cat.songSkin.bg_img
|
||||||
var id = this.getFilename(name)
|
var id = this.getFilename(name)
|
||||||
var image = document.createElement("img")
|
var image = document.createElement("img")
|
||||||
var url = gameConfig.assets_baseurl + "img/" + name
|
var url = gameConfig.assets_baseurl + "img/" + name
|
||||||
this.addPromise(pageEvents.load(image), url)
|
categoryPromises.push(pageEvents.load(image).catch(response => {
|
||||||
|
this.errorMsg(response, url)
|
||||||
|
}))
|
||||||
image.id = name
|
image.id = name
|
||||||
image.src = url
|
image.src = url
|
||||||
this.assetsDiv.appendChild(image)
|
this.assetsDiv.appendChild(image)
|
||||||
assets.image[id] = image
|
assets.image[id] = image
|
||||||
})
|
})
|
||||||
|
this.addPromise(Promise.all(categoryPromises))
|
||||||
|
|
||||||
snd.buffer = new SoundBuffer()
|
snd.buffer = new SoundBuffer()
|
||||||
snd.musicGain = snd.buffer.createGain()
|
snd.musicGain = snd.buffer.createGain()
|
||||||
@ -307,7 +327,6 @@ class Loader{
|
|||||||
this.promises.push(promise)
|
this.promises.push(promise)
|
||||||
promise.then(this.assetLoaded.bind(this), response => {
|
promise.then(this.assetLoaded.bind(this), response => {
|
||||||
this.errorMsg(response, url)
|
this.errorMsg(response, url)
|
||||||
return Promise.resolve()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
soundUrl(name){
|
soundUrl(name){
|
||||||
@ -315,7 +334,7 @@ class Loader{
|
|||||||
}
|
}
|
||||||
loadSound(name, gain){
|
loadSound(name, gain){
|
||||||
var id = this.getFilename(name)
|
var id = this.getFilename(name)
|
||||||
return gain.load(this.soundUrl(name)).then(sound => {
|
return gain.load(new RemoteFile(this.soundUrl(name))).then(sound => {
|
||||||
assets.sounds[id] = sound
|
assets.sounds[id] = sound
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -415,21 +434,28 @@ class Loader{
|
|||||||
this.screen.classList[patternBg ? "add" : "remove"]("pattern-bg")
|
this.screen.classList[patternBg ? "add" : "remove"]("pattern-bg")
|
||||||
}
|
}
|
||||||
ajax(url, customRequest){
|
ajax(url, customRequest){
|
||||||
return new Promise((resolve, reject) => {
|
var request = new XMLHttpRequest()
|
||||||
var request = new XMLHttpRequest()
|
request.open("GET", url)
|
||||||
request.open("GET", url)
|
var promise = pageEvents.load(request).then(() => {
|
||||||
pageEvents.load(request).then(() => {
|
if(request.status === 200){
|
||||||
if(request.status === 200){
|
return request.response
|
||||||
resolve(request.response)
|
}else{
|
||||||
}else{
|
return Promise.reject(`${url} (${request.status})`)
|
||||||
reject()
|
|
||||||
}
|
|
||||||
}, reject)
|
|
||||||
if(customRequest){
|
|
||||||
customRequest(request)
|
|
||||||
}
|
}
|
||||||
request.send()
|
|
||||||
})
|
})
|
||||||
|
if(customRequest){
|
||||||
|
customRequest(request)
|
||||||
|
}
|
||||||
|
request.send()
|
||||||
|
return promise
|
||||||
|
}
|
||||||
|
loadScript(url){
|
||||||
|
var script = document.createElement("script")
|
||||||
|
var url = url + this.queryString
|
||||||
|
var promise = pageEvents.load(script)
|
||||||
|
script.src = url
|
||||||
|
document.head.appendChild(script)
|
||||||
|
return promise
|
||||||
}
|
}
|
||||||
getCsrfToken(){
|
getCsrfToken(){
|
||||||
return this.ajax("api/csrftoken").then(response => {
|
return this.ajax("api/csrftoken").then(response => {
|
||||||
|
@ -34,10 +34,10 @@ class LoadSong{
|
|||||||
run(){
|
run(){
|
||||||
var song = this.selectedSong
|
var song = this.selectedSong
|
||||||
var id = song.folder
|
var id = song.folder
|
||||||
|
var songObj
|
||||||
this.promises = []
|
this.promises = []
|
||||||
if(song.folder !== "calibration"){
|
if(id !== "calibration"){
|
||||||
assets.sounds["v_start"].play()
|
assets.sounds["v_start"].play()
|
||||||
var songObj
|
|
||||||
assets.songs.forEach(song => {
|
assets.songs.forEach(song => {
|
||||||
if(song.id === id){
|
if(song.id === id){
|
||||||
songObj = song
|
songObj = song
|
||||||
@ -50,11 +50,12 @@ class LoadSong{
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}else{
|
}else{
|
||||||
var songObj = {
|
songObj = {
|
||||||
"music": "muted",
|
music: "muted",
|
||||||
"chart": "blank"
|
custom: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.songObj = songObj
|
||||||
|
|
||||||
song.songBg = this.randInt(1, 5)
|
song.songBg = this.randInt(1, 5)
|
||||||
song.songStage = this.randInt(1, 3)
|
song.songStage = this.randInt(1, 3)
|
||||||
@ -99,14 +100,14 @@ class LoadSong{
|
|||||||
}
|
}
|
||||||
let img = document.createElement("img")
|
let img = document.createElement("img")
|
||||||
let force = imgLoad[i].type === "song" && this.touchEnabled
|
let force = imgLoad[i].type === "song" && this.touchEnabled
|
||||||
if(!songObj.music && (this.imgScale !== 1 || force)){
|
if(!songObj.custom && (this.imgScale !== 1 || force)){
|
||||||
img.crossOrigin = "Anonymous"
|
img.crossOrigin = "Anonymous"
|
||||||
}
|
}
|
||||||
let promise = pageEvents.load(img)
|
let promise = pageEvents.load(img)
|
||||||
this.addPromise(promise.then(() => {
|
this.addPromise(promise.then(() => {
|
||||||
return this.scaleImg(img, filename, prefix, force)
|
return this.scaleImg(img, filename, prefix, force)
|
||||||
}), songObj.music ? filename + ".png" : skinBase + filename + ".png")
|
}), songObj.custom ? filename + ".png" : skinBase + filename + ".png")
|
||||||
if(songObj.music){
|
if(songObj.custom){
|
||||||
img.src = URL.createObjectURL(song.songSkin[filename + ".png"])
|
img.src = URL.createObjectURL(song.songSkin[filename + ".png"])
|
||||||
}else{
|
}else{
|
||||||
img.src = skinBase + filename + ".png"
|
img.src = skinBase + filename + ".png"
|
||||||
@ -115,57 +116,29 @@ class LoadSong{
|
|||||||
}
|
}
|
||||||
this.loadSongBg(id)
|
this.loadSongBg(id)
|
||||||
|
|
||||||
var url = gameConfig.songs_baseurl + id + "/main.mp3"
|
if(songObj.sound){
|
||||||
this.addPromise(new Promise((resolve, reject) => {
|
songObj.sound.gain = snd.musicGain
|
||||||
if(songObj.sound){
|
}else if(songObj.music !== "muted"){
|
||||||
songObj.sound.gain = snd.musicGain
|
this.addPromise(snd.musicGain.load(songObj.music).then(sound => {
|
||||||
resolve()
|
songObj.sound = sound
|
||||||
}else if(!songObj.music){
|
}), songObj.music.url)
|
||||||
snd.musicGain.load(url).then(sound => {
|
}
|
||||||
songObj.sound = sound
|
var chart = songObj.chart
|
||||||
resolve()
|
if(chart.separateDiff){
|
||||||
}, reject)
|
var chartDiff = this.selectedSong.difficulty
|
||||||
}else if(songObj.music !== "muted"){
|
chart = chart[chartDiff]
|
||||||
snd.musicGain.load(songObj.music, true).then(sound => {
|
}
|
||||||
songObj.sound = sound
|
if(chart){
|
||||||
resolve()
|
this.addPromise(chart.read(song.type === "tja" ? "sjis" : "").then(data => {
|
||||||
}, reject)
|
|
||||||
}else{
|
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
}), songObj.music ? songObj.music.webkitRelativePath : url)
|
|
||||||
if(songObj.chart){
|
|
||||||
if(songObj.chart === "blank"){
|
|
||||||
this.songData = ""
|
|
||||||
}else{
|
|
||||||
var reader = new FileReader()
|
|
||||||
this.addPromise(pageEvents.load(reader).then(event => {
|
|
||||||
this.songData = event.target.result.replace(/\0/g, "").split("\n")
|
|
||||||
}), songObj.chart.webkitRelativePath)
|
|
||||||
if(song.type === "tja"){
|
|
||||||
reader.readAsText(songObj.chart, "sjis")
|
|
||||||
}else{
|
|
||||||
reader.readAsText(songObj.chart)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(songObj.lyricsFile && settings.getItem("showLyrics")){
|
|
||||||
var reader = new FileReader()
|
|
||||||
this.addPromise(pageEvents.load(reader).then(event => {
|
|
||||||
songObj.lyricsData = event.target.result
|
|
||||||
}, () => Promise.resolve()), songObj.lyricsFile.webkitRelativePath)
|
|
||||||
reader.readAsText(songObj.lyricsFile)
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
var url = this.getSongPath(song)
|
|
||||||
this.addPromise(loader.ajax(url).then(data => {
|
|
||||||
this.songData = data.replace(/\0/g, "").split("\n")
|
this.songData = data.replace(/\0/g, "").split("\n")
|
||||||
}), url)
|
}), chart.url)
|
||||||
if(song.lyrics && !songObj.lyricsData && !this.multiplayer && (!this.touchEnabled || this.autoPlayEnabled) && settings.getItem("showLyrics")){
|
}else{
|
||||||
var url = this.getSongDir(song) + "main.vtt"
|
this.songData = ""
|
||||||
this.addPromise(loader.ajax(url).then(data => {
|
}
|
||||||
songObj.lyricsData = data
|
if(songObj.lyricsFile && !songObj.lyricsData && !this.multiplayer && (!this.touchEnabled || this.autoPlayEnabled) && settings.getItem("showLyrics")){
|
||||||
}), url)
|
this.addPromise(songObj.lyricsFile.read().then(data => {
|
||||||
}
|
songObj.lyricsData = data
|
||||||
|
}, () => {}), songObj.lyricsFile.url)
|
||||||
}
|
}
|
||||||
if(this.touchEnabled && !assets.image["touch_drum"]){
|
if(this.touchEnabled && !assets.image["touch_drum"]){
|
||||||
let img = document.createElement("img")
|
let img = document.createElement("img")
|
||||||
@ -289,17 +262,6 @@ class LoadSong{
|
|||||||
randInt(min, max){
|
randInt(min, max){
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min
|
return Math.floor(Math.random() * (max - min + 1)) + min
|
||||||
}
|
}
|
||||||
getSongDir(selectedSong){
|
|
||||||
return gameConfig.songs_baseurl + selectedSong.folder + "/"
|
|
||||||
}
|
|
||||||
getSongPath(selectedSong){
|
|
||||||
var directory = this.getSongDir(selectedSong)
|
|
||||||
if(selectedSong.type === "tja"){
|
|
||||||
return directory + "main.tja"
|
|
||||||
}else{
|
|
||||||
return directory + selectedSong.difficulty + ".osu"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setupMultiplayer(){
|
setupMultiplayer(){
|
||||||
var song = this.selectedSong
|
var song = this.selectedSong
|
||||||
|
|
||||||
@ -326,13 +288,14 @@ class LoadSong{
|
|||||||
this.selectedSong2[i] = this.selectedSong[i]
|
this.selectedSong2[i] = this.selectedSong[i]
|
||||||
}
|
}
|
||||||
this.selectedSong2.difficulty = event.value.diff
|
this.selectedSong2.difficulty = event.value.diff
|
||||||
if(song.type === "tja"){
|
var chart = this.songObj.chart
|
||||||
|
var chartDiff = this.selectedSong2.difficulty
|
||||||
|
if(song.type === "tja" || !chart || !chart.separateDiff || !chart[chartDiff]){
|
||||||
this.startMultiplayer()
|
this.startMultiplayer()
|
||||||
}else{
|
}else{
|
||||||
loader.ajax(this.getSongPath(this.selectedSong2)).then(data => {
|
chart[chartDiff].read(song.type === "tja" ? "sjis" : "").then(data => {
|
||||||
this.song2Data = data.replace(/\0/g, "").split("\n")
|
this.song2Data = data.replace(/\0/g, "").split("\n")
|
||||||
this.startMultiplayer()
|
}, () => {}).then(() => {
|
||||||
}, () => {
|
|
||||||
this.startMultiplayer()
|
this.startMultiplayer()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -389,6 +352,7 @@ class LoadSong{
|
|||||||
}
|
}
|
||||||
clean(){
|
clean(){
|
||||||
delete this.promises
|
delete this.promises
|
||||||
|
delete this.songObj
|
||||||
pageEvents.remove(p2, "message")
|
pageEvents.remove(p2, "message")
|
||||||
if(this.cancelButton){
|
if(this.cancelButton){
|
||||||
pageEvents.remove(this.cancelButton, ["mousedown", "touchstart"])
|
pageEvents.remove(this.cancelButton, ["mousedown", "touchstart"])
|
||||||
|
@ -89,6 +89,7 @@ var vectors
|
|||||||
var settings
|
var settings
|
||||||
var scoreStorage
|
var scoreStorage
|
||||||
var account = {}
|
var account = {}
|
||||||
|
var gpicker
|
||||||
|
|
||||||
pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => {
|
pageEvents.add(root, ["touchstart", "touchmove", "touchend"], event => {
|
||||||
if(event.cancelable && cancelTouch && event.target.tagName !== "SELECT"){
|
if(event.cancelable && cancelTouch && event.target.tagName !== "SELECT"){
|
||||||
|
@ -49,7 +49,7 @@ class SongSelect{
|
|||||||
border: ["#dec4fd", "#a543ef"],
|
border: ["#dec4fd", "#a543ef"],
|
||||||
outline: "#a741ef"
|
outline: "#a741ef"
|
||||||
},
|
},
|
||||||
"browse": {
|
"customSongs": {
|
||||||
sort: 0,
|
sort: 0,
|
||||||
background: "#fab5d3",
|
background: "#fab5d3",
|
||||||
border: ["#ffe7ef", "#d36aa2"],
|
border: ["#ffe7ef", "#d36aa2"],
|
||||||
@ -80,42 +80,7 @@ class SongSelect{
|
|||||||
|
|
||||||
this.songs = []
|
this.songs = []
|
||||||
for(let song of assets.songs){
|
for(let song of assets.songs){
|
||||||
var title = this.getLocalTitle(song.title, song.title_lang)
|
this.songs.push(this.addSong(song))
|
||||||
var subtitle = this.getLocalTitle(title === song.title ? song.subtitle : "", song.subtitle_lang)
|
|
||||||
var skin = null
|
|
||||||
var categoryName = ""
|
|
||||||
var originalCategory = ""
|
|
||||||
if(song.category_id !== null && song.category_id !== undefined){
|
|
||||||
var category = assets.categories.find(cat => cat.id === song.category_id)
|
|
||||||
var categoryName = this.getLocalTitle(category.title, category.title_lang)
|
|
||||||
var originalCategory = category.title
|
|
||||||
var skin = this.songSkin[category.title]
|
|
||||||
}else if(song.category){
|
|
||||||
var categoryName = song.category
|
|
||||||
var originalCategory = song.category
|
|
||||||
}
|
|
||||||
this.songs.push({
|
|
||||||
id: song.id,
|
|
||||||
title: title,
|
|
||||||
originalTitle: song.title,
|
|
||||||
subtitle: subtitle,
|
|
||||||
skin: skin || this.songSkin.default,
|
|
||||||
courses: song.courses,
|
|
||||||
originalCategory: originalCategory,
|
|
||||||
category: categoryName,
|
|
||||||
category_id: song.category_id,
|
|
||||||
preview: song.preview || 0,
|
|
||||||
type: song.type,
|
|
||||||
offset: song.offset,
|
|
||||||
songSkin: song.song_skin || {},
|
|
||||||
music: song.music,
|
|
||||||
volume: song.volume,
|
|
||||||
maker: song.maker,
|
|
||||||
canJump: true,
|
|
||||||
hash: song.hash || song.title,
|
|
||||||
order: song.order,
|
|
||||||
lyrics: song.lyrics
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
this.songs.sort((a, b) => {
|
this.songs.sort((a, b) => {
|
||||||
var catA = a.originalCategory in this.songSkin ? this.songSkin[a.originalCategory] : this.songSkin.default
|
var catA = a.originalCategory in this.songSkin ? this.songSkin[a.originalCategory] : this.songSkin.default
|
||||||
@ -170,17 +135,26 @@ class SongSelect{
|
|||||||
action: "settings",
|
action: "settings",
|
||||||
category: strings.random
|
category: strings.random
|
||||||
})
|
})
|
||||||
if("webkitdirectory" in HTMLInputElement.prototype && !(/Android|iPhone|iPad/.test(navigator.userAgent))){
|
|
||||||
this.browse = document.getElementById("browse")
|
|
||||||
pageEvents.add(this.browse, "change", this.browseChange.bind(this))
|
|
||||||
|
|
||||||
|
var showCustom = false
|
||||||
|
if(gameConfig.google_credentials.gdrive_enabled){
|
||||||
|
if(!(/iPhone|iPad/.test(navigator.userAgent))){
|
||||||
|
showCustom = true
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if("webkitdirectory" in HTMLInputElement.prototype && !(/Android|iPhone|iPad/.test(navigator.userAgent))){
|
||||||
|
showCustom = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(showCustom){
|
||||||
this.songs.push({
|
this.songs.push({
|
||||||
title: assets.customSongs ? strings.defaultSongList : strings.browse,
|
title: assets.customSongs ? strings.customSongs.default : strings.customSongs.title,
|
||||||
skin: this.songSkin.browse,
|
skin: this.songSkin.customSongs,
|
||||||
action: "browse",
|
action: "customSongs",
|
||||||
category: strings.random
|
category: strings.random
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this.songs.push({
|
this.songs.push({
|
||||||
title: strings.back,
|
title: strings.back,
|
||||||
skin: this.songSkin.back,
|
skin: this.songSkin.back,
|
||||||
@ -501,11 +475,11 @@ class SongSelect{
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
if(this.state.screen === "song" && this.redrawRunning){
|
if(this.state.screen === "song" && this.redrawRunning){
|
||||||
var currentSong = this.songs[this.selectedSong]
|
var currentSong = this.songs[this.selectedSong]
|
||||||
if(currentSong.action === "browse"){
|
if(currentSong.action === "customSongs"){
|
||||||
var mouse = this.mouseOffset(event.changedTouches[0].pageX, event.changedTouches[0].pageY)
|
var mouse = this.mouseOffset(event.changedTouches[0].pageX, event.changedTouches[0].pageY)
|
||||||
var moveBy = this.songSelMouse(mouse.x, mouse.y)
|
var moveBy = this.songSelMouse(mouse.x, mouse.y)
|
||||||
if(moveBy === 0){
|
if(moveBy === 0){
|
||||||
this.toBrowse()
|
this.toCustomSongs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -668,10 +642,6 @@ class SongSelect{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
browseChange(event){
|
|
||||||
new ImportSongs(this, event)
|
|
||||||
}
|
|
||||||
|
|
||||||
toSelectDifficulty(fromP2){
|
toSelectDifficulty(fromP2){
|
||||||
var currentSong = this.songs[this.selectedSong]
|
var currentSong = this.songs[this.selectedSong]
|
||||||
if(p2.session && !fromP2 && currentSong.action !== "random"){
|
if(p2.session && !fromP2 && currentSong.action !== "random"){
|
||||||
@ -686,6 +656,9 @@ class SongSelect{
|
|||||||
}
|
}
|
||||||
}else if(this.state.locked === 0 || fromP2){
|
}else if(this.state.locked === 0 || fromP2){
|
||||||
if(currentSong.courses){
|
if(currentSong.courses){
|
||||||
|
if(currentSong.unloaded){
|
||||||
|
return
|
||||||
|
}
|
||||||
this.state.screen = "difficulty"
|
this.state.screen = "difficulty"
|
||||||
this.state.screenMS = this.getMS()
|
this.state.screenMS = this.getMS()
|
||||||
this.state.locked = true
|
this.state.locked = true
|
||||||
@ -721,8 +694,8 @@ class SongSelect{
|
|||||||
this.toAbout()
|
this.toAbout()
|
||||||
}else if(currentSong.action === "settings"){
|
}else if(currentSong.action === "settings"){
|
||||||
this.toSettings()
|
this.toSettings()
|
||||||
}else if(currentSong.action === "browse"){
|
}else if(currentSong.action === "customSongs"){
|
||||||
this.toBrowse()
|
this.toCustomSongs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.pointer(false)
|
this.pointer(false)
|
||||||
@ -857,18 +830,25 @@ class SongSelect{
|
|||||||
}, 500)
|
}, 500)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
toBrowse(){
|
toCustomSongs(){
|
||||||
if(assets.customSongs){
|
if(assets.customSongs){
|
||||||
assets.customSongs = false
|
assets.customSongs = false
|
||||||
assets.songs = assets.songsDefault
|
assets.songs = assets.songsDefault
|
||||||
|
delete assets.otherFiles
|
||||||
this.playSound("se_don")
|
this.playSound("se_don")
|
||||||
this.clean()
|
this.clean()
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
new SongSelect("browse", false, this.touchEnabled)
|
new SongSelect("customSongs", false, this.touchEnabled)
|
||||||
}, 500)
|
}, 500)
|
||||||
pageEvents.send("import-songs-default")
|
pageEvents.send("import-songs-default")
|
||||||
}else{
|
}else{
|
||||||
this.browse.click()
|
localStorage["selectedSong"] = this.selectedSong
|
||||||
|
|
||||||
|
this.playSound("se_don")
|
||||||
|
this.clean()
|
||||||
|
setTimeout(() => {
|
||||||
|
new CustomSongs(this.touchEnabled)
|
||||||
|
}, 500)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2420,30 +2400,31 @@ class SongSelect{
|
|||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
songObj = {id: id}
|
songObj = {id: id}
|
||||||
|
if(currentSong.previewMusic){
|
||||||
var previewFilename = prvTime > 0 ? "/preview.mp3" : "/main.mp3"
|
songObj.preview_time = 0
|
||||||
|
var promise = snd.previewGain.load(currentSong.previewMusic).catch(() => {
|
||||||
var loadPreview = previewFilename => {
|
|
||||||
return snd.previewGain.load(gameConfig.songs_baseurl + id + previewFilename)
|
|
||||||
}
|
|
||||||
|
|
||||||
new Promise((resolve, reject) => {
|
|
||||||
if(!currentSong.music){
|
|
||||||
songObj.preview_time = 0
|
|
||||||
loadPreview(previewFilename).catch(() => {
|
|
||||||
songObj.preview_time = prvTime
|
|
||||||
return loadPreview("/main.mp3")
|
|
||||||
}).then(resolve, reject)
|
|
||||||
}else if(currentSong.music !== "muted"){
|
|
||||||
songObj.preview_time = prvTime
|
songObj.preview_time = prvTime
|
||||||
snd.previewGain.load(currentSong.music, true).then(resolve, reject)
|
return snd.previewGain.load(currentSong.music)
|
||||||
}
|
})
|
||||||
}).then(sound => {
|
}else if(currentSong.unloaded){
|
||||||
if(currentId === this.previewId){
|
var promise = this.getUnloaded(this.selectedSong, songObj)
|
||||||
|
}else if(currentSong.sound){
|
||||||
|
songObj.preview_time = prvTime
|
||||||
|
currentSong.sound.gain = snd.previewGain
|
||||||
|
var promise = Promise.resolve(currentSong.sound)
|
||||||
|
}else if(currentSong.music !== "muted"){
|
||||||
|
songObj.preview_time = prvTime
|
||||||
|
var promise = snd.previewGain.load(currentSong.music)
|
||||||
|
}else{
|
||||||
|
return
|
||||||
|
}
|
||||||
|
promise.then(sound => {
|
||||||
|
if(currentId === this.previewId || loadOnly){
|
||||||
songObj.preview_sound = sound
|
songObj.preview_sound = sound
|
||||||
this.preview = sound
|
if(!loadOnly){
|
||||||
this.previewLoaded(startLoad, songObj.preview_time, currentSong.volume)
|
this.preview = sound
|
||||||
|
this.previewLoaded(startLoad, songObj.preview_time, currentSong.volume)
|
||||||
|
}
|
||||||
var oldPreview = this.previewList.shift()
|
var oldPreview = this.previewList.shift()
|
||||||
if(oldPreview){
|
if(oldPreview){
|
||||||
oldPreview.preview_sound.clean()
|
oldPreview.preview_sound.clean()
|
||||||
@ -2452,6 +2433,10 @@ class SongSelect{
|
|||||||
}else{
|
}else{
|
||||||
sound.clean()
|
sound.clean()
|
||||||
}
|
}
|
||||||
|
}).catch(e => {
|
||||||
|
if(e !== "cancel"){
|
||||||
|
return Promise.reject(e)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2483,6 +2468,72 @@ class SongSelect{
|
|||||||
snd.musicGain.fadeOut(0.4)
|
snd.musicGain.fadeOut(0.4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
getUnloaded(selectedSong, songObj){
|
||||||
|
var currentSong = this.songs[selectedSong]
|
||||||
|
var file = currentSong.chart
|
||||||
|
var importSongs = new ImportSongs(false, assets.otherFiles)
|
||||||
|
return file.read(currentSong.type === "tja" ? "sjis" : "").then(data => {
|
||||||
|
currentSong.chart = new CachedFile(data, file)
|
||||||
|
return importSongs.addTja({
|
||||||
|
file: currentSong.chart,
|
||||||
|
index: 0
|
||||||
|
})
|
||||||
|
}).then(() => {
|
||||||
|
var imported = importSongs.songs[0]
|
||||||
|
importSongs.clean()
|
||||||
|
imported.id = currentSong.id
|
||||||
|
imported.order = currentSong.order
|
||||||
|
delete imported.song_skin
|
||||||
|
songObj.preview_time = imported.preview
|
||||||
|
if(imported.music){
|
||||||
|
return snd.previewGain.load(imported.music).then(sound => {
|
||||||
|
imported.sound = sound
|
||||||
|
var index = assets.songs.findIndex(song => song.id === currentSong.id)
|
||||||
|
if(index !== -1){
|
||||||
|
assets.songs[index] = imported
|
||||||
|
}
|
||||||
|
this.songs[selectedSong] = this.addSong(imported)
|
||||||
|
return sound.copy()
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
return Promise.reject("cancel")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
addSong(song){
|
||||||
|
var title = this.getLocalTitle(song.title, song.title_lang)
|
||||||
|
var subtitle = this.getLocalTitle(title === song.title ? song.subtitle : "", song.subtitle_lang)
|
||||||
|
var skin = null
|
||||||
|
var categoryName = ""
|
||||||
|
var originalCategory = ""
|
||||||
|
if(song.category_id !== null && song.category_id !== undefined){
|
||||||
|
var category = assets.categories.find(cat => cat.id === song.category_id)
|
||||||
|
var categoryName = this.getLocalTitle(category.title, category.title_lang)
|
||||||
|
var originalCategory = category.title
|
||||||
|
var skin = this.songSkin[category.title]
|
||||||
|
}else if(song.category){
|
||||||
|
var categoryName = song.category
|
||||||
|
var originalCategory = song.category
|
||||||
|
}
|
||||||
|
var addedSong = {
|
||||||
|
title: title,
|
||||||
|
originalTitle: song.title,
|
||||||
|
subtitle: subtitle,
|
||||||
|
skin: skin || this.songSkin.default,
|
||||||
|
originalCategory: originalCategory,
|
||||||
|
category: categoryName,
|
||||||
|
preview: song.preview || 0,
|
||||||
|
songSkin: song.song_skin || {},
|
||||||
|
canJump: true,
|
||||||
|
hash: song.hash || song.title
|
||||||
|
}
|
||||||
|
for(var i in song){
|
||||||
|
if(!(i in addedSong)){
|
||||||
|
addedSong[i] = song[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addedSong
|
||||||
|
}
|
||||||
|
|
||||||
onusers(response){
|
onusers(response){
|
||||||
this.songs.forEach(song => {
|
this.songs.forEach(song => {
|
||||||
@ -2657,8 +2708,6 @@ class SongSelect{
|
|||||||
pageEvents.remove(this.touchFullBtn, "click")
|
pageEvents.remove(this.touchFullBtn, "click")
|
||||||
delete this.touchFullBtn
|
delete this.touchFullBtn
|
||||||
}
|
}
|
||||||
pageEvents.remove(this.browse, "change")
|
|
||||||
delete this.browse
|
|
||||||
delete this.selectable
|
delete this.selectable
|
||||||
delete this.ctx
|
delete this.ctx
|
||||||
delete this.canvas
|
delete this.canvas
|
||||||
|
@ -5,24 +5,11 @@
|
|||||||
pageEvents.add(window, ["click", "touchend", "keypress"], this.pageClicked.bind(this))
|
pageEvents.add(window, ["click", "touchend", "keypress"], this.pageClicked.bind(this))
|
||||||
this.gainList = []
|
this.gainList = []
|
||||||
}
|
}
|
||||||
load(url, local, gain){
|
load(file, gain){
|
||||||
if(local){
|
return file.arrayBuffer().then(response => {
|
||||||
var reader = new FileReader()
|
|
||||||
var loadPromise = pageEvents.load(reader).then(event => {
|
|
||||||
return event.target.result
|
|
||||||
})
|
|
||||||
reader.readAsArrayBuffer(url)
|
|
||||||
}else{
|
|
||||||
var loadPromise = loader.ajax(url, request => {
|
|
||||||
request.responseType = "arraybuffer"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return loadPromise.then(response => {
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
return this.context.decodeAudioData(response, resolve, reject)
|
return this.context.decodeAudioData(response, resolve, reject)
|
||||||
}).catch(error => {
|
}).catch(error => Promise.reject([error, file.url]))
|
||||||
throw [error, url]
|
|
||||||
})
|
|
||||||
}).then(buffer => {
|
}).then(buffer => {
|
||||||
return new Sound(gain || {soundBuffer: this}, buffer)
|
return new Sound(gain || {soundBuffer: this}, buffer)
|
||||||
})
|
})
|
||||||
@ -90,8 +77,8 @@ class SoundGain{
|
|||||||
}
|
}
|
||||||
this.setVolume(1)
|
this.setVolume(1)
|
||||||
}
|
}
|
||||||
load(url, local){
|
load(url){
|
||||||
return this.soundBuffer.load(url, local, this)
|
return this.soundBuffer.load(url, this)
|
||||||
}
|
}
|
||||||
convertTime(time, absolute){
|
convertTime(time, absolute){
|
||||||
return this.soundBuffer.convertTime(time, absolute)
|
return this.soundBuffer.convertTime(time, absolute)
|
||||||
@ -134,7 +121,7 @@ class Sound{
|
|||||||
this.sources = new Set()
|
this.sources = new Set()
|
||||||
}
|
}
|
||||||
copy(gain){
|
copy(gain){
|
||||||
return new Sound(gain, this.buffer)
|
return new Sound(gain || this.gain, this.buffer)
|
||||||
}
|
}
|
||||||
getTime(){
|
getTime(){
|
||||||
return this.soundBuffer.getTime()
|
return this.soundBuffer.getTime()
|
||||||
|
@ -102,20 +102,6 @@ var translations = {
|
|||||||
tw: "遊戲設定",
|
tw: "遊戲設定",
|
||||||
ko: "게임 설정"
|
ko: "게임 설정"
|
||||||
},
|
},
|
||||||
browse: {
|
|
||||||
ja: "参照する…",
|
|
||||||
en: "Browse…",
|
|
||||||
cn: "浏览…",
|
|
||||||
tw: "開啟檔案…",
|
|
||||||
ko: "찾아보기…"
|
|
||||||
},
|
|
||||||
defaultSongList: {
|
|
||||||
ja: "デフォルト曲リスト",
|
|
||||||
en: "Default Song List",
|
|
||||||
cn: "默认歌曲列表",
|
|
||||||
tw: "默認歌曲列表",
|
|
||||||
ko: "기본 노래 목록"
|
|
||||||
},
|
|
||||||
songOptions: {
|
songOptions: {
|
||||||
ja: "演奏オプション",
|
ja: "演奏オプション",
|
||||||
en: "Song Options",
|
en: "Song Options",
|
||||||
@ -1071,6 +1057,43 @@ var translations = {
|
|||||||
cn: "带歌词",
|
cn: "带歌词",
|
||||||
tw: "帶歌詞",
|
tw: "帶歌詞",
|
||||||
ko: "가사가있는"
|
ko: "가사가있는"
|
||||||
|
},
|
||||||
|
customSongs: {
|
||||||
|
title: {
|
||||||
|
en: "Custom Song List",
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
ja: "デフォルト曲リスト",
|
||||||
|
en: "Default Song List",
|
||||||
|
cn: "默认歌曲列表",
|
||||||
|
tw: "默認歌曲列表",
|
||||||
|
ko: "기본 노래 목록"
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
en: [
|
||||||
|
"Pick a folder with Taiko chart files in TJA format to play on a custom song list!"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
localFolder: {
|
||||||
|
en: "Local Folder..."
|
||||||
|
},
|
||||||
|
gdriveFolder: {
|
||||||
|
en: "Google Drive..."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
gpicker: {
|
||||||
|
myDrive: {
|
||||||
|
en: "My Drive"
|
||||||
|
},
|
||||||
|
starred: {
|
||||||
|
en: "Starred"
|
||||||
|
},
|
||||||
|
sharedWithMe: {
|
||||||
|
en: "Shared with me"
|
||||||
|
},
|
||||||
|
authError: {
|
||||||
|
en: "Auth error: %s"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var allStrings = {}
|
var allStrings = {}
|
||||||
|
12
public/src/views/customsongs.html
Normal file
12
public/src/views/customsongs.html
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<div class="view-outer">
|
||||||
|
<div class="view">
|
||||||
|
<div class="view-title stroke-sub"></div>
|
||||||
|
<div class="view-content"></div>
|
||||||
|
<div class="left-buttons">
|
||||||
|
<div id="link-localfolder" class="taibtn stroke-sub link-btn"></div>
|
||||||
|
<div id="link-gdrivefolder" class="taibtn stroke-sub link-btn"></div>
|
||||||
|
</div>
|
||||||
|
<div class="view-end-button taibtn stroke-sub selected"></div>
|
||||||
|
</div>
|
||||||
|
<form><input id="browse" type="file" webkitdirectory multiple></form>
|
||||||
|
</div>
|
@ -2,5 +2,4 @@
|
|||||||
<canvas id="song-sel-canvas"></canvas>
|
<canvas id="song-sel-canvas"></canvas>
|
||||||
<div id="song-sel-selectable" tabindex="1"></div>
|
<div id="song-sel-selectable" tabindex="1"></div>
|
||||||
<div id="touch-full-btn"></div>
|
<div id="touch-full-btn"></div>
|
||||||
<form><input id="browse" type="file" webkitdirectory multiple></form>
|
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user