Javascript で再開可能アップロードを使って大きなサイズのファイルを非同期で Google Drive へアップロードする

# 背景と概要

大きなサイズのファイル(5 MB 以上あるいは 50 MB 以上)を Google Drive へアップロードしようとすると、[再開可能アップロード(Resumable upload)](https://developers.google.com/drive/api/v3/manage-uploads#resumable)のプロセスを行う必要があります。Javascript を使用してブラウザからファイルをアップロードするとき、多くの場合は公式のライブラリである[google-api-javascript-client](https://github.com/google/google-api-javascript-client)を使用します。この場合、Google Docs ファイルの新規作成や 5 MB 以下のファイルをアップロードすることは可能ですが、この記事を書いた段階では再開可能アップロードを行うためのメソッドはまだ用意されていません。そこで、Javascript を使って大きなサイズのファイルを再開可能アップロードプロセスでアップロードするための[ライブラリ](https://github.com/tanaikech/ResumableUploadForGoogleDrive_js)を作成しました。

ここでは、このライブラリを使用したサンプルとして、大きなサイズのファイル(100 MB)を 5 つ用意し、これを非同期で Google Drive へアップロードするスクリプトを紹介させていただきます。

# ResumableUploadForGoogleDrive_js

ResumableUploadForGoogleDrive_js は、Drive API を使用してファイルを再開可能アップロードするための Javascript 用ライブラリです。リポジトリは[こちら](https://github.com/tanaikech/ResumableUploadForGoogleDrive_js)です。詳細な使用方法は、リポジトリをご覧ください。

# 使い方

## 1. スプレッドシートの作成

ここでは、スプレッドシートを作成し、スプレッドシート上へ開いたサイドバーでスクリプトを実行させます。そのため、最初にスプレッドシートを作成してください。作成後、スクリプトエディタを開いてください。

## 2. サンプルスクリプトをコピーペースト

Google Apps Script と HTML&Javascript の 2 種類のスクリプトを使用します。そのため、スクリプトエディタを開いた際、ファイル->新規作成->HTML ファイル として HTML ファイルを作成してください。ファイル名は`index.html`です。

### Google Apps Script: コード.gs

下記のスクリプトを`コード.gs`へコピーペーストします。

```javascript
function main() {
  var html = HtmlService.createHtmlOutputFromFile("index");
  SpreadsheetApp.getUi().showSidebar(html);
}

function getAuth() {
  // DriveApp.createFile(blob) // This is used for adding the scope of "https://www.googleapis.com/auth/drive".
  return ScriptApp.getOAuthToken();
}
```

### HTML: index.html

下記のスクリプトを作成した`index.html`へコピーペーストします。ライブラリは、jsdelivr cdn を使ってロードしています。また、アクセストークンは Google Apps Script 側で取得しています。

```html
<input type="file" id="file" multiple="true" />
<input type="button" onclick="run()" value="Upload" />
<div id="progress"></div>

<script src="https://cdn.jsdelivr.net/gh/tanaikech/ResumableUploadForGoogleDrive_js@master/resumableupload_js.min.js"></script>
<script>
  function run() {
    google.script.run
      .withSuccessHandler(accessToken =>
        ResumableUploadForGoogleDrive(accessToken)
      )
      .getAuth();
  }

  function ResumableUploadForGoogleDrive(accessToken) {
    const f = document.getElementById("file");
    [...f.files].forEach((file, i) => {
      let fr = new FileReader();
      fr.fileName = file.name;
      fr.fileSize = file.size;
      fr.fileType = file.type;
      fr.readAsArrayBuffer(file);
      fr.onload = e => {
        var id = "p" + ++i;
        var div = document.createElement("div");
        div.id = id;
        document.getElementById("progress").appendChild(div);
        document.getElementById(id).innerHTML = "Initializing.";
        const f = e.target;
        const resource = {
          fileName: f.fileName,
          fileSize: f.fileSize,
          fileType: f.fileType,
          fileBuffer: f.result,
          accessToken: accessToken
        };
        const ru = new ResumableUploadToGoogleDrive();
        ru.Do(resource, function(res, err) {
          if (err) {
            console.log(err);
            return;
          }
          console.log(res);
          let msg = "";
          if (res.status == "Uploading") {
            msg =
              Math.round(
                (res.progressNumber.current / res.progressNumber.end) * 100
              ) +
              "% (" +
              f.fileName +
              ")";
          } else {
            msg = res.status + " (" + f.fileName + ")";
          }
          document.getElementById(id).innerText = msg;
        });
      };
    });
  }
</script>
```

## 3. スクリプトの実行

スクリプトエディタから ファンクション `main()` を実行すると、スプレッドシート上へサイドバーが表示されます。ここでファイルを選択して Upload ボタンを押すと、ファイルがアップロードされます。下記はデモンストレーションの動画です。

![20191021a-demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133383/a5d32d04-066a-13cc-ce06-73c59277009a.gif)


また、サンプルスクリプトのリポジトリは[こちら](https://github.com/tanaikech/AsynchronousResumableUploadForGoogleDrive)です。

# 参考

- [Perform a resumable upload](https://developers.google.com/drive/api/v3/manage-uploads#resumable)
- [Resumable Upload of Multiple Files with Asynchronous Process for Google Drive](https://github.com/tanaikech/AsynchronousResumableUploadForGoogleDrive)
- [ResumableUploadForGoogleDrive_js](https://github.com/tanaikech/ResumableUploadForGoogleDrive_js)