福井県河川・砂防総合情報システム(PCサイトhttps://sabo.pref.fukui.lg.jp/および携帯サイトhttp://i-ame.ame.pref.fukui.lg.jp/fukuimelmaga/ameinfos/)の観測データ等がオープンデータであることをいいことに, i-ameメール(福井県河川・砂防総合情報メール)の内容をつぶやく非公式アカウント
ふくいi-ameは, 福井県河川・砂防総合情報システムデータ利用規約に基づき, 福井県河川・砂防総合情報システムから配信されるi-ameメールの内容を, TwitterアカウントとFacebookアカウントで配信しています. (利用規約は, 福井県ホームページ「福井県河川・砂防総合情報システムの観測情報はテレビ放送や報道機関等のホームページでもご覧になれます」に掲載されています.)
ふくいi-ameは以下の著作物を改変して利用しています.
福井県河川・砂防総合情報システム, 福井県・国土交通省近畿地方整備局・福井地方気象台, クリエイティブ・コモンズ・ライセンス表示 2.1 (https://creativecommons.org/licenses/by/2.1/jp/)
ふくいi-ameは, i-ameメールをGMailのメールアカウントで受信し, それを5分おきにGoogleAppsScriptで処理し, Twitter APIでTwitterアカウントに, Facebook Graph APIでFacebookアカウントに投稿しています.
ふくいi-ameのソースコードのうち, GMailメールアカウントで受信したメールの処理, Twitter APIの呼び出し, Facebook Graph APIの呼び出しの部分について掲載します.
GMailメールアカウントで受信したi-ameメールの処理はtweetMail関数で行っています. このtweetMail関数が5分おきに呼び出されます.
NIKUSHI_LOGGERの名前空間が付けられた関数は「Google Apps Script カスタムLoggerでログをspreadsheetに書き出す · Nikushi's blog(http://orihubon.com/blog/2014/06/18/log-to-sheet-by-custom-logger-google-apps-script/(2019年時点のURL))」で紹介されているコードをそのまま利用しています.
var GMAIL_SEARCH_STRING = "in:inbox is:unread"; function tweetMail(){ try { var threads = GmailApp.search(GMAIL_SEARCH_STRING, 0, 20); for(var j=0;j<threads.length;j++){ var msgs = threads[j].getMessages(); for(var i=0;i<msgs.length;i++){ if(msgs[i].isUnread()){ var mailad = msgs[i].getFrom(); mailad = mailad.slice(mailad.indexOf("<")+1,mailad.lastIndexOf(">")); if(mailad == "i-ame@ame.pref.fukui.lg.jp"){ // Twitterの処理 var msgbody = msgs[i].getBody(); msgbody = msgbody.replace(/<br \/>/g,""); msgbody = msgbody.replace(/こちらは、福井県庁です。/,""); msgbody = msgbody.replace(/ /g,""); msgbody = msgbody.replace(/ /g,""); msgbody = msgbody.replace(/---[\w\W]+$/,""); msgbody = msgbody.replace(/=/g,"-"); if(msgs[i].getSubject() == "水位観測情報"){ msgbody = msgbody.slice(0,140); NIKUSHI_LOGGER.debug(msgbody); sendTweet(msgbody); }else if(msgs[i].getSubject() == "雨量観測情報"){ msgbody = msgbody.replace(/※[\w\W]+$/,""); msgbody = msgbody.slice(0,140); NIKUSHI_LOGGER.debug(msgbody); sendTweet(msgbody); }else{ var l; if(msgs[i].getSubject() == "土砂災害警戒情報"){ l = msgbody.indexOf("お知らせします。")+10; }else{ msgbody = msgbody.replace(/\n+新たに発表または解除された市町のみ表示しています。/,""); var strmatch; strmatch = msgbody.match(/^[\w\W]+報[^かに]/); if(strmatch){ l = strmatch[0].length+1; }else{ l = 0; } } if(l >= 100){ // headerとなる部分が100文字以上となる場合, headerは無し l = 0; } var header = msgbody.slice(0,l); var l_bodys = 0; do{ // 140文字づつ(改行の位置で区切る) var body = msgbody.slice(l,l_bodys+140); var l_body = body.lastIndexOf("\n")+1; if(l_body == 0) l_body=body.length; body = body.slice(0,l_body); NIKUSHI_LOGGER.debug(header+body); sendTweet(header+body); l = l + l_body; l_bodys = l_bodys + l_body; }while(l < msgbody.length) } // Facebookの処理 msgbody = msgs[i].getBody(); msgbody = msgbody.replace(/<br \/>/g,""); msgbody = msgbody.replace(/こちらは、福井県庁です。/,""); msgbody = msgbody.replace(/ /g,""); msgbody = msgbody.replace(/ /g,""); msgbody = msgbody.replace(/登録変更解除[\w\W]+$/,""); NIKUSHI_LOGGER.debug(msgbody); sendFBFeed(FB_ID,msgbody); } msgs[i].markRead(); } } } } catch(e) { NIKUSHI_LOGGER.error(e.toString()); } }
Twitter API v2の呼び出しはsendTweet関数で行っています. もともとは、このsendTweet関数は「Google Apps ScriptでOAuthConfigのサポートが終了してTwitter botが危険そうだったので変更 - きじとら(https://kijtra.com/article/twitter-api-for-google-apps-script-without-oauthconfig/)」で紹介されているコードをそのまま利用していました. しかしながら, 2023年5月にTwitter API v1.1のサポートが終了したことから, 現在は「GASからTwitter API v2でツイートする【Google Apps Script】 | prtn-blog(https://prtn-life.com/blog/gas-twitter-api#toc3)」で紹介されているsendTweet関数の最初の部分を下記のとおり修正して利用しています.
function sendTweet(text) { var payload = { text: text }
Facebook Graph APIの呼び出しはsendFBFeed関数で行っています. なお、ソースコード中のアクセストークンやページIDは, ここでは実際の値ではなく****...*と記載しています.
var PAGE_ACCESS_TOKEN = '****...*'; var FB_ID = '****...*'; var FB_BASE_URL = 'https://graph.facebook.com/v2.6/' + FB_ID + '/feed?access_token=' + PAGE_ACCESS_TOKEN; function sendFBFeed(id, text) { var url = FB_BASE_URL; var payload = { 'recipient': id, 'message': text }; payload = Object.keys(payload).map(function(key) { return encodeRfc3986(key) + '=' + encodeRfc3986(payload[key]); }).join('&'); var options = { 'method': 'post', "headers": { "Content-type": "application/json" }, 'payload': payload, muteHttpExceptions: true }; var result = UrlFetchApp.fetch(url, options); var json = JSON.parse(result.getContentText()); if (json) { if (json.error) { NIKUSHI_LOGGER.error(json.error); } } return result; } function encodeRfc3986(str) { return encodeURIComponent(str).replace(/[!'()]/g, function(char) { return escape(char); }).replace(/\*/g, "%2A"); }
GMailのメールを処理する部分の参考にしました.
Twitter APIを使ってTwitterアカウントに投稿する処理の参考にしました.
Facebook Graph APIを使ってFacebookアカウントに投稿する処理の参考にしました.
Facebookアカウントのアクセストークンを取得する際の参考にしました.
デバッグ用にログをスプレッドシートに残す処理の参考としました.
Twitter API v2を使ってTwitterアカウントに投稿する処理の参考にしました.