pixiv insideは移転しました! ≫ https://inside.pixiv.blog/

JSZipによるファイル一括DL

こんばんは、雪が降りそうな寒い日が続いていますね。
2015年新卒 いっくんです。

創作活動がより楽しくなるショップ作成サービス BOOTHものづくりをもっと身近にする pixivFACTORY などを通じて、ユーザーさんに創作活動を楽しんでもらうお仕事をしています。

さて、今日はJSZipによる クライアントサイドzip生成 & ファイル一括DLを紹介します。

なぜクライアントサイドでzip生成?

今回は、Webページのダウンロードリンクからファイルを一括ダウンロードするために使います。

複数のダウンロードリンクがあるページでは、「一括ダウンロード」のボタンを用意したくなりますよね。 しかし、サーバーサイドでzipを生成しておくのは負荷が大きいです。

そこで便利なのが、クライアントサイドでのzip圧縮です。 ブラウザでzipファイルを作ることで、サーバーへ負荷をかけずに「一括ダウンロード」を実装することができます。

どのように実装するか

下記の手順で、クライアントサイドでのzip圧縮を行います

  1. ダウンロードするファイルのURL一覧を用意する
  2. ファイルをダウンロードする
  3. zipファイルを生成
  4. 生成したzipファイルを保存する

1. ダウンロードするファイルのURL一覧を用意する

ダウンロードしたいファイルの配列をつくります。おまかせですね。

2. ファイルをダウンロードする

ajaxを使ってファイルをダウンロードします。 その際、元のデータを壊さないためにXMLHttpRequestresponseTypeを設定する必要があります。

responseTypeを設定することで、レスポンスの型を任意の形式にすることが可能です。 (json, textなど)
今回はarraybufferを指定します。(それぞれの詳細についてはリンク先を参照)

// ファイルをダウンロード
var downloadFile = function (url) {
  var xhr = new XMLHttpRequest(),
      deferred = new $.Deferred();

  // ダウンロードが完了したら実行されるよ ( ゚∀゚)o彡゚
  xhr.addEventListener('load', function() {
    xhr.response; // ダウンロードしたデータ
    deferred.resolve(xhr);
  });

  xhr.open('GET', url, true);
  xhr.responseType = 'arraybuffer'; // <- ここでarraybufferを設定
  xhr.send();

  return deferred.promise();
}

これで、ArrayBufferの型でファイルをダウンロードできるようになりました。

3. zipファイルを生成

続いて、複数のファイルをダウンロードして、zipファイルにしてみましょう。 zipの生成にはJSZipを使います。

// 複数ファイルを一括ダウンロード
var batchDownload = function(urlList) {
  var zip = new JSZip(),
      deferreds = [];

  for (var i = 0; i < urlList.length; i += 1) {
    var deferred = downloadFile(urlList[i]).done(function(xhr) {
      var filename = 'do_something.extname';
      zip.file(filename, xhr.response); // zipに追加 ( ゚∀゚)o彡゚
    })

    deferreds.push(deferred);
  }

  $.when.apply($, deferreds).done(function() {
    // すべてのダウンロードが完了したら実行されるよ!
    var zipFile = zip.generate({ type: 'blob' });
  });
};

batchDownload(['http://...', 'http://...', ...]);

jQuery.deferredjQuery.whenを使って、並列ダウンロードが終わるのを待っています。

4. 生成したzipファイルを保存する

さて、JavaScriptを使って生成したファイルを保存するために、いずれかのプラグインを利用します。

  • Downloadify 対応ブラウザが多いが、ちょっと扱いづらい
  • FileSaver.js モダンブラウザに対応(Safariのみバグがある)

もともとJSZip自体がモダンなブラウザでしか動かないため、今回はFileSaverを使ってファイルを保存します。
FileSaverを使えば、とてもシンプルに生成したファイルを保存することができます。

saveAs(zip.generate({ type: 'blob' }), 'example.zip');

簡単ですね。

まとめ

実際のところ、クライアントのzip圧縮はブラウザや容量の制限があるため導入の際には検討が必要です。 しかしながら、サーバーサイドに負荷をかけずにzipファイルを生成できるのは魅力的ですねヽ(・∀・ )ノ

明日は @uchienneo がSketchについて話をしてくれます。

備考

  • クロスブラザ対応などのコードは排除しています
  • Gistにコードをまとめました
  • 導入の際にはJSZipの制限を読んで検討してください
  • jQuery.ajaxarraybufferに対応していません。それでもjQueryを使いたい場合は、jQuery.ajaxTransportを使ってカスタマイズしてください

エンジニア募集!

pixivではWEBアプリケーションエンジニアを絶賛募集中です。