Slackと同じElectronで出来ているDiscordはSlackのbotの作り方と親和性が高く、ほとんど同じようにDiscord用のbotを作ることが出来ます。
今回はFPSゲームであるApex Legendsのデータトラッカーを利用してDiscordにbotを作成してみます。
概要
ある時間になるとGASがApex LegendsのプレイヤーデータをTRNから取得し、Discordに投稿する
- トリガーが実行される。
- TRNからApex Legendsのプレイヤーデータを取得する。
- プレイヤーデータをDiscordにPOSTする。
- Discordのチャンネルに投稿される。
完成イメージはこんな感じです。
embedという形式で投稿しています。
また、embedを使わない普通の投稿も作ってみました。
作成
TRNでのApex trackerの使い方
現在Apex Legendsは公式のデータトラック用APIを公開していませんが、TRNというデータトラック用のサイトを経由してプレイヤー情報を取得することが出来ます。
TRN Apex Legends API
Apex TrackerをAPIとして使用するためにはAPIのキーが必要です。
TRNのアカウントを登録してログイン後、上のURLの
「Manage or Create API Keys」をクリックします。
適当に使いたい理由を書いてメールを送信すると使えるようになります。
その後APIキーを見ることが出来ます。
管理画面に遷移してもキーを確認できます。
APIキーを取得できたので、トラック情報が取得できるかcurlで確認してみます。
コマンドプロンプトから以下のコマンドを打ちます。
※windowsではcurlコマンドを使えるように別途インストールが必要です。
2021/4/11追記:こちらTRNのAPIバージョンが変わりURLが変わっておりました。
curl https://public-api.tracker.gg/v2/apex/standard/profile/[platform]/[プレイヤー名] -H "TRN-API-KEY:[取得したAPIキー]"
[platform]…プレイしているプラットフォームを入れる。現在origin, play station Network, xbox Liveに対応している。
- Origin … “origin”
- PlayStationNetwork … “psn”
- Xbox Live … “xbl”
プレイヤーデータが返ってきたら無事データを取得できています。
{
"data": {
"id": "XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXX",
"type": "player",
"children": [
{
"id": "legend_5",
"type": "",
"metadata": {
"legend_name": "Bloodhound",
"icon": "https://media.contentapi.ea.com/content/dam/apex-legends/images/2019/01/legends-character-tiles/apex-grid-tile-legends-bloodhound.png.adapt.crop16x9.png",
"bgimage": "https://trackercdn.com/cdn/apex.tracker.gg/legends/bloodhound-concept-bg-small.jpg"
},
"stats": [
{
"metadata": {
"key": "SeasonWins",
"name": "Season Wins",
"categoryKey": "game",
"categoryName": "Game",
"isReversed": false
},
"value": 11.0,
"percentile": 2.1,
"rank": 3688,
"displayValue": "11",
"displayRank": "3,688"
},
{
"metadata": {
"key": "SeasonDamage",
"name": "Season Damage",
"categoryKey": "game",
"categoryName": "Game",
"isReversed": false
},
"value": 27452.0,
"percentile": 3.0,
"displayValue": "27,452",
"displayRank": ""
},
{
"metadata": {
"key": "SeasonKills",
"name": "Season Kills",
"categoryKey": "game",
"categoryName": "Game",
"isReversed": false
},
"value": 80.0,
"percentile": 3.8,
"rank": 9927,
"displayValue": "80",
"displayRank": "9,927"
}
]
},
...
...
}
あとはこのコマンドをGASから打ち込むだけです。
2021/4/11追記:APIのバージョンが上がり、取得できる情報もAPIも増えたようです。
https://tracker.gg/developers/docs/titles/apex
情報が持ってこれない場合、TRNアカウントとApex Legendsアカウントが紐づいていないのでTRN上でアカウントを認識させましょう。
キャラクターはTRNのダッシュボード上の「ADD LEGEND」で追加できます。
Apex Legendsを実際に起動した状態で、ゲーム内でトラッカーに追加したいキャラが選択された状態で「FORCE UPDATE」を押すと反映されます。
トラッカー情報取得まわり
ApexTrack.gs
var key = "[取得したAPIキー]";
function getApexTrack(member) {
var trackUrl = member.trackUrl;
var params={
headers:{
"TRN-API-KEY":key
},
method:"get"
};
var res = UrlFetchApp.fetch(trackUrl,params);
//Logger.log(res);
return JSON.parse(res);
}
後述しますが、引数のmemberオブジェクトにはプレイヤーのtrackURLが含まれていて、curlを叩く先のURLとなっています。
Discordまわり
Incoming Webhooksの作成 ※要管理者権限
チャンネルの設定画面の下段に「Incoming Webhooks」という項目があり、そこからwebhookを作成します。
チャンネルの横の設定をクリックし、
Webhooks項目の「Webhookを作成」ボタンをクリック
Webhookの設定画面で、
・Bot名
・投稿するチャンネル名
・アイコン画像
を設定します。
下段のWebhookURLがGASで使用するURLになります。
通常のテキストによる投稿
postDiscord.gs
function testPost() {
var text = "text";
postDiscord(text);
}
function postDiscord(text,url) {
//DiscordのIncoming Webhookで取得したURL
var url="https://discordapp.com/api/webhooks/9999999999999999/XXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
//URLの一番右の文字列
var token="XXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
var channel="#general";
var username="ApexTrackerBOT";
var parse = "full";
var method= "post";
var jsonData={
"token":token,
"channel":channel,
"username":username,
"content":text,
"parse":parse,
}
var options={
"method":method,
"headers":{"Content-type":"application/json"},
"payload":JSON.stringify(jsonData),
"muteHttpExceptions":true
};
UrlFetchApp.fetch(url,options);
}
testPost()を実行すると、チャンネルにテスト投稿されます。
Embedを利用した投稿
Embedとは、名前と実際の値というペアを良い感じに出してくれる機能です。
Discordだけでなく、Slackにも同じ機能があります。
postDiscordEmbed.gs
function testPostEmbed() {
var embed = {};
embed.fields = [];
embed.fields.push({
name: 'Test',
value: '-------------------'
});
postDiscordEmbed("",embed);
}
function postDiscordEmbed(msg,embed) {
//DiscordのIncoming Webhookで取得したURL
var url="https://discordapp.com/api/webhooks/9999999999999999/XXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
//URLの一番右の文字列
var token="XXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
var channel="#bot";
var username="ApexTrackerBOT";
var parse = "full";
var method= "post";
var jsonData={
"token":token,
"channel":channel,
"username":username,
"content":msg,
"embeds":,
"parse":parse,
}
var options={
"method":method,
"headers":{
"Content-type":"application/x-www-form-urlencoded",
"User-Agent":"DiscordBot"
},
"payload":JSON.stringify(jsonData),
"muteHttpExceptions":true
};
UrlFetchApp.fetch(url,options);
}
testPostEmbed()を実行すると、チャンネルにテスト投稿されます。
一つのAppとしてまとめる
テキスト形式で投稿する(非Embed)
main.gs
var members = {
player1: {
name : 'player1',
imgUrl : '[メンバーのアイコンとして使いたい画像URL]',
trackUrl : " https://public-api.tracker.gg/v2/apex/standard/profile/origin/[プレイヤー名]"
},
player2: {
name : 'player2',
imgUrl : '[メンバーのアイコンとして使いたい画像URL]',
trackUrl : " https://public-api.tracker.gg/v2/apex/standard/profile/origin/[プレイヤー名]"
}
};
function memberData_text() {
for(var key in members) {
var legends = getCharactorsData(getApexTrack(members[key]));
for (var i=0; i<legends.length; i++) {
var text = makeText(members[key],legends[i]);
postDiscord(text);
//キャラ分連続投稿するため、0.5秒遅延させて投稿が反映されるようにしている
Utilities.sleep(500);
}
}
}
function makeText(member,legend) {
var text = []
text.push("**【Apex Legends DATA】" + member.name + "**");
text.push("**Legend Name:" + legend['legendName'] + "**");
delete legend['legendName'];
text.push(legend['bgimage']);
delete legend['bgimage'];
text.push("==========================================");
for(var key in legend) {
text.push(key + " : " + legend[key]);
}
text.push("==========================================");
return text.join("\n");
}
function getCharactorsData(jsonData) {
var charactors = [];
for each(var charactor in jsonData['data']['children']) {
//初期化とともにレジェンド名を設定
var legend = {legendName: charactor['metadata']['legend_name']};
//アイコンを設定
legend['bgimage'] = charactor['metadata']['bgimage'].toString();
//ゲーム上のバナーで設定している項目を設定
for(var i=0; i<charactor['stats'].length; i++) {
legend[charactor['stats'][i]['metadata']['key'].toString()] = charactor['stats'][i]['value'].toString();
}
charactors.push(legend);
}
//Logger.log(charactors);
return charactors;
}
流れを説明します。
- トリガーからメインの関数が実行される(memberData_text())
- membersに格納されたプレイヤー分のキャラクターデータリストを取得する。
(getCharactorsData(jsonData)) - 取得できたキャラクターデータ分、投稿内容を組み立ててDiscordに投稿する。(makeText(member,legend))
Embed形式で投稿する
var members = {
player1: {
name : 'player1',
imgUrl : '[メンバーのアイコンとして使いたい画像URL]',
trackUrl : " https://public-api.tracker.gg/v2/apex/standard/profile/origin/[プレイヤー名]"
},
player2: {
name : 'player2',
imgUrl : '[メンバーのアイコンとして使いたい画像URL]',
trackUrl : " https://public-api.tracker.gg/v2/apex/standard/profile/origin/[プレイヤー名]"
}
};
function memberData_embed() {
for(var key in members) {
var legends = getCharactorsData(getApexTrack(members[key]));
var embed = makeEmbed(members[key], legends);
postDiscordEmbed("",embed);
}
}
function makeEmbed(member, legend) {
var embed = {};
embed.title = "Apex TRN";
embed.description = "Apex Legends Tracker";
embed.url = "https://thetrackernetwork.com/";
embed.color = 3329330;
embed.author = {name: member.name, icon_url: member.imgUrl};
embed.fields = [];
for(var i=0; i<legend.length; i++) {
embed.fields.push({
name: "__" + legend[i]['legendName'] + "__",
value: "==============================="
});
delete legend[i]['legendName'];
delete legend[i]['bgimage'];
for(var key in legend[i]) {
embed.fields.push({
name: key,
value: legend[i][key],
inline: true
});
}
}
return embed;
}
function getCharactorsData(jsonData) {
var charactors = [];
for each(var charactor in jsonData['data']['children']) {
//初期化とともにレジェンド名を設定
var legend = {legendName: charactor['metadata']['legend_name']};
//アイコンを設定
legend['bgimage'] = charactor['metadata']['bgimage'].toString();
//ゲーム上のバナーで設定している項目を設定
for(var i=0; i<charactor['stats'].length; i++) {
legend[charactor['stats'][i]['metadata']['key'].toString()] = charactor['stats'][i]['value'].toString();
}
charactors.push(legend);
}
//Logger.log(charactors);
return charactors;
}
流れはテキスト形式の時と同じ流れですが、Embed形式の場合はキャラごとに投稿する必要はなく、まとめてEmbed用の配列に格納すればOKです。
ちなみに、画像URLも格納できますがイメージはDiscordに表示されません。
テストしていて気付いたのですが、画像URLを投稿した時の動作がSlackとDiscordで違っていて、
・Slackの場合はURLのすぐ下に画像が差し込まれて表示される
・Discordの場合は投稿文の下にまとめて画像が表示される
でした。
トリガー
毎日Botがチャンネルに投稿するようにしました。