Created
September 8, 2017 02:17
-
-
Save dolpen/8c8c6612cdc0d987c29b7f0c3be2f138 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 依存している外部ライブラリ(リソース > ライブラリから追加) | |
// DiscordWebhook(1) : 1QyXmzA-4hugnTy3Nnvbrl0qsSOe4kmStcErJCgtVewfdzlftB0vDUJ-E | |
// SpreadSheetUtils(14) : 1NHmUM9XoGSiIS4UsBMQY0-pFheGsZ-SPCbMIjJ6RPhHGxZYNa2uQcz4c | |
// Twitter(1) : 1M7klEgU3suAbv1S0LUm3oamiI45DYRxSujnYee9qJMIaQ6lWRzjyRI9b | |
var settings = { | |
// oauth_* : https://dev.twitter.com/ 見て作る | |
oauth_consumer_token: '********', | |
oauth_consumer_secret: '********', | |
oauth_access_token: '********', | |
oauth_access_secret: '********', | |
target_screen_name: 'gesotown_shop', // ゲソタウン情報bot | |
read_count: 20, // ツイート収集単位<=200 | |
translation_sheet: 'your_spreadsheet_id', //対訳表ID | |
translation_stages: 'stages', //ルール/ステージ対訳表シート名 | |
translation_gps: 'gps', //ギアパワー対訳表シート名 | |
discord_id: 'id_for_prod', // discordのbot id | |
discord_token: 'id_for_prod', // discordのbot token | |
}; | |
var utils = { | |
time : function(time){ | |
var d = new Date(time); | |
return '' + ('0' + d.getHours()).slice(-2) + ':' | |
+ ('0' + d.getMinutes()).slice(-2); | |
}, | |
datetime : function(time){ | |
var d = new Date(time); | |
return '' + d.getFullYear() + '/' | |
+ ('0' + (d.getMonth() + 1)).slice(-2) + '/' | |
+ ('0' + d.getDate()).slice(-2) + ' ' | |
+ ('0' + d.getHours()).slice(-2) + ':' | |
+ ('0' + d.getMinutes()).slice(-2); | |
} | |
}; | |
// スプレッドシートに[英名,日本名,略名]の対訳表を作っておく | |
var Translation = function(s,p){ | |
var d = {}; | |
SpreadSheetUtils.asWrapper(s,p).getAllRows().forEach(function(row){d[row[0]] = {name:row[1],short:row[2]}}); | |
this.dict = d; | |
}; | |
Translation.prototype = { | |
toShort : function(k){ | |
if(this.dict[k])return this.dict[k].short; | |
return '"'+k+'?"'; | |
} | |
}; | |
// マッチルール/ステージ情報を取得する | |
var info = (function(){ | |
var translation = new Translation(settings.translation_sheet,settings.translation_stages); | |
var endpoint = 'https://splatoon2.ink/data/schedules.json'; | |
var CityInfo = function(){ | |
this.schedule = null; | |
this.cached = null; | |
this.now = new Date(); | |
}; | |
CityInfo.prototype = { | |
_fetch: function(){ | |
if (this.schedule != null)return this.schedule; | |
var resp = UrlFetchApp.fetch(endpoint, { 'method': 'get' }); | |
var data = JSON.parse(resp.getContentText()); | |
this.schedule = data; | |
return data; | |
}, | |
_get: function(mode, time){ | |
return this._fetch()[mode].filter(function(info){ | |
return info.start_time <= time && info.end_time >= time; | |
})[0]; | |
}, | |
_canonical: function(name){ | |
return translation.toShort(name); | |
}, | |
_date: function(time){ | |
return utils.datetime(time); | |
}, | |
_period: function(time){ | |
var r = this._get('regular',time); | |
var g = this._get('gachi',time); | |
var l = this._get('league',time); | |
return '[' | |
+ this._date(r.start_time*1000) | |
+ '〜]\nレ: ' | |
+ this._canonical(r.stage_a.name) | |
+ this._canonical(r.stage_b.name) | |
+ '\nガ: ' | |
+ this._canonical(g.stage_a.name) | |
+ this._canonical(g.stage_b.name) | |
+ this._canonical(g.rule.name) | |
+ '\nリ: ' | |
+ this._canonical(l.stage_a.name) | |
+ this._canonical(l.stage_b.name) | |
+ this._canonical(l.rule.name) | |
+ '\n'; | |
}, | |
_toMessage: function(){ | |
var message = ''; | |
message += this._period((this.now.getTime())/1000); | |
message += '\n' + this._period((this.now.getTime())/1000+3600*2); | |
message += '\n' + this._period((this.now.getTime())/1000+3600*4); | |
return message; | |
}, | |
get: function(){ | |
if (this.cached != null)return this.cached; | |
var message = ''; | |
var info = this._fetch(); | |
message += info ? this._toMessage() : 'ニュースの取得に失敗しました'; | |
this.cached = message; | |
return message; | |
} | |
}; | |
return new CityInfo(); | |
})(); | |
// 直近のサーモンラン予定の取得 | |
var salmon = (function(){ | |
var endpoint = 'https://splatoon2.ink/data/salmonruncalendar.json'; | |
var SalmonInfo = function(){ | |
this.schedule = null; | |
this.cached = null; | |
this.now = new Date(); | |
}; | |
SalmonInfo.prototype = { | |
_fetch: function(){ | |
if (this.schedule != null)return this.schedule; | |
var resp = UrlFetchApp.fetch(endpoint, { 'method': 'get' }); | |
var data = JSON.parse(resp.getContentText()); | |
this.schedule = data.schedules; | |
return data.schedules; | |
}, | |
_getNearest: function(time){ | |
return this._fetch().filter(function(info){ | |
return info.end_time >= time; | |
}).sort(function(a,b){ | |
return a.start_time - b.start_time | |
})[0]; | |
}, | |
_date: function(time){ | |
return utils.datetime(time); | |
}, | |
_period: function(time){ | |
var r = this._getNearest(time); | |
var started = time - r.start_time >= 0; | |
return 'サ: ' + (started?'**【募集中】** ':'準備中 ') | |
+ this._date(r.start_time*1000) + '〜' + this._date(r.end_time*1000) | |
}, | |
_toMessage: function(){ | |
return this._period((this.now.getTime())/1000); | |
}, | |
get: function(){ | |
if (this.cached != null)return this.cached; | |
var message = ''; | |
var info = this._fetch(); | |
message += info ? this._toMessage() : 'バイト情報の取得に失敗しました'; | |
this.cached = message; | |
return message; | |
} | |
}; | |
return new SalmonInfo(); | |
})(); | |
// ゲソタウン新着お知らせbotのツイートを解析して有効なギアの情報を得る | |
var gear = (function(){ | |
var translation = new Translation(settings.translation_sheet,settings.translation_gps); | |
var GearInfo = function(){ | |
this.tweets = null; | |
this.cached = null; | |
this.now = new Date(); | |
}; | |
GearInfo.prototype = { | |
_fetch: function(){ | |
if (this.tweets != null)return this.tweets; | |
var self = this; | |
var twitter = Twitter.newInstance(settings.oauth_consumer_token, settings.oauth_consumer_secret, settings.oauth_access_token, settings.oauth_access_secret); | |
var url = 'https://api.twitter.com/1.1/statuses/user_timeline.json?trim_user=1&screen_name=' | |
+ settings.target_screen_name | |
+ '&count=' | |
+ settings.read_count; | |
var resp = twitter.execRequest(url, 'get', {}); | |
this.tweets = resp.map(function(tweet){ | |
return { | |
w : tweet.text.replace(/(/g,'(').replace(/)/g,')').match(/^([^\(]+)\([^:]+:([^\)]+\)?)\)[^:]+:([^\n]+)[^:]+:([^\(]+)\(([^\)]+\)?)\)/), | |
c : tweet.created_at | |
} | |
}).filter(function(o){return o.w !== null;}).map(function(o){ | |
var tm = new Date(o.c).getTime(); | |
var lt = tm%(1000*3600*2); | |
var w =o.w; | |
[2,3,5].forEach(function(i){w[i] = self._canonical(w[i]);}); | |
return { | |
timestamp : tm - lt + 1000*3600*12, // expires | |
brand : w[4]+'('+w[5]+')', | |
item : w[1]+'('+w[2]+' → '+w[3]+')', | |
name : w[1], | |
spec : w[2]+'+'+w[5]+' → **'+w[3]+'+'+w[5]+'**', | |
isXxx : w[5] == w[3] // bad code!! | |
}; | |
}); | |
return this.tweets; | |
}, | |
_get: function(now){ | |
return this._fetch().filter(function(data){ | |
return data.timestamp >= now; | |
}).sort(function(a,b){ | |
return a.timestamp - b.timestamp; | |
}); | |
}, | |
_date: function(time){ | |
return utils.time(time); | |
}, | |
_canonical: function(name){ | |
return translation.toShort(name); | |
}, | |
_toMessage: function(){ | |
var message = 'ゲ:\n'; | |
var self = this; | |
message += this._get((new Date()).getTime()).map(function(g){ | |
return '[〜' + self._date(g.timestamp) + '] ' + (g.isXxx?'**【違法】**':'') + '\n ' + g.name + ' ( ' + g.spec+' )'; | |
}).join('\n'); | |
return message; | |
}, | |
get: function(){ | |
//if (this.cached != null)return this.cached; | |
var message = ''; | |
var info = this._fetch(); | |
message += info ? this._toMessage() : 'ゲソタウン情報の取得に失敗しました'; | |
this.cached = message; | |
return message; | |
} | |
}; | |
return new GearInfo(); | |
})(); | |
// cron で curl なりすると動くエンドポイント | |
function doGet(){ | |
var discord = DiscordWebhook.newInstance(settings.discord_id, settings.discord_token); | |
var news = '【ハイカラニュース】\n\n' + info.get() + '\n' + salmon.get() + '\n\n' + gear.get(); | |
discord.send(news); | |
return ContentService.createTextOutput("{}").setMimeType(ContentService.MimeType.JSON); | |
} | |
// 検証用 | |
function doTest(){ | |
var discord = DiscordWebhook.newInstance('id_for_test','token_for_test'); | |
var news = '【ハイカラニュース】\n\n' + info.get() + '\n' + salmon.get() + '\n\n' + gear.get(); | |
Logger.log(news); | |
discord.send(news); | |
return ContentService.createTextOutput("{}").setMimeType(ContentService.MimeType.JSON); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment