This repository has been archived on 2024-01-28. You can view files and clone it, but cannot push or open issues/pull-requests.
gdcdn/googleDrive.js

172 lines
4.2 KiB
JavaScript

import xf from './xfetch'
class GoogleDrive {
constructor(auth) {
this.auth = auth
this.expires = 0
this._getIdCache = new Map()
}
async initializeClient() {
// any method that do api call must call this beforehand
if (Date.now() < this.expires) return
const resp = await xf
.post('https://www.googleapis.com/oauth2/v4/token', {
urlencoded: {
client_id: this.auth.client_id,
client_secret: this.auth.client_secret,
refresh_token: this.auth.refresh_token,
grant_type: 'refresh_token'
}
})
.json()
this.client = xf.extend({
baseURI: 'https://www.googleapis.com/drive/v3/',
headers: {
Authorization: `Bearer ${resp.access_token}`
}
})
this.expires = Date.now() + 3500 * 1000 // normally, it should expiers after 3600 seconds
}
async listDrive() {
await this.initializeClient()
return this.client.get('drives').json()
}
async download(id, range = '') {
await this.initializeClient()
return this.client.get(`files/${id}`, {
qs: {
includeItemsFromAllDrives: true,
supportsAllDrives: true,
alt: 'media'
},
headers: {
Range: range
}
})
}
async downloadByPath(path, rootId = 'root', range = '') {
const id = await this.getId(path, rootId)
if (!id) return null
return this.download(id, range)
}
async getMeta(id) {
await this.initializeClient()
return this.client
.get(`files/${id}`, {
qs: {
includeItemsFromAllDrives: true,
supportsAllDrives: true,
fields: '*'
}
})
.json()
}
async getMetaByPath(path, rootId = 'root') {
const id = await this.getId(path, rootId)
if (!id) return null
return this.getMeta(id)
}
async listFolder(id) {
await this.initializeClient()
const getList = pageToken => {
const qs = {
includeItemsFromAllDrives: true,
supportsAllDrives: true,
q: `'${id}' in parents and trashed = false`,
orderBy: 'folder,name,modifiedTime desc',
fields:
'files(id,name,mimeType,size,modifiedTime),nextPageToken',
pageSize: 1000
}
if (pageToken) {
qs.pageToken = pageToken
}
return this.client
.get('files', {
qs
})
.json()
}
const files = []
let pageToken
do {
const resp = await getList(pageToken)
files.push(...resp.files)
pageToken = resp.nextPageToken
} while (pageToken)
return { files }
}
async listFolderByPath(path, rootId = 'root') {
const id = await this.getId(path, rootId)
if (!id) return null
return this.listFolder(id)
}
async getId(path, rootId = 'root') {
const toks = path.split('/').filter(Boolean)
let id = rootId
for (const tok of toks) {
id = await this._getId(id, tok)
}
return id
}
async _getId(parentId, childName) {
if (this._getIdCache.has(parentId + childName)) {
return this._getIdCache.get(parentId + childName)
}
await this.initializeClient()
childName = childName.replace(/\'/g, `\\'`) // escape single quote
const resp = await this.client
.get('files', {
qs: {
includeItemsFromAllDrives: true,
supportsAllDrives: true,
q: `'${parentId}' in parents and name = '${childName}' and trashed = false`,
fields: 'files(id)'
}
})
.json()
.catch(e => ({ files: [] })) // if error, make it empty
if (resp.files.length === 0) {
return null
}
this._getIdCache.has(parentId + childName)
return resp.files[0].id // when there are more than 1 items, simply return the first one
}
async upload(parentId, name, file) {
await this.initializeClient()
const createResp = await this.client.post(
'https://www.googleapis.com/upload/drive/v3/files',
{
qs: {
uploadType: 'resumable',
supportsAllDrives: true
},
json: {
name,
parents: [parentId]
}
}
)
const putUrl = createResp.headers.get('Location')
return this.client
.put(putUrl, {
body: file
})
.json()
}
async uploadByPath(path, name, file, rootId = 'root') {
const id = await this.getId(path, rootId)
if (!id) return null
return this.upload(id, name, file)
}
async delete(fileId) {
return this.client.delete(`files/${fileId}`)
}
async deleteByPath(path, rootId = 'root') {
const id = await this.getId(path, rootId)
if (!id) return null
return this.delete(id)
}
}
export default GoogleDrive