Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save c4software/981661f1f826ad34c2a5dc11070add0f to your computer and use it in GitHub Desktop.
Save c4software/981661f1f826ad34c2a5dc11070add0f to your computer and use it in GitHub Desktop.
Download multiple files then compress to one zip file using JSZip & JSZip-utils
var zip = new JSZip();
var count = 0;
var zipFilename = "zipFilename.zip";
var urls = [
'http://image-url-1',
'http://image-url-2',
'http://image-url-3'
];
urls.forEach(function(url){
var filename = "filename";
// loading a file and add it in a zip file
JSZipUtils.getBinaryContent(url, function (err, data) {
if(err) {
throw err; // or handle the error
}
zip.file(filename, data, {binary:true});
count++;
if (count == urls.length) {
zip.generateAsync({type:'blob'}).then(function(content) {
saveAs(content, zipFilename);
});
}
});
});
@snahmad
Copy link

snahmad commented Jun 14, 2019

Does this download each file in parallel or sequential. I need to request list of file download sequentially.

@oleg-yudovich
Copy link

What is saveAs function? Where it came from?

@mkilponen
Copy link

mkilponen commented Jul 10, 2019

What is saveAs function? Where it came from?

https://github.com/eligrey/FileSaver.js/

include this in your file after npm i save-as:
import { saveAs } from 'save-as'

Note: each file needs an unique filename, otherwise the zip will contain only one file. Struggled with this for 2 hours lol.
also, the filename needs to include the type. For me it is:
zip.file(image+ ".jpg", data, {binary:true});

@yyimam
Copy link

yyimam commented Aug 17, 2019

what is JSZipUtils? my angular project throw error "Cannot find name 'JSZipUtils'"

@mkilponen
Copy link

what is JSZipUtils? my angular project throw error "Cannot find name 'JSZipUtils'"

https://github.com/Stuk/jszip-utils

install and import

@sucheep-s
Copy link

Thanks! This definitely saves my day !

@de-b
Copy link

de-b commented Sep 11, 2019

Perfect!!!

Thank you

@varun-singh-01
Copy link

What about if files are of sizes 5 GB , 10 GB etc. ? What I observed here, is it downloads all files and start downloading zip that is created. Is there a way I can start downloading zip while it is getting written with files data?

@rajeshpal1990
Copy link

rajeshpal1990 commented Mar 27, 2020

its not working with the images having "https" url. plz suggest.

Error :
Access to XMLHttpRequest at 'https://otousedcar.s3.ap-southeast-1.amazonaws.com/finance/267/1583318607942.JPEG' from origin 'http://localhost:3040' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Note : i am using in react js

@Ugoivy
Copy link

Ugoivy commented Jul 11, 2020

you can either disable CORS or use a proxy @rajeshpal1990.

As @mkilponen said, you need unique file names to make this work. You can split and pop the file name from the urls.

Try this:

 function test() {
    var urls = [
        'https://www..../Cani-spiaggia.png',
        'https://www..../39052fe544a95dbf6ccfdd106fcabb3e_L.jpg'
    ];
    var zip = new JSZip();
    var count = 0;
    var count2 = 0;
    var zipFilename = "zipFilename.zip";
    var nameFromURL = [];

    var the_arr = "";
    for (var i = 0; i< urls.length; i++){
        the_arr = urls[i].split('/');
        nameFromURL[i] = the_arr.pop();

    }

    urls.forEach(function(url){
        var filename = nameFromURL[count2];
        count2++;
        // loading a file and add it in a zip file
        JSZipUtils.getBinaryContent(url, function (err, data) {
            if(err) {
                throw err; // or handle the error
            }
            zip.file(filename, data, {binary:true});
            count++;
            if (count === urls.length) {
                zip.generateAsync({type:'blob'}).then(function(content) {
                    saveAs(content, zipFilename);
                });
            }
        });
    });
}

@M-ElSherif
Copy link

@Ugoivy thank you for sharing your solution to this.

I do have a question about the counters used, mainly 'count' and 'count2'. Could you not have used 'count' as the index for the nameFromUrl array?

@umerchaudhary34
Copy link

umerchaudhary34 commented Sep 26, 2020

Uncaught Error: InvalidStateError: Failed to read the 'responseText' property from 'XMLHttpRequest': The value is only accessible if the object's 'responseType' is '' or 'text' (was 'arraybuffer').
I`m using react js and having this issue.can you please help? @Ugoivy @mkilponen

@Atabord
Copy link

Atabord commented Nov 5, 2020

@Ugoivy just a little improvement so you don't have to iterate twice over the urls, just take the url file name inside the forEach

import JSZip from 'jszip';
import JSZipUtils from 'jszip-utils';
import saveAs from 'save-as';

 function test() {
    const urls = [
        'https://www..../Cani-spiaggia.png',
        'https://www..../39052fe544a95dbf6ccfdd106fcabb3e_L.jpg'
    ];
    const zip = new JSZip();
    let count = 0;
    const zipFilename = "evidence.zip";
    urls.forEach(async function (url){
      const urlArr = url.split('/');
      const filename = urlArr[urlArr.length - 1];
      try {
        const file = await JSZipUtils.getBinaryContent(url)
        zip.file(filename, file, { binary: true});
        count++;
        if(count === urls.length) {
          zip.generateAsync({type:'blob'}).then(function(content) {
            saveAs(content, zipFilename);
          });
        }
      } catch (err) {
        console.log(err);
      }
    });
}

@umerchaudhary34 this was all I needed to make it work
well in develop environment with react I had troubles because of CORS, for testing purposes I added this to the beginning of the url https://cors-anywhere.herokuapp.com/ example https://cors-anywhere.herokuapp.com/https://myurl.com/myImage.com

but for production environment I suggest you to configure your server to accept this kind of connections.

PD: I also changed it to work as async/await function but it works as a callback too

@rodrigo01
Copy link

@Ugoivy just a little improvement so you don't have to iterate twice over the urls, just take the url file name inside the forEach

import JSZip from 'jszip';
import JSZipUtils from 'jszip-utils';
import saveAs from 'save-as';

 function test() {
    const urls = [
        'https://www..../Cani-spiaggia.png',
        'https://www..../39052fe544a95dbf6ccfdd106fcabb3e_L.jpg'
    ];
    const zip = new JSZip();
    let count = 0;
    const zipFilename = "evidence.zip";
    urls.forEach(async function (url){
      const urlArr = url.split('/');
      const filename = urlArr[urlArr.length - 1];
      try {
        const file = await JSZipUtils.getBinaryContent(url)
        zip.file(filename, file, { binary: true});
        count++;
        if(count === urls.length) {
          zip.generateAsync({type:'blob'}).then(function(content) {
            saveAs(content, zipFilename);
          });
        }
      } catch (err) {
        console.log(err);
      }
    });
}

@umerchaudhary34 this was all I needed to make it work
well in develop environment with react I had troubles because of CORS, for testing purposes I added this to the beginning of the url https://cors-anywhere.herokuapp.com/ example https://cors-anywhere.herokuapp.com/https://myurl.com/myImage.com

but for production environment I suggest you to configure your server to accept this kind of connections.

PD: I also changed it to work as async/await function but it works as a callback too

Hi, i just want to make a cors proxy for my project, how do you make that "Proxy"?

@adamiusz
Copy link

work, thanks

@ArashChoobdar
Copy link

I have some SVG file and I convert it to PNG and now I want to push the PNG file in a folder and zip it and download it , but in this example want URLs but I don't have URL but I have the element , I want to know what I can do for it ?

@Apy102
Copy link

Apy102 commented Dec 29, 2022

I'm facing cors issue, how can i solve that? for testing when i dessabled the web security then zip file properly got downloaded. so please suggest me how can i solve this cors error

@rami-alloush
Copy link

This is what's working for me recently on Typescript

import { saveAs } from 'file-saver';
import * as JSZip from 'jszip';
// @ts-ignore
import * as JSZipUtils from 'jszip-utils';

  downloadAllFiles(urls: any[]): void {
    var zip = new JSZip();
    var count = 0;
    var zipFilename = 'zipFilename.zip';

    urls.forEach(function (url, idx) {
      console.log(url);

      var filename = 'filename' + idx + '.pdf';
      // loading a file and add it in a zip file
      JSZipUtils.getBinaryContent(
        url,
        function (
          err: any,
          data:
            | string
            | ArrayBuffer
            | number[]
            | Uint8Array
            | Blob
            | NodeJS.ReadableStream
            | Promise<
                | string
                | ArrayBuffer
                | number[]
                | Uint8Array
                | Blob
                | NodeJS.ReadableStream
              >
        ) {
          if (err) {
            throw err; // or handle the error
          }
          zip.file(filename, data, { binary: true });
          count++;
          if (count == urls.length) {
            zip.generateAsync({ type: 'blob' }).then(function (content) {
              saveAs(content, zipFilename);
            });
          }
        }
      );
    });
  }

@Atabord
Copy link

Atabord commented Jun 27, 2023

I'm facing cors issue, how can i solve that? for testing when i dessabled the web security then zip file properly got downloaded. so please suggest me how can i solve this cors error

in development mode you could add this to the beginning of the url https://cors-anywhere.herokuapp.com/ example https://cors-anywhere.herokuapp.com/https://myurl.com/myImage.com

but for production environment you should configure your server to accept this kind of connections with Access-Control-Allow-Origin from the server side.

@ElvisAns
Copy link

What is saveAs function? Where it came from?

https://github.com/eligrey/FileSaver.js/

include this in your file after npm i save-as: import { saveAs } from 'save-as'

Note: each file needs an unique filename, otherwise the zip will contain only one file. Struggled with this for 2 hours lol. also, the filename needs to include the type. For me it is: zip.file(image+ ".jpg", data, {binary:true});

+1
I have also struggled with file name being redundant and i ended up with a zip with one file, i suggest adding something like self.crypto.randomUUID(); https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID to ensure uniqueness!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment