Skip to content

Instantly share code, notes, and snippets.

@shiranuik
Last active March 19, 2020 09:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shiranuik/d6783773dcaea023cb2a70d56b275c20 to your computer and use it in GitHub Desktop.
Save shiranuik/d6783773dcaea023cb2a70d56b275c20 to your computer and use it in GitHub Desktop.
GAS+PhantomJSで乗り換え検索してくれるSlackBOT
// Naviなんとかさんで経路を検索して教えてくれるSlackBOT
//Slack側で必要なこと
// スラックアプリを新規作成する
// Slash Commandsの設定。
// アプリをワークスペースにインストールする
//GAS側の設定・注意するところ
// 公開するときは「ウェブアプリケーションとして公開
// 自分が実行
// アクセス可能な人:Anyone,even anonymous
// 一度登録した後変更するには、必ず新しいバージョンにして更新すること。
// 使い方( slash commandを /transit として登録した場合 )
// `/transit (到着駅)` or `/transit (出発駅)から(到着駅)`
// phantomjsのKey(一日500ページまで)
const PhantomJSKey = "PhantomJSのKey";
const slackToken = "SlackのアプリのToken";
function doPost(e){
verification(e.parameter.token);
const toStation = e.parameter.text;
const userId = e.parameter.user_id;
if(toStation==""){
return ContentService.createTextOutput(JSON.stringify({text:"駅名を入力して下さい。"})).setMimeType(ContentService.MimeType.JSON);
}
addJobQue(toStation,e.parameter.response_url,userId);
if(toStation.match(/から/)){
return ContentService.createTextOutput(JSON.stringify({text:toStation+"の経路を検索します。1分〜2分ほどかかりますので少々お待ち下さい。"})).setMimeType(ContentService.MimeType.JSON);
}
return ContentService.createTextOutput(JSON.stringify({text:"会社から"+toStation+"の経路を検索します。2分〜3分ほどかかりますので少々お待ち下さい。"})).setMimeType(ContentService.MimeType.JSON);
}
function addJobQue(toStation,responseUrl,userId){
let newQue = {
"toStation":toStation,
"responseUrl":responseUrl,
"userId":userId
};
cache = CacheService.getScriptCache();
let data = cache.get("trangit");
if(data==null){
data = [];
}else{
data = data.split(";");
}
data.push(JSON.stringify(newQue));
// 2分間だけ保存されるキャッシュ。
cache.put("trangit",data.join(";"),60*2);
return;
}
function timeDrivenFunction(){
//cacheの取得
cache = CacheService.getScriptCache();
let data = cache.get("trangit");
if(data==null){
return;
}else{
data = data.split(";");
}
//長い処理に取り掛かる前に、Jobが複数実行されないようQueは空にしておく。
cache.remove("trangit");
for(let i=0; i<data.length; i++) {
data[i] = JSON.parse(data[i]);
let response = getTransit(data[i].toStation,data[i].userId);
UrlFetchApp.fetch(data[i].responseUrl,{
method: 'post',
contentType: 'application/json',
payload: JSON.stringify({
text:response
})
});
}
return;
}
function getTransit(toStation,userId) {
let returnText="";
if(toStation.match(/から/)){
// 出発地の指定がある
let KeiroArg = toStation.split("から");
let fromString = KeiroArg[0];
let toString = KeiroArg[1].replace("まで","");
returnText = returnText + searchTransit(fromString,toString);
} else {
// 指定がないので****からと@@@@からを検索(会社最寄り駅が2つあるので)
returnText = returnText + searchTransit("****",toStation);
returnText = returnText + searchTransit("@@@@",toStation);
}
return "<@"+userId+"> "+returnText;
//Logger.log(returnText);
}
function searchTransit(fromStation,toStation){
let searchURL = "https://www.navitime.co.jp/transfer/searchlist?orvStationName="+fromStation+"&dnvStationCode=&thr1StationName=&thr1StationCode=&thr2StationName=&thr2StationCode=&thr3StationName=&thr3StationCode=&basis=1&sort=0&wspeed=100&airplane=0&sprexprs=0&utrexprs=1&othexprs=1&mtrplbus=1&intercitybus=0&ferry=0";
let optionParam = "&dnvStationName="+ toStation;
let now = new Date();
// 下に降りる時間があるので出発は5分後にする。
now.setMinutes(now.getMinutes() + 5);
let year = Utilities.formatDate(now, 'Asia/Tokyo', 'yyyy');
let month = Utilities.formatDate(now, 'Asia/Tokyo','MM');
let day = Utilities.formatDate(now, 'Asia/Tokyo','dd');
let hour = Utilities.formatDate(now, 'Asia/Tokyo','HH');
let minute = Utilities.formatDate(now, 'Asia/Tokyo','mm');
//さらに5分後の出発で検索するURLのため、念の為すべてを取得
now.setMinutes(now.getMinutes() + 5);
let nyear = Utilities.formatDate(now, 'Asia/Tokyo', 'yyyy');
let nmonth = Utilities.formatDate(now, 'Asia/Tokyo','MM');
let nday = Utilities.formatDate(now, 'Asia/Tokyo','dd');
let nhour = Utilities.formatDate(now, 'Asia/Tokyo','HH');
let nminute = Utilities.formatDate(now, 'Asia/Tokyo','mm');
let nextParam = optionParam + '&year='+nyear+'&month'+nmonth+'&day='+nday+'&hour='+nhour+'&minute='+nminute;
optionParam = optionParam + '&year='+year+'&month'+month+'&day='+day+'&hour='+hour+'&minute='+minute;
let requestParam = {
url:searchURL + optionParam,
renderType:'HTML',
outputAsJson:true};
requestParam = JSON.stringify(requestParam);
requestParam = encodeURIComponent(requestParam);
let url = 'https://phantomjscloud.com/api/browser/v2/'+PhantomJSKey+'/?request='+requestParam;
let response = UrlFetchApp.fetch(url);
let json = JSON.parse(response.getContentText());
let content = json["content"]["data"];
let result = content.match(/name="routeText".*?【1】/g);
let returnText = fromStation+"から"+toStation+"の検索\n";
if(Array.isArray(result)){
result.forEach(function(r){
returnText = returnText + r.replace('name="routeText" value="',"").replace("【1】","").replace("回<br>","回 ").replace("分<br>","分 ").replace("円<br>","円").replace(/<br>/g,"\n") + "\n----\n";
});
returnText = returnText + "<"+searchURL+nextParam+"|"+fromStation+"を"+nminute+"分に出発で検索>\n=====\n";
}else{
returnText = returnText + "検索結果は0件でした。駅名が正しくない可能性があります。\n";
}
return returnText;
}
//tokenCheck
function verification(token){
if( token != slackToken ){
throw new Error('invalid token');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment