2020-10-29 13:07:56 +08:00
|
|
|
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
|
2020-10-29 14:04:36 +08:00
|
|
|
if(!list){
|
|
|
|
continue
|
|
|
|
}
|
2020-10-29 13:07:56 +08:00
|
|
|
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){
|
2020-10-29 14:04:36 +08:00
|
|
|
return Promise.resolve()
|
2020-10-29 13:07:56 +08:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
))
|
|
|
|
}
|
2020-10-31 19:47:42 +08:00
|
|
|
getToken(lockedCallback=()=>{}){
|
2020-10-29 13:07:56 +08:00
|
|
|
if(this.oauthToken){
|
2020-10-29 14:04:36 +08:00
|
|
|
return Promise.resolve()
|
2020-10-29 13:07:56 +08:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
}
|
2020-10-31 19:47:42 +08:00
|
|
|
downloadFile(id, arrayBuffer, retry){
|
|
|
|
var url = this.filesUrl + id + "?alt=media"
|
|
|
|
return this.queue().then(this.getToken.bind(this)).then(() =>
|
|
|
|
loader.ajax(url, request => {
|
2020-10-29 13:07:56 +08:00
|
|
|
if(arrayBuffer){
|
|
|
|
request.responseType = "arraybuffer"
|
|
|
|
}
|
|
|
|
request.setRequestHeader("Authorization", "Bearer " + this.oauthToken)
|
2020-10-31 19:47:42 +08:00
|
|
|
}, 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()
|
2020-10-29 13:07:56 +08:00
|
|
|
})
|
|
|
|
)
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|