I'm creating a Chrome extension that needs to download multiple files (images and/or videos) from a website. These files may have a huge size, so I want to show the download progress to the user. After some research I found that currently a possible solution might be:
- Download all the files with XMLHttpRequests.
- When downloaded, zip all the files into one archive with a JavaScript library (eg. JSZip.js, zip.js).
- Prompt the user to save the zip with SaveAs dialog.
I'm stuck at passage 2), how can I zip the downloaded files?
To understand, here is a code sample:
var fileURLs = ['http://www.test.com/img.jpg',...];
var zip = new JSZip();
var count = 0;
for (var i = 0; i < fileURLs.length; i++){
var xhr = new XMLHttpRequest();
xhr.onprogress = calculateAndUpdateProgress;
xhr.open('GET', fileURLs[i], true);
xhr.responseType = "blob";
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
var blob_url = URL.createObjectURL(response);
// add downloaded file to zip:
var fileName = fileURLs[count].substring(fileURLs[count].lastIndexOf('/')+1);
zip.file(fileName, blob_url); // <- here's one problem
count++;
if (count == fileURLs.length){
// all download are completed, create the zip
var content = zip.generate();
// then trigger the download link:
var zipName = 'download.zip';
var a = document.createElement('a');
a.href = "data:application/zip;base64," + content;
a.download = zipName;
a.click();
}
}
};
xhr.send();
}
function calculateAndUpdateProgress(evt) {
if (evt.lengthComputable) {
// get download progress by performing some average
// calculations with evt.loaded, evt.total and the number
// of file to download / already downloaded
...
// then update the GUI elements (eg. page-action icon and popup if showed)
...
}
}
The upper code generate a downloadable archive containing small corrupted files.
There is also an issue with filename sync: blob object do not contains the file name, so If eg. fileURLs[0]
takes more time to be downloaded than fileURLs[1]
names become wrong (inverted)..
NOTE: I know that Chrome has a download API but it's in dev channel so unfortunately it's not a solution now, and I would like to avoid using NPAPI for such a simple task.