GDrive API v3文件.是否设置下载进度



如何使用gap客户端v3neneneba API显示从GDrive下载大文件的进度?

我使用的是v3 API,并尝试在头中使用Range请求,这是有效的,但下载速度非常慢(如下(。我的最终目标是播放4K视频。GDrive将播放限制为1920x1280。我的计划是通过v3 API将块下载到IndexedDB,并从本地缓存的数据中播放。我通过Range请求使用下面的代码来完成这项工作,但速度太慢了。在我的连接上,直接(例如通过GDrive网页(正常下载完整的438 MB测试文件大约需要30-35秒,巧合的是,每个1 MB范围的请求几乎需要完全相同的30-35秒。感觉GDrive后端正在读取和发送每个子范围的完整文件?

我还尝试过使用XHR和fetch来下载该文件,但失败了。我一直在使用webContent链接(通常以&export=download结尾(,但我无法正确获取访问标头。我收到CORS或其他奇怪的权限问题。webContent链接在<image><video>src标记中工作良好。我想这是由于浏览器专门为这些媒体标签处理的特殊权限处理或我缺少的一些标题信息。我的解决方案必须能够读取私有(非公共、非共享(链接,因此可以使用v3 API。

对于小于GDrive限制的视频文件,我可以设置MediaRecorder并使用<video>元素来获取进度数据。不幸的是,对于更大的文件,1920x1080的限制扼杀了这种方法,因为进度反馈更为重要。

这是客户端的gap-Range代码,它可以工作,但对于大型(400MB-2GB(文件来说速度慢得令人讨厌:

const getRange = (start, end, size, fileId, onProgress) => (
new Promise((resolve, reject) => gapi.client.drive.files.get(
{ fileId, alt: 'media', Range: `bytes=${start}-${end}` },
// { responseType: 'stream' }, Perhaps this fails in the browser?
).then(res => {
if (onProgress) {
const cancel = onProgress({ loaded: end, size, fileId })
if (cancel) {
reject(new Error(`Progress canceled download at range ${start} to ${end} in ${fileId}`))
}
}
return resolve(res.body)
}, err => reject(err)))
)
export const downloadFileId = async (fileId, size, onProgress) => {
const batch = 1024 * 1024
try {
const chunks = []
for (let start = 0; start < size; start += batch) {
const end = Math.min(size, start + batch - 1)
const data = await getRange(start, end, size, fileId, onProgress)
if (!data) throw new Error(`Unable to get range ${start} to ${end} in ${fileId}`)
chunks.push(data)
}
return chunks.join('')
} catch (err) {
return console.error(`Error downloading file: ${err.message}`)
}
}

身份验证对我来说很好,我使用其他GDrive命令也很好。我目前使用drives.photos.readonly作用域,但即使我使用完全写入权限作用域,我也会遇到同样的问题。

切切地说,当使用gap运行客户端时,我无法获得流(在服务器端的节点中运行良好(。这太奇怪了。如果我能得到一条流,我想我可以利用它来获得进步。每当我为responseType: 'stream'添加注释行时,我都会收到以下错误:The server encountered a temporary error and could not complete your request. Please try again in 30 seconds. That’s all we know.当然等待没有帮助,如果我不请求流,我可以得到成功的响应。

我改为直接使用XMLHttpRequest,而不是使用gap包装器。谷歌提供了这些使用CORS的说明,展示了如何将任何请求从使用gap转换为XHR。然后,您可以附加到onprogress事件(以及onload、oneror和其他事件(以获取进度。

下面是问题中downloadFileId方法的替换代码,其中包含一堆调试脚手架:

const xhrDownloadFileId = (fileId, onProgress) => new Promise((resolve, reject) => {
const user = gapi.auth2.getAuthInstance().currentUser.get()
const oauthToken = user.getAuthResponse().access_token
const xhr = new XMLHttpRequest()
xhr.open('GET', `https://www.googleapis.com/drive/v3/files/${fileId}?alt=media`)
xhr.setRequestHeader('Authorization', `Bearer ${oauthToken}`)
xhr.responseType = 'blob'
xhr.onloadstart = event => {
console.log(`xhr ${fileId}: on load start`)
const { loaded, total } = event
onProgress({ loaded, size: total })
}
xhr.onprogress = event => {
console.log(`xhr ${fileId}: loaded ${event.loaded} of ${event.total} ${event.lengthComputable ? '' : 'non-'}computable`)
const { loaded, total } = event
onProgress({ loaded, size: total })
}
xhr.onabort = event => {
console.warn(`xhr ${fileId}: download aborted at ${event.loaded} of ${event.total}`)
reject(new Error('Download aborted'))
}
xhr.onerror = event => {
console.error(`xhr ${fileId}: download error at ${event.loaded} of ${event.total}`)
reject(new Error('Error downloading file'))
}
xhr.onload = event => {
console.log(`xhr ${fileId}: download of ${event.total} succeeded`)
const { loaded, total } = event
onProgress({ loaded, size: total })
resolve(xhr.response)
}
xhr.onloadend = event => console.log(`xhr ${fileId}: download of ${event.total} completed`)
xhr.ontimeout = event => {
console.warn(`xhr ${fileId}: download timeout after ${event.loaded} of ${event.total}`)
reject(new Error('Timout downloading file'))
}
xhr.send()
})

最新更新