内藤 裕二/ 9月 17, 2018/ GAS, 技術

はじめに

本記事は、Qiita上で2018/9/17に初公開した記事を転記したものです。


発端

知人との一時的なデータのやり取りにGoogle Driveを使用していた。
Google Drive上のファイルに直接アクセスするに記載した方法を使えば、Google Driveを経由してファイルの共有ができる。
ただし、Google Driveには容量制限があるため、不要になったファイルは削除したい。
いちいち共有した相手にダウンロードしたかどうかを尋ねるのも面倒だったので、特定フォルダ配下のファイルのうち、一定時間更新されていないものを削除するスクリプトを作成し、定期的に実行することにした。

作成したスクリプト

スクリプトは下記よりダウンロード

  • https://github.com/rot-z/GasHouseKeepingSample

使用方法

削除処理の対象となるルートフォルダをGoogle Drive上で作成

Google Drive上で適当なフォルダを作成する

自分のGASエディタを開いて、HouseKeeping.gsの内容をすべて張り付け

GASエディタ上で、HouseKeeping.gsの内容をすべて張り付ける

拡張サービスでGoogle Driveと連携

下記を参考に、Google Driveと連携する

スクリプトプロパティを設定する

ファイル削除を行うGoogle Drive上のフォルダIDを、スクリプトプロパティの「
ROOT_FOLDER_ID」として設定する

エディタのメニューから「プロジェクトのプロパティ」を選択

ScriptProperty-Menu.jpg

「スクリプトプロパティ」タブを選択し、「行を追加」をクリック
「ROOT_FOLDER_ID」として、対象のGoogle Drive上のフォルダIDを指定する

ScriptProperty.jpg

フォルダIDの調べ方は、スプレッドシート・フォルダのID確認方法参照

Stackdriverとの連携設定

Stackdriverとの連携設定を一度もしていないのであれば、下記を参考に連携設定する

試しに実行

関数「doHouseKeeping」を一度実行する
エラーがなければ、問題なし
初回実行では、アカウントに対するアクセス許可が求められるので、承認する

トリガを設定する

スクリプトを毎日動作するようにトリガを設定する
「現在のプロジェクトのトリガー」を選択

Trigger1.jpg

「トリガーが設定されていません。今すぐ設定するにはここをクリックしてください」をクリック

Trigger2.jpg

関数「doHouseKeeping」を、毎日適当な時間に動作するようにトリガを設定

Trigger3.jpg

「保存」を押せば、毎日不要なファイルの削除処理が走るようになる

主な仕様とカスタマイズ

スクリプトプロパティで指定した特定フォルダの配下のみ対象とする

Google Drive全域を対象に動作すると大変な事になるので、特定フォルダ配下のみ対象とするようにしている

最終更新日が5日以上前のファイルを削除する

スクリプトの下記部分を変更すると、削除対象とするファイルの範囲を変更できる
なお、「for Debug」のコメントのついた行は、デバッグ用に1秒前のファイルを削除するようにしてある

  // Generate target date
  var baseDate = new Date();
  baseDate.setDate(baseDate.getDate() - 5);
  //baseDate.setSeconds(baseDate.getSeconds() - 1);  // for Debug.

空のサブフォルダも削除する

ファイルを削除した結果、空になったサブフォルダも削除する

  for(var i = 0; i < folderList.length; i++){
    // Delete files recursively
    var folderResult = cleanUpFolder(folderList[i].getId(), baseDate);
    if (folderResult.isEmpty){
      // Remember deleted file and subfolder names
      Array.prototype.push.apply(result.removedObjects, folderResult.removedObjects);
      // Remember empty subfolder
      result.removedObjects.push(folderList[i].getName());
      // Delete empty subfolder
      currentFolder.removeFolder(folderList[i]);
    }
  }

ループの中のisEmptyを参照しているブロックをそのままコメントアウトすれば、空フォルダは残るようになる

  for(var i = 0; i < folderList.length; i++){
    // Delete files recursively
    var folderResult = cleanUpFolder(folderList[i].getId(), baseDate);
    //if (folderResult.isEmpty){
    //  // Remember deleted file and subfolder names
    //  Array.prototype.push.apply(result.removedObjects, folderResult.removedObjects);
    //  // Remember empty subfolder
    //  result.removedObjects.push(folderList[i].getName());
    //  // Delete empty subfolder
    //  currentFolder.removeFolder(folderList[i]);
    //}
  }

スクリプト実行後、Google Driveのゴミ箱を空にする

Drive APIのFolder.removeFileを使用した際、当該フォルダの配下ではなくなっても、ファイル実体が残るケースがあった
(数日経過して、容量使用率が減らずに発覚)
そのため、removeFileを使用せず、一旦ゴミ箱に入れた後、ゴミ箱を空にする、という処理になっている。

Google Driveのゴミ箱は全フォルダ共通なので、問題ある場合は下記部分をコメントアウト

  // Empty trash.
  // If this code isn't exist, Google drive entity still survived.
  Drive.Files.emptyTrash();

参考

スクリプト自体はそれほど複雑なことをやっていないので、個別に調べれば詳細が見つかるはず