技術めいた何か

1人の大学生によるIT系の記事群

Google Apps Script と Twilio で自作留守電サービスを構築してみた話

2016/08/16

Githubに公開しました。そのうち、いま運用している差分もそっちにあげます。

github.com

 

ブログ更新、久々です。

僕は、格安sim(IIJ mio)のユーザーで留守電サービスを利用していないです。

今回はGoogle Apps Script(無料) と KDDIのTwilio(試用期間で無料)を使ってお遊びで留守電サービスを構築してみました。

 

必要なもの

・携帯の電話番号

Google アカウント

・Twilioのアカウント(新規で作った)

 

全体像の構想

www.questetra.com

上記のページのような具合。Google Apps EngineではなくGoogle Apps Scriptだけど。

実際にはこれに、

・メールで通知する機能

Google Driveのフォルダに録音データを保存する機能

・Twilioのサーバーから録音データを削除する機能

を加えた。

 

留守電として動作させるために、Androidスマホの方でx秒受話しなかったらTwilioの番号へ転送するようにしている。

(試しに40秒で設定中)

 

動作した様子(コーディングとかについては下の方を参照)

f:id:atofaer:20160813033956j:plain

f:id:atofaer:20160813033751j:plain

 

コーディングとか

コーディングは1時ぐらいに開始。雑魚なのでところどころ詰まって終わったのは3時くらい。

 

大まかな流れは

事前にGASのtwilio_ response_voice.gsの公開リンクをTwilioのTwiML AppsのREQUEST URLに登録する。

f:id:atofaer:20160813032426p:plain

Twilioの番号に着信があるとREQUEST URLへPOST(設定次第ではGET)がいくのでTwilioにしてほしい動作に合わせてXMLを返す。

XMLの構成については公式ドキュメントを参照した。

https://jp.twilio.com/docs/api/twiml/record

 

Twilioは受け取ったXMLにもとづいて動作する。今回は女性の声で「只今電話にでることができません〜」といったあと1分が上限の録音をする。

録音が終了すると、TwilioはXMLでいうactionに記したurlへ録音ファイルのurlなどの情報をpostする。それをtwilio_ receive_recorded_voice.gsのdoPostで受け取り、録音ファイルをドライブへ保存したり、そのリンクを入りつけたメールを飛ばしたり、後始末でTwilioサーバー上の録音ファイルを削除したりする。

 

 

twilio_ response_voice.gs

function doGet(e) {
var response_str = "<Response>\n <Say voice=\"woman\" language=\"ja-jp\">只今電話にでることができません。ピーとなったら1分以内の伝言を残してください。</Say>\n <Record action=\"https://script.google.com/macros/s/{GASID}/exec\" method=\"post\" maxLength=\"360\" />\n</Response>";
var out = ContentService.createTextOutput(response_str);
out.setMimeType(ContentService.MimeType.XML);
return out;
}
function doPost(e) {
var response_str = "<Response>\n <Say voice=\"woman\" language=\"ja-jp\">只今電話にでることができません。ピーとなったら1分以内の伝言を残してください。</Say>\n <Record action=\"https://script.google.com/macros/s/{GASID}/exec\" method=\"post\" maxLength=\"360\" />\n</Response>";
var out = ContentService.createTextOutput(response_str);
out.setMimeType(ContentService.MimeType.XML);
return out;
}

 

実際には{GASID}の部分は ↓のtwilio_ receive_recorded_voice.gsの公開urlに合わせてIDを指定。

twilio_ receive_recorded_voice.gs

var accountSid="{YourAccountSid}";
var auth_token="{YourToken}";

function doGet() {
var out = ContentService.createTextOutput("");
out.setMimeType(ContentService.MimeType.XML);
return out;
}

function doPost(e)
{
var now_date = new Date();
var file_name = now_date.toLocaleString();
var recode_file_url = e.parameter['RecordingUrl'];
var response = UrlFetchApp.fetch(recode_file_url);
var fileBlob = response.getBlob();
fileBlob.setName(file_name);
var outputDir = DriveApp.getFolderById("{YourFolderID}}");
var voiceDetail = outputDir.createFile(fileBlob);
voiceDetail.setSharing(DriveApp.Access.PRIVATE, DriveApp.Permission.EDIT);
var sharingUrl = voiceDetail.getUrl();

send_e_mail(file_name,sharingUrl);
delete_voice_recorded_data(recode_file_url);
var out = ContentService.createTextOutput("");
out.setMimeType(ContentService.MimeType.XML);
return out;
}

var options = {
method: "delete",
headers: {
Authorization: " Basic " + Utilities.base64Encode(accountSid + ":" + auth_token)
},
muteHttpExceptions: true
};

function delete_voice_recorded_data(url_data){
url_data+=".json";
var now_date = new Date();
var file_name = now_date.toLocaleString();
var response = UrlFetchApp.fetch(url_data,options);
//send_e_mail("元メッセージ削除通知",response.getResponseCode());
}

function send_e_mail(date_str,share_url){
var mailTo = "{yourmailaddress}";
var subject_str = date_str+"の留守電";
var body_str = date_str+"に留守電がありました。内容は以下のリンクから確認してください。";
body_str+="\n\n";
body_str+=share_url;
MailApp.sendEmail(mailTo, subject_str, body_str);
}

 

{ほにゃらら}の部分はその都度任意で。アクセストークンはTwilioのものを使用。

https://jp.twilio.com/user/account/developer-tools/api-explorer/recording-delete

 

上記urlにログインした状態でアクセスするとREST APIの使い方とかが何となくわかる。

 

今わかっている問題点

メールの本文からは相手の電話番号がわからない。

    →Twilioからかかってきた相手の番号をしらべることはできるが、すべて自身の電話から転送する形をとっているため、大元辿った番号がわからない

メールが送られてきた時間とスマホ側の電話の受信履歴を見ればある程度予想はつくだろうけども。。。 

 

ブログ書いちゃったけど、ディジコンのLT_Matchに使うネタとして温存しときたい(願望)