初心者でもわかるGoogle Apps Script活用のススメ

GoogleドライブとGoogleフォトで無料で無制限に写真/動画をバックアップする

スマホで写真や動画を撮影する人は少なくないと思いますが、手軽に撮れるからこそついつい撮りすぎてしまって大量の写真/動画をどこにバックアップしたら良いか迷ってしまう人も少なくないのではないでしょうか?

今回の投稿では写真をGoogleフォトから自動でGoogleドライブにバックアップして、自動で年ごと、月ごとに写真を仕分けしてくれるシステムをご紹介します。

GoogleフォトというアプリはGoogleから提供されているアプリですが、iOSでもAndroidでも利用することができまるアプリです。

 

Googleフォトの便利さは他のサイトでもよく記事が書かれていたりしますので、このページではアプリの説明については割愛したいと思います。

Googleフォト自体はとても便利なアプリなのですが、バックアップしたGoogleフォトフォルダをGoogleドライブから確認すると写真のフォルダ分けは年ごとでしか行われていないことに気づくと思います。

写真をそれほど取らない人であればそれほど問題にはならないと思いますが、1年に数百枚や数千枚、数万枚と撮影する写真愛好家の方からすると、膨大な写真ファイルの中から自分の探している写真を見つけるのは一苦労です。

これは私のGoogleフォトフォルダですが、年フォルダがGoogleフォトフォルダの直下にあり、年フォルダを開くとその年に撮影した写真や動画がズラッと保存されてしまいます。

そこで、Google Apps Scriptの簡単なコードで自動で撮影年月に仕分けしてくれるシステムを作ってみましたので紹介します。私の場合は、このプログラムを毎日1回自動で起動するように設定しており、Googleフォトフォルダに写真があれば自動的に写真と動画のフォルダに分けて撮影年月で仕分けされるようにしてあります。

写真を探す手間がすごく軽減されました。

Android端末であれば写真や動画を撮影すれば自動的にGoogleフォトでアップロード・仕分けをしてくれますので、ほぼ手間いらずで写真のバックアップができます。バックアップしたメディアファイルは削除してしまっても問題ありません。iOS端末であっても撮影後Googleフォトアプリを一度開けば新規で撮影した画像/動画が自動的にアップロードされるので、とても簡単にバックアップを取ることができます。

おかげさまで、私のスマホは写真や動画を端末に保存しておく必要がないので同じ端末を長く使っていてもそれほど内蔵の保存容量を消費していません。(128GBの端末を購入したのですが、全く必要性がありませんでした)

それでは、長い前置きとなりましたが、スクリプトを下記に記載致します。

プログラムを実行する前に、写真フォルダと動画フォルダを事前にドライブの何処かに作成しておいて下さい。

sortMediaFiles()

写真自動仕分けプログラム
var GooglePhoto = DriveApp.getFolderById("{{ googlePhotoFolderId }}"); //{{から}}までを自分のGoogleフォトIDに置き換えて使用
var photoDestinationId = "{{ photoFolderId }}"; //{{から}}までを自分の写真フォルダIDに置き換えて使用
var videoDestinationId = "{{ videoFolderId }}"; //{{から}}までを自分の動画フォルダIDに置き換えて使用

