10
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

GASのLINEボットで受け取った画像をGoogleドライブに保存する(+LINEボットについての雑記)

Last updated at Posted at 2020-07-18

#はじめに
LINEボットの基礎的なアレコレは以下の記事が詳しいです。

Google Apps ScriptでLINE BOTつくったら30分で動かせた件 (@hakshuさん)

LINEボットを初めて作る方は、先にこちらを読んだ方が良いでしょう。手順やサンプルコードが簡潔にまとめられているので、LINEボット作成がどんなものかの理解に繋がると思います。

ただし上記記事をベースにコードを書く場合、サンプルコードの以下の部分:

var userMessage = JSON.parse(e.postData.contents).events[0].message.text;

こちらは、

var event = JSON.parse(e.postData.contents).events[0];
var userMessage = event.message.text || "";
var event = JSON.parse(e.postData.contents).events[0];
if(event.message.type == "text") {
  var userMessage = event.message.text;
  ...
}

のように(あるいはもっと適した形に)書き直した方が良いです。本記事で示す通り、ボットが受け取るメッセージのtypetextだけではないためです。…もっと詳しく言うと、event.messageオブジェクトの中身は、そのtypeごとに異なります。

type=textのときのevent.message
{
  type: 'text',
  text: 'aaaaa'
}
type=imageのときのevent.message
{
  type: 'image',
  id: 1234567890,
  ...
}

typeがimageのときは、event.message.textは存在しませんね。そういうことです。


#本題(コード)
特に説明することはないです。

.gs

//LINEボットのアクセストークン
var ACCESS_TOKEN = 'ACCESS_TOKEN';
//Googleドライブに作ったフォルダのURLの末尾にある30文字くらいの文字列
var FOLDER_ID = 'FOLDER_ID';
//返信用エンドポイント
var REPLY_URL = 'https://api.line.me/v2/bot/message/reply';

function sendMsg(url, payload) {
  UrlFetchApp.fetch(url, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify(payload),
  });
}
function getImage(id) {
  //画像取得用エンドポイント
  var url = 'https://api-data.line.me/v2/bot/message/' + id + '/content';
  var data = UrlFetchApp.fetch(url,{
    'headers': {
      'Authorization' :  'Bearer ' + ACCESS_TOKEN,
    },
    'method': 'get'
  });
  //ファイル名を被らせないように、今日のDateのミリ秒をファイル名にしています
  var img = data.getBlob().getAs('image/png').setName(Number(new Date()) + '.png');
  return img;
}
function saveImage(blob) {
  try{
    var folder = DriveApp.getFolderById(FOLDER_ID);
    var file = folder.createFile(blob);
    return file.getUrl();
  }catch(e){
    return false;
  }
}
function doPost(e) {
  var event = JSON.parse(e.postData.contents).events[0];
  if(event.message.type == 'image') {
    try {
      var img = getImage(event.message.id);
      var url = saveImage(img);
      sendMsg(REPLY_URL, {
        'replyToken': event.replyToken,
        'messages': [{
          'type': 'text',
          'text': url ? "保存しました:\n" + url : "ダウンロードエラー",
        }]
      })
    }catch(e) {
      Logger.log(e);
    }
  }
  return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}

受信した画像の取り扱いに非常に難儀しました。バイナリねえ…。


###雑記
本題から逸れますが、トークンやURLなどの変数やらは、GASのプロジェクトのプロパティ(「ファイル」→「プロジェクトのプロパティ」)に環境変数みたいな形で保存できます。
2cOaJ.png

保存した変数は以下のようにすることで取得できます。

.gs
function PROPERTY(key) {
  return PropertiesService.getScriptProperties().getProperty(key);
}
var ACCESS_TOKEN = PROPERTY("ACCESS_TOKEN");
var FOLDER_ID = PROPERTY("FOLDER_ID");

ボットの機能を拡張する度に、DB用のスプレッドシートのIDや、PUSHメッセージ・ユーザープロフィール取得用のエンドポイントURLなどなど、必要な変数は一気に増えます。ヘンな文字列がいっぱいコード上にあると、コードの可読性は一気に低下します。是非ご活用ください。

10
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?