LINE Message APIとGoogle apps scriptを使ってアイデア帳を作る

IT
スポンサーリンク

LINE developerの登録や、アクセストークンの発行等々は色々なブログで共有されているので割愛。

今回はコードを中心とした解説をします。

※この記事は作成途中です。また更新します。(2018/11/11更新)

大まかな流れ




まず、LINE(bot)にメッセージが送られた時の大まかな流れの説明。
LINEにメッセージが送信されるとwebhook記載のURLにPOST送信でデータが送信されます。
それを最初に受け取る部分、それがdoPOST関数です。
そのため要はdoPOST関数に必要な処理さえ書き込めばそれで事足りるのです。

よく「おうむ返し」するものは作られていますよね。
これは、do POSTで送信されてきたJSONのmessage.typeが「text」であった時のtext部分を一度変数にでも入れて、replyしているだけです。

JSONのtypeについて

ここで、textでない場合はどうなるの?ってすぐに思われた人はいい感じです。
送られてきたJSONのtypeは数種類あります。
LINE Developerのメッセージイベントの確認はこちら

text:皆が良く打つメッセージ(文字列)


JSON:text
{
  "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
  "type": "message",
  "timestamp": 1462629479859,
  "source": {
    "type": "user",
    "userId": "U4af4980629..."
  },
  "message": {
    "id": "325708",
    "type": "text",
    "text": "Hello, world!"
  }
}

sticker:スタンプ


JSON:sticker
{
  "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
  "type": "message",
  "timestamp": 1462629479859,
  "source": {
    "type": "user",
    "userId": "U4af4980629..."
  },
  "message": {
    "id": "325708",
    "type": "sticker",
    "packageId": "1",
    "stickerId": "1"
  }
}

image:画像


JSON:image
{
  "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
  "type": "message",
  "timestamp": 1462629479859,
  "source": {
    "type": "user",
    "userId": "U4af4980629..."
  },
  "message": {
    "id": "325708",
    "type": "image"
  }
}

audio:音声


JSON:audio
{
  "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
  "type": "message",
  "timestamp": 1462629479859,
  "source": {
    "type": "user",
    "userId": "U4af4980629..."
  },
  "message": {
    "id": "325708",
    "type": "audio"
  }
}

file:ファイル


JSON:file
{
  "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
  "type": "message",
  "timestamp": 1462629479859,
  "source": {
    "type": "user",
    "userId": "U4af4980629..."
  },
  "message": {
    "id": "325708",
    "type": "file",
    "fileName": "file.txt",
    "fileSize": 2138
  }
}

video:動画


JSON:video
{
  "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
  "type": "message",
  "timestamp": 1462629479859,
  "source": {
    "type": "user",
    "userId": "U4af4980629..."
  },
  "message": {
    "id": "325708",
    "type": "video"
  }
}

location:位置情報


JSON:location
{
  "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
  "type": "message",
  "timestamp": 1462629479859,
  "source": {
    "type": "user",
    "userId": "U4af4980629..."
  },
  "message": {
    "id": "325708",
    "type": "location",
    "title": "my location",
    "address": "〒150-0002 東京都渋谷区渋谷2丁目21−1",
    "latitude": 35.65910807942215,
    "longitude": 139.70372892916203
  }
}

これで全て網羅できてると思うのですが、何か他にあれば教えて下さい(^-^)

用は送られてきたmessage.typeが上記の場合の処理を記載すればスタンプであろうが、位置情報であろうが適切にreplyすることができます。

アイデア帳コード解説

ざっと処理の流れ

1.LINE Message APIにメッセージを送るmessage.type→text
※Message.typeがtext出ない場合は”処理できないよ!”ってreplyする。
2.textがhelpの場合、使い方をreplyする。
3.textがspreadの場合、GoogleSpreadSheetURLをreplyする。
4.textがideaの場合、ideaをreplyする。
5.testが上記以外の場合、ユーザが入力したtextをシートに書き込む。

少し細かく処理の流れ

2は、message.textを一度変数に入れ、helpと”==”か?って処理をして”TRUE”が返却されれば使い方をreplyすれば良いですね。
3は、2同様GoogleSpreadSheetURLをreplyすれば良いですね。
4は3同様。
5は、上記以外でいけそうです。

問題は、3と4のGoogleSpreadSheetのURL取得(3.1)と、GoogleSpreadSheetへの書き込み(4.1)、GoogleSpreadSheetのideaの取得(4.2)といったところでしょうか。
3.1はGoogleSpreadSheetのClass ServiceのgetURLメソッドを使用すれば大丈夫ですね。
ScriptApp.getService().getURL()

4.1、GoogleSpreadSheetへの書き込みはSpreadSheet名(id)で対象のSpreadSheetを取得して、SpreadSheetのシート名を取得して、そのシートのセル(◯、×)ってすればなんとかなりそうですね。

4.2、GoogleSpreadSheetのideaの取得は4.1同様、対象のSpreadSheetを取得して、SpreadSheetのシート名を取得まで同じで、選択対象範囲を指定してやればなんとかできそうですね。

では、実装内容を見ていきましょう。

まず、全貌から。


line.js
// Messaging APIのアクセストークン
var channel_access_token = 'LINE Message APIアクセストークン';
// 応答メッセージAPIのURL
var line_endpoint = 'https://api.line.me/v2/bot/message/reply';
// ユーザープロフィールAPIのURL
var line_endpoint_profile = 'https://api.line.me/v2/bot/profile';
// Main処理
function doPost(e) {
var json = JSON.parse(e.postData.contents);
var reply_token = json.events[0].replyToken;
// POSTのreplyTokenが'undefined'
if (typeof reply_token === 'undefined') {
return;
}
// POSTしたユーザのUserIDを取得する
var user_id = json.events[0].source.userId;
Logger.log(user_id);
// POSTしたユーザのメッセージ内容の取得
var user_message = json.events[0].message.text;
Logger.log(user_message);
// 変数宣言
var reply_messages;
var spreadSheet;
// メッセージ内容分岐
if (user_message === 'help') {
reply_messages = ['スプレッドシートにアクセスしたい場合は「spread」と入力してください。\nアイデアを思い出したくなったら「アイデア」と入力してください。あなたの過去のアイデアをランダムにお伝えします。\n使い方がわからなくなったら「help」と入力してみてください。'];
} else if (user_message === 'spread') {
spreadSheet = getSpreadSheet(user_id);
reply_messages = [spreadSheet.getUrl()];
} else if (user_message === 'idea') {
try {
spreadSheet = getSpreadSheet(user_id);
reply_messages = getRandomIdeas(spreadSheet);
} catch (ex) {
Logger.log(ex);
}
} else if (user_message === 'undefined') {
reply_messages = ['ゴメンナサイ、文字以外の情報には対応していません。\n使い方が知りたいときは「ヘルプ」と入力してみてください。'];
} else {
addToSpreadSheet(user_id, user_message);
reply_messages = ['アイデアが追加されました'];
}
var messages = reply_messages.map(function (v) {
return {'type': 'text', 'text': v};    
});    
UrlFetchApp.fetch(line_endpoint, {
'headers': {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ' + channel_access_token
},
'method': 'post',
'payload': JSON.stringify({
'replyToken': reply_token,
'messages': messages,
}),
});
return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}
function getSpreadSheet(user_id) {  
var sheet_id = PropertiesService.getScriptProperties().getProperty(user_id);  
if (sheet_id == null) { 
return createSpreadSheet(user_id);  
} else {  
try { 
return SpreadsheetApp.openById(sheet_id); 
} catch(e) {  
return createSpreadSheet(user_id);  
} 
} 
} 
function getRandomIdeas(spreadSheet) {  
var ideas = []; 
var sheet = spreadSheet.getSheets()[0]; 
var rowNum = sheet.getLastRow();  
if (rowNum < 1) { 
ideas.push('ゴメンナサイ、この機能を使うには、ある程度の数のアイデアが必要です。アイデアをいくつか入力してみてください。'); 
} else {  
ideas.push('あなたは以前、こんなアイデアを考えていました。');  
var num = getRandom(rowNum);  
ideas.push(getIdea(spreadSheet, num));  
var num2  
for (var i = 0; i < 100; i++) { 
num2 = getRandom(rowNum); 
if (num != num2) {  
break;  
} 
} 
ideas.push(getIdea(spreadSheet, num2)); 
} 
return ideas;   
} 
function addToSpreadSheet(user_id, message) { 
var today = new Date(); 
var spreadSheet = getSpreadSheet(user_id);  
var sheet = spreadSheet.getSheets()[0]; 
sheet.appendRow([today, message]);  
} 
function createSpreadSheet(user_id) {
var spreadSheet = SpreadsheetApp.create("idea(" + getUserDisplayName(user_id) + ")");
var sheet = spreadSheet.getSheets()[0];
sheet.appendRow(['日時', 'メッセージ']);
PropertiesService.getScriptProperties().setProperty(user_id, spreadSheet.getId());
var file = DriveApp.getFileById(spreadSheet.getId());
file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
sheet.setColumnWidth(1, 130);
sheet.setColumnWidth(2, 300);
return spreadSheet;
}
function getUserDisplayName(user_id) {
var res = UrlFetchApp.fetch(line_endpoint_profile + '/' + user_id, {
'headers': {
'Content-Type': 'application/json; charset=UTF-8',
'Authorization': 'Bearer ' + channel_access_token,
},
'method': 'get',
});
return JSON.parse(res).displayName;
}
function getRandom(num) {
return Math.ceil(Math.random() * (num - 1));
}
function getIdea(spreadSheet, num) {
var sheet = spreadSheet.getSheets()[0];
var time = Utilities.formatDate(sheet.getRange((num + 1), 1).getValue(), 'Asia/Tokyo', 'yyyy/MM/dd hh:mm a');
var message = sheet.getRange((num + 1), 2).getValue();
return "(" + time + ")\n" + message;
}
function getSpreadSheet(user_id) {
var sheet_id = PropertiesService.getScriptProperties().getProperty(user_id);
if (sheet_id == null) {
return createSpreadSheet(user_id);
} else {
try {
return SpreadsheetApp.openById(sheet_id);
} catch(e) {
return createSpreadSheet(user_id);
}
}
}

コード解説詳細

各種APIについて


line.js
// Messaging APIのアクセストークン
var channel_access_token = 'LINE Message APIアクセストークン';・・・①
// 応答メッセージAPIのURL
var line_endpoint = 'https://api.line.me/v2/bot/message/reply';・・・②
// ユーザープロフィールAPIのURL
var line_endpoint_profile = 'https://api.line.me/v2/bot/profile';・・・③

①LINE Message APIアクセストークン

これはXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=っていうLINE Developerログインページ記載の長いトークンです。

②応答メッセージAPIのURL

https://api.line.me/v2/bot/message/reply
上記がLINE Developer Document記載のAPIのURLになります。これはこういうものです。

③ユーザープロフィールAPIのURL

https://api.line.me/v2/bot/profile
上記がLINE Developer Document記載のAPIのURLになります。これもこういうものです。

コードについての解説は少しづつしていきます。