//Googleフォトで自動バックアップされたメディアファイルをさらに自動で撮影年月で仕分けするプログラム
function sortMediaFiles() {
  var properties = PropertiesService.getScriptProperties();
  var triggers = ScriptApp.getProjectTriggers();
  var length = triggers.length - 1;
  if (length > 0) {
    var triggerId = properties.getProperty("TriggerId");
    for (var i = 0; i <= length; i++) {
      if (triggers[i].getUniqueId() == triggerId) {
         ScriptApp.deleteTrigger(triggers[i]);
      }
    }
  }
  var duration = 7 * 60 * 1000;
  var triggerId = ScriptApp.newTrigger("sortMediaFiles")
                           .timeBased()
                           .after(duration)
                           .create()
                           .getUniqueId(); //6分以上処理時間がかかったときに自動的に再起動させるための時間トリガーをセット
  properties.setProperty("TriggerId", triggerId);
  var folders = GooglePhoto.getFolders();
  while (folders.hasNext()) { //Googleフォトフォルダ内に小フォルダがあればループする
    var folder = folders.next();
    var folderId = folder.getId();
    var sourceFolder = DriveApp.getFolderById(folderId);
    var files = folder.getFiles();
    while (files.hasNext()) { //小フォルダ内にファイルがあればループする
      var file = files.next();
      var fileId = file.getId();
      var targetFile = DriveApp.getFileById(fileId);
      var mimeType = file.getMimeType();
      if (mimeType.match(/image/)) { //対象ファイルが写真ファイルだった場合の処理
        var fileData = Drive.Files.get(fileId);
        var picFile = fileData.imageMediaMetadata;
        var destFolder = DriveApp.getFolderById(photoDestinationId);
        if (picFile === undefined) {
          continue;
        }
        else if (picFile.date === undefined) { //撮影日が保存されていなかった場合の処理
          var date = fileData.createdDate
                             .replace(/T.+/, "")
                             .replace(/-\d+$/, "月")
                             .replace(/-/, "年");
        }
        else { //撮影日が保存されていた場合の処理
          var date = picFile.date
                            .replace(/\s.*/, "")
                            .replace(/:\d+$/, "月")
                            .replace(/:/, "年");
        }
      }
      else if (mimeType.match(/video/)) { //対象ファイルが動画ファイルだった場合の処理
        var destFolder = DriveApp.getFolderById(videoDestinationId);
        var videoFile = Drive.Files.get(fileId)
        var date = videoFile.createdDate
                            .replace(/T.+/, "")
                            .replace(/-\d+$/, "月")
                            .replace(/-/, "年");
      }
      var year = date.match(/.+年/);
      var month = date.match(/\d+月$/);
      var yearFolders = destFolder.getFolders();
      var flg1 = true;
      while (yearFolders.hasNext()) { //移動先の写真/動画フォルダに対象年フォルダがあればループ処理する
        var yearFolder = yearFolders.next();
        var folderName = yearFolder.getName();
        if (folderName == year) { //対象年フォルダがあれば、if内処理を実行
          var yearFolderId = yearFolder.getId();
          var yearFolder = DriveApp.getFolderById(yearFolderId);
          var monthFolders = yearFolder.getFolders();
          var flg2 = true;
          while (monthFolders.hasNext()) { //対象年フォルダ内にフォルダがあればループ処理する
            var monthFolder = monthFolders.next();
            var folderName = monthFolder.getName();
            if (folderName == month) { //対象月に合致すればそのフォルダにファイルを移動させる
              var monthFolderId = monthFolder.getId();
              var targetFolder = DriveApp.getFolderById(monthFolderId);
              targetFolder.addFile(targetFile);
              sourceFolder.removeFile(targetFile);
              flg2 = false;
            }
          }
          if (flg2) { //対象月に合致しなければ対象年フォルダに月ファイルを作成してファイルを移動させる
            var createFolderId = yearFolder.createFolder(month).getId();
            var createFolder = DriveApp.getFolderById(createFolderId);
            createFolder.addFile(targetFile);
            sourceFolder.removeFile(targetFile);
          }
          flg1 = false;
        }
      }
      if (flg1) { //対象年フォルダがなければ年フォルダと月フォルダを作成してファイルを移動させる
        var createFolderId = destFolder.createFolder(year).getId();
        var createFolder = DriveApp.getFolderById(createFolderId);
        var createFolderId = createFolder.createFolder(month).getId();
        var createFolder = DriveApp.getFolderById(createFolderId);
        createFolder.addFile(targetFile);
        sourceFolder.removeFile(targetFile);
      }
    }
  }
  //上記ループ処理が完了したら時間トリガーを削除する
  var triggers = ScriptApp.getProjectTriggers();
  var triggerId = properties.getProperty("TriggerId");
  var length = triggers.length - 1;
  for (var i = 0; i <= length; i++) {
    if (triggers[i].getUniqueId() == triggerId) {
       ScriptApp.deleteTrigger(triggers[i]);
    }
  }
}

簡単な使用方法

一番上にグローバル変数として指定している

var GooglePhoto
var photoDestinationId
var videoDestinationId

の{{ }}部分をご自分のフォルダIDに置き換えることによってプログラムが動作するようになります。フォルダIDの確認方法は、ブラウザで対象のフォルダにアクセスし、フォルダURLの下記**********部分になります。

参考URL:https://drive.google.com/drive/folders/*********************************

***部分をすべてコピーしてコードの””内{{から}}までと置き換えて下さい。

今回のプログラムでは、撮影年月までの仕分けですが、やろうと思えば撮影日ごとに日にちを分けることや、写真のGPS情報を利用して撮影場所によってフォルダ分けを行うことも可能です。

Googleの拡張サービスでDrive APIというものを一部使用しています。プログラムを使用前にDrive APIをコードで使用するための初期設定が必要になりますので、その手順も記しておきます。

Google Drive APIの有効化方法

  1. スクリプトエディタを開き、上部メニューの『リソース』→『Googleの拡張サービス』をクリック

 2. 新しく開いたウインドウでDrive APIを探し、クリック①の部分をクリックしてDrive APIをオンにし、クリック②をクリック

 3. 新しく開いたページの中央上部の検索バーに『Drive』と入力し、選択候補の『Google Drive API』をクリックする

 4. 開いたページの『有効化』ボタンをクリックする

ページが切り替わったらAPIの有効化が完了していますので、ページを閉じてスクリプトエディタへ戻って下さい。

ここまでできましたら、プログラムを実行してみましょう。最初にプログラムにアカウント情報へアクセスする許可が必要となりますので、アカウントタイプに合わせて下記の認証作業を終わらせて下さい。

無料のGmailアカウントでGASに初回の実行許可を与える方法
Google WorkspaceでGASに初回の実行許可を与える方法

プログラム実行後のGoogleドライブ

上記のスクリーンショットのように写真フォルダと動画フォルダに分けて撮影年月によって写真が仕分けされます。年ごとでしかまとめられていなかったものより1フォルダ内の写真数が少ないので、ブラウザの動作も遅くなりませんし、探しているメディアファイルをとても見つけやすくなりました!

※プログラムの実行は自己責任でお願いします。

まとめ

Googleフォトはそのアプリ単体でも完成度が非常に高いアプリですが、Google Apps Scriptを利用すると、今回紹介したプログラムのようにできることの幅が更に広がります。

私の場合は、仕分けをしたほうが圧倒的に写真を探す手間が軽減されました。

ご紹介したプログラムだけでなく、アイディア次第ではいろいろな可能性を秘めている言語だと思いますので、皆さんのGoogle Apps Scriptの活用事例などもぜひ聞いてみたいと思っています!

Exit mobile version