如何解决如何避免 Firefox 下载的“另存为”对话框?
我正在为网站创建批量下载功能。它适用于 chrome,但 Firefox 中的另存为对话框给我带来了问题。由于我正在循环下载大量文件,因此它会打开相同数量的对话框(除非他们快速选择保存为第一次下载。)有没有办法解决这个问题?
理想情况下,我希望在选择另存为对话时触发一个事件,或者可能是一种了解它的简单方法我当前文件类型的默认行为是“每次询问”或“另存为”并提示用户在下载开始之前更改它。但据我所知,这些功能并不存在(如果我错了,请纠正我)。
请注意,我无权访问服务器,因此任何类型的服务器端解决方案都不适合我。我也无法在客户端压缩文件,因为这些文件可能很大。
仅供参考,虽然我认为这在这里不是很有帮助,但以下是我的 Downloader 类,这里感兴趣的方法是 _savetodisk()
class Downloader{
/**
*
* @param {Array<string>} downloadLinks
*/
constructor(downloadLinks){
//downloadConstants
this.bufferSize =
downloadConstants.bufferSize
this.noOfActiveFetchLimit =
downloadConstants.noOfActiveFetchLimit
this.fallbackNoOfActiveFetchLimit =
downloadConstants.fallbackNoOfActiveFetchLimit
this.downloadInterval =
downloadConstants.downloadInterval
this.fallbackDownloadInterval =
downloadConstants.fallbackDownloadInterval
this.expectedBufferUsed = 0
this.noOfActiveFetch = 0
this.downloadedCount = 0
this.abortedCount = 0
this.downloadJobCount =
downloadLinks?.length ? downloadLinks.length : 0
this.isDownloadOngoing = false
this.iteratedOnce = false
this.lastFiveIsEqual = false
this.hasSizeInfo = true
this.downloadLinks = downloadLinks ?? []
this.FailedDownloads = {
retry : [],//with status 0
errorlog: [] //status >= 400
}
this.queue = new DownloadQueue()
this.lastFive = new LastFive()
this.lastFiveOnloadedSize = new LastFive()
}
_isFallBack(){
return (
this.expectedBufferUsed > this.bufferSize ||
!this.hasSizeInfo &&
(
!this.lastFiveOnloadedSize.getAvgSize() ?
true :
this.lastFiveOnloadedSize.getAvgSize() > this.bufferSize
))
}
_isDownloadComplete(){
return (this.downloadedCount + this.abortedCount
=== this.downloadJobCount)
}
_shouldAbort(size){
return (this.bufferSize - this.expectedBufferUsed <= size &&
!this.iteratedOnce &&
!this.lastFiveIsEqual &&
!this.lastFiveOnloadedSize.allEqual())
}
_getNoOfActiveFetchLimit(){
return !this._isFallBack() ?
this.noOfActiveFetchLimit : this.fallbackNoOfActiveFetchLimit
}
_getDownloadInterval(){
return !this._isFallBack() ?
this.downloadInterval : this.fallbackDownloadInterval
}
_addExpectedBufferUsed(size){
if (!size){
if(this.lastFiveOnloadedSize.allEqual()){
size = this.lastFiveOnloadedSize.array[4]
}else if(this.lastFiveOnloadedSize.getAvgSize()){
size = this.lastFiveOnloadedSize.getAvgSize()
}else{
size = 0
}
}
this.expectedBufferUsed += size
//for cases when size info isn't available
if(this.expectedBufferUsed < 0){
this.expectedBufferUsed = 0
}
}
_abortHandler(xhr,downloadLink,size){
//if lastFive elements have same size
//we assume that all the requests will be the same
//until proven differently
xhr.abort()
this.queue.push({
url: downloadLink,size
})
this.lastFive.push(size)
this.abortedCount++
this.noOfActiveFetch--
return
}
_requestSmallerFile(){
if(this.noOfActiveFetch >= this._getNoOfActiveFetchLimit()){
return false
}
const fetchSize = this.bufferSize - this.expectedBufferUsed
const newRequestItem = this.queue.pop(fetchSize)
if(newRequestItem != undefined){
this._fetch(newRequestItem.url)
return true
}
return false
}
_filterRequests(xhr,downloadLink){
const size = xhr.getResponseHeader("Content-length") ?
parseInt(xhr.getResponseHeader("Content-length")) :
null
this.hasSizeInfo = size ? true : false
this.lastFive.push(size)
this.lastFiveIsEqual = this.lastFive.allEqual()
if(this._shouldAbort(size)){
this._abortHandler(xhr,size,downloadLink)
this._requestSmallerFile()
return
}
this._addExpectedBufferUsed(size)
}
_savetodisk(res,downloadLink){
this.lastFiveOnloadedSize.push(res.loaded)
const blobURL = window.URL.createObjectURL(res)
const a = document.createElement('a')
const fileName = downloadLink.substr(downloadLink.lastIndexOf('/') + 1)
a.href = blobURL
a.setAttribute('download',fileName)
document.body.appendChild(a)
a.click()
a.remove()
window.URL.revokeObjectURL(blobURL)
}
_updateDownloadParams(loaded){
//deduct the memory freed here
this._addExpectedBufferUsed((-1)*loaded)
this.noOfActiveFetch--
this.downloadJobCount++
}
_handleErrors(xhr,downloadLink){
const status = xhr.status
if(status === 0){
this.FailedDownloads.retry.push(downloadLink)
} else{
this.FailedDownloads.errorlog.push({
status,url: downloadLink
})
}
}
_retryFailedDownloads(){
//under construction
}
_onload(xhr,res,downloadLink){
const status = xhr.status
if(status >= 200 && status < 400){
this._savetodisk(xhr.response,downloadLink)
this._updateDownloadParams(res.loaded)
} else {
this._handleErrors(xhr,downloadLink)
}
if(this._isDownloadComplete()){
this._retryFailedDownloads()
}
}
_fetch(downloadLink){
const xhr = new XMLHttpRequest()
xhr.overrideMimeType('application/octet-stream')
xhr.onreadystatechange = res => {
const readyState = xhr.readyState
if (readyState === 1){
this.fetchCount += 1
this.noOfActiveFetch += 1
return
} else if (readyState === 2){
this._filterRequests(xhr,downloadLink)
} else if (readyState === 3){
return
} else if (readyState === 4){
this._onload(xhr,downloadLink)
}
}
xhr.open('GET',downloadLink)
xhr.responseType = 'blob'
xhr.send(null)
}
_initiateSecondDownloadIteration(){
this.iteratedOnce = true
if (this.queue.length == 0){
return
}
this.downloadLinks = this.downloadLinks.concat(this.queue.getURLs())
this.queue.reset()
this._initiateDownload()
return
}
_initiateDownload(){
const setDownloadInterval = () => {
if (this.downloadLinks.length === 0){
this._initiateSecondDownloadIteration()
return
}
if(this.noOfActiveFetch >= this._getNoOfActiveFetchLimit()){
setTimeout(setDownloadInterval,this._getDownloadInterval() + this.fallbackDownloadInterval)
return
}
this._fetch(`${fileServerBaseUrl}/${directoryEndpoint}/${this.downloadLinks.pop()}`)
setTimeout(setDownloadInterval,this._getDownloadInterval())
}
setTimeout(setDownloadInterval,0)
}
/**
*
* @param {Array.<string>} downloadLinks
*/
download(downloadLinks){
if(downloadLinks != undefined){
this.downloadLinks = this.downloadLinks.concat(downloadLinks)
this.downloadJobCount +=
this.downloadLinks?.length ? downloadLinks.length : 0
}
if(!this.isDownloadOngoing){
this.isDownloadOngoing = true
this._initiateDownload()
return
}
return
}
_reset(){
this.expectedBufferUsed = 0
this.noOfActiveFetch = 0
this.downloadedCount = 0
this.abortedCount = 0
this.downloadJobCount = 0
this.isDownloadOngoing = false
this.iteratedOnce = false
this.lastFiveIsEqual = false
this.hasSizeInfo = true
this.downloadLinks = []
this.FailedDownloads = {
retry : [],errorlog: []
}
this.queue.reset()
this.lastFive.reset()
this.lastFiveOnloadedSize.reset()
}
}
解决方法
“选项”页面上有一个“每次都问我”保存下载的位置的设置,只需将其设置为“从不”。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。