背景
保育園の役員や謝恩会の委員、アルバム制作など、多くの人が経験することとと思います。
その中で、アルバム制作の写真集めを、GASを使って効率化した話を書きます。
エンジニアの仕事の効率化ではないことを最初に謝っておきます。ごめんなさい。
長女(9)の時に苦労して、長男(7)の時に効率化した話です。
GASのコードは、初めてGASを書いた状態なので燦々たる状態ですが、現状リファクタリングニーズがないのでこのまま供養します。
課題
子供達の保育園では、卒園アルバム制作が保護者のタスクとなっています。
例年、下記の内容でアルバム制作を進めています。
- 業者選定
- 分担(デザイン、撮影、データ)
- 分担に分かれて作業
- 納品
- 配布
この中で、データ担当になり、写真データを集めて管理していた話です。
年にもよりますが、長女の時は、3000枚程度の写真を集めていました
何時間もかけて集めた写真をスキャンしていました、、、、
「各自、スキャンして送ってもらうのが良いが、メールで送ってもらったのを分類するのも大変そう、、、、どうせなら色々と自動でできないかしら。」
と思ったということで、長男の時には、いろんな条件で特定のドライブに移すものを作りました
使うもの
- Googleメールアドレス
- 画像メールの受け子
- Googleドライブ
- 画像の格納先
- GoogleAppScript
- いろいろ(後述)
- GoogleSpreadsheet
- いろいろの設定(後述)
GAS + SpreadSheetで行ったこと
- GAS
- 新着メールからの複数画像ファイルをSpreadSheetで指定したファイルへの移動
- メールタイトルとフォルダを対応付け
- ファイル→メールのトレーサビリティを確保するため、メールの日時をファイル名に付与(ファイルサイズが小さい等の返信をすることがあるので結構重要)
- SpreadSheetで指定したファイル名への変更
- 連番_〇〇ちゃん、というprefixを付けて、ソートできるようにした
- 新着メールからの複数画像ファイルをSpreadSheetで指定したファイルへの移動
新着メールからの複数画像ファイルをSpreadSheetで指定したファイルへの移動.gs
function gmailFileUploader(){
//スプレッドシートを読み込む
var spreadsheets = SpreadsheetApp.openById(SPREADSHEET_ID);
var spreadsheet = spreadsheets.getSheetByName("フォルダ");
//二次元配列に
var data = spreadsheet.getRange(1,1,spreadsheet.getLastRow(),2).getValues();
//タイトル名の配列と、ファイル名の配列にする
folderArray = [];
titleArray = [];
for(var i = 0; i < data.length ; i++){
titleArray.push(data[i][0]);
folderArray.push(data[i][1]);
}
var Threads = GmailApp.getInboxThreads();
for(var i=0;i<100;i++){
if (!Threads[i]){return;}//メールがなければ抜ける
var status = Threads[i].isUnread();
var status_save = false;
if(status==true){
var subject = Threads[i].getMessages()[0].getSubject();
for (var k = 0;k < titleArray.length;k++){
if(data[k] != null && subject==titleArray[k]){//タイトルは0列目に
for(var i_msg = 0; i_msg < Threads[i].getMessageCount(); i_msg++){
var msg = Threads[i].getMessages()[i_msg];
//既読だったら処理を飛ばして次のmsgへ
if(msg.isUnread() == false){ continue; }
var attachments = Threads[i].getMessages()[i_msg].getAttachments({includeInlineImages:true});
var mailfrom = remove_dot(Threads[i].getMessages()[i_msg].getFrom());
var folders = DriveApp.getFoldersByName(folderArray[k]);//フォルダは1列目に
while(folders.hasNext()){
var folder = folders.next();
for(var j = 0;j<attachments.length;j++){
var data = DriveApp.createFile(attachments[j]);
//ファイル名に時間を入れる
var new_file_name = Utilities.formatDate(msg.getDate(),"Asia/Tokyo","yyyyMMdd-HHmmss") + mailfrom + "_" + attachments[j].getName();
data.setName(new_file_name);
folder.addFile(data);
status_save=true;
}
}
if(status_save){
msg.markRead();//保存終了したら既読にする
}
}
continue;//一致するタイトルが見つかったら次のループへ
}
}
}
}
}
//あとでメールアドレスから名前に変換するため、メールアドレスの@以前のドットを抜いた状態でファイル名につける
function remove_dot(mail_from){
var reg = /<.*@.*>/g;
var ret = "";
if(mail_from.length > 0 && mail_from.match(reg) != null){
ret = mail_from.match(reg)[0];
}else{
ret = mail_from;
}
ret = ret.split("@")[0].replace(/@*/g,"").split('<').join('').split('.').join('');
return ret;
}
SpreadSheetで指定したファイル名への変更.gs
function myFunction() {
//スプレッドシートを読み込む
var spreadsheets = SpreadsheetApp.openById(SPREADSHEET_ID);
var spreadsheet = spreadsheets.getSheetByName("よみかえ");
//エリアのサイズを取得
var rowSize = spreadsheet.getDataRange().getHeight();
var colSize = spreadsheet.getDataRange().getWidth();
//jpegのみ収集
var files = DriveApp.getFilesByType(MimeType.JPEG);
var froms = spreadsheet.getRange(1, 1, rowSize, 1).getValues();
var tos = spreadsheet.getRange(1, 2, rowSize, 1).getValues();
//ファイル全てに対してループ
var count = 0;
while (files.hasNext()) {
var file = files.next();
for(var i = 1; i < rowSize ; i++){
var from = froms[i]
var name = tos[i]
//ファイル名に指定文字列が含まれる、かつ、読み替え後文字列が存在すれば読み替える
if(file.getName().indexOf(from) > 0 && name.length > 0){
var fname = file.getName();
file.setName(name + fname.replace(from,""));
Logger.log(fname);
count++;
//読み替えたら次ループへ
continue;
}
}
}
Logger.log(count);
}
- SpreadSheet※個人情報満載なのでつけられません
- タイトルによる格納先一覧
- フォルダと、メールタイトルの対応付け
- メールアドレスによる自動ファイル名付け一覧
- 送信元メールアドレス(@以前のみ、ドットは削除)と、つけるprefixの対応付け
- タイトルによる格納先一覧
運用
- 写真は、専用のメールアドレスにファイル添付で送ってもらうこととする
- 「2歳児クラス」等の学年や、「5才遠足」等のイベントごとに、メールのタイトルと氏名等を含めたメールを作成するURL・QRコードを作成して一覧配布
- 同時にLINEでも○歳は、タイトル「○才」で送ってね、という周知
- (※ページの都合で、「5歳クラス」と「5歳遠足」というMECEじゃない分け方で困りそうな感じなのは私のせいじゃない)
振り返り等々
- タイトル指定はなかなか難しい(半角全角の表記ゆれ等)
- メールでデータを送る、が慣れていない人も
- そもそもスキャンしたくない人も多くいた(そういう人は、スキャンしてまで送りたくない、となって枚数が減ってしまう。写真集めをタスクとしている身としては、目的を満たせないかなり大きな問題)
- スキャン環境がない人の分は現物を受け取って実施した。以前と比べると現物受け取り枚数は減ったので、スキャンの負担をある程度分散できたように思う
- この仕組みを使っても使わなくても、スキャン画像の荒さなどの問題がでる
- 学年間違えて送ったりは目検で救済
- 複数人から同じ写真が送られてくることがあり、皆が気に入って買っている写真があるのもあったが、人毎に分かれてしまうので、似た写真がわかるといいなと思った
感想
- GASを当時初めて使ったけれど、便利だと思った、勉強になった!ここから私のGAS生活が始まった、、、!
- 機械学習用の画像データを集めを複数人で行うときに便利かもと思ったり
- 個人情報だらけのため、スプレッドシートが出せなくてすみません
今後
- もう一人、次男(3)の分の仕事が残っています
- この仕組みをまた使うかは分からないが、次回使うなら、画像サイズでの自動返信を入れたい、、、。「画像サイズが小さいので、担当まで現物を渡してください」のような感じで、、、、
- GoogleFormの方が簡単かもしれないとちょっと思っています
- LINEでのコミュニケーションを、Slackに出来たら、まだまだ色々と自動化できそうだな〜と思ったり。(進行スケジュールとか)
- まあ細かい効率化はありますが、結局コミュニケーションを効率化することが一番、、、、
- 4人目の予定はありません。たぶん。