Qiitaのトレンドに載ったらうれしいですよね。
今回は、Qiitaが提供しているRSSを使って自身の記事がトレンド入りしたらSlackで教えてくれる機能を実装してみました。
はじめに (すみません、実はシリーズです。)
以前、QiitaのRSSをDrupalでAPI化する実装をしてみました。
せっかく実装したAPIですので、今回さらに活躍させてみようと思います。
※ 「せっかく公式がRSSを提供しているのに、なんでAPI化するの?」っていう疑問あると思います。どれかの記事で触れてるので文句・不満がある人は読んでください。
トレンド / Feed (Qiita公式)
どうやら、個人記事RSS/トレンド記事RSS どちらもXMLの構造に大きなフォーマットの違いがないようです。(APIをそのまま使えるからありがたい 🤲)
以下のURLが提供しているFeedです。(リーダー登録してもいいかもですね。)
https://qiita.com/popular-items/feed
実装しましょ
手順はこちらです。
- API実装
- Slack通知関数の実装
- Cron の設定
そんな難しくないです。1つずつやっていきましょ。
今回はDrupalで実装しましたが、どの言語/どのフレームワークでも、ある程度は対応できる仕様だと思います。
ご自身のお得意なものを使ってください。
001. API実装
API実装(XMLパース)については、過去記事で紹介しています。
ほぼ変更ありませんので細かいところはそちらを参照ください。
ただ、1点だけ過去記事と違う所 があります。
個人記事 / RSSにはなかった Author を今回使用します。
記事の投稿者が誰かわからないAPIは嫌ですよね。
/**
* Parses XML data and generates list item markup for each feed item.
*
* @param \SimpleXMLElement $xml
* The XML data.
* @param string $url
* Rss url.
*
* @return array
* The array for the list items.
*/
private function parseXml(\SimpleXMLElement $xml, string $url): array {
$articles = [];
foreach ($xml->entry as $o) {
// Get feed item.
$title = (string) $o->title;
$link = (string) $o->url;
$author = (string) $o->author->name;
$published = (string) $o->published;
if (!isset($title) || !isset($link) || !isset($published)) {
continue;
}
$published = new \Datetime($published);
if (!$author) {
// 個人RSSの場合.
$articles[] = [
'title' => $title,
'link' => $link,
'published' => $published->format('c'),
];
}
else {
// トレンドRSSの場合Authorを考慮する.
$articles[] = [
'author' => $author,
'link' => $link,
'published' => $published->format('c'),
'title' => $title,
];
}
}
return [
'title' => (string) $xml->title,
'link' => $url,
'data' => $articles,
];
}
以前の実装したメソッドをゴリ押しで対応させました。(雑だけど許して)
API化についてはこちらの記事で紹介しています。
APIにアクセスして、JSONデータが返ってくれば👌です。
これでAPIの実装は完了です。
/api/qiita/{id}
の{id}
にユーザー名をセットする想定です。
例えば、/api/qiita/umekikazuya
にアクセスする感じ。
今回のFeedのURLはhttps://qiita.com/popular-items/feed
です。
{ホスト名}/api/qiita/popular-items
でアクセスする感じですね。
※ 以前の記事では、アカウント単位で 8時間 キャッシュさせる機構についても紹介しています。そちらもぜひ。
002. Slack通知関数の実装
次は、Slack通知関数の実装を行います。
イメージはこんな感じ。
- APIからJSONデータを取得する
- JSONデータに自身のアカウントが存在するかチェック
- Slackのフォーマットに変換
$client = new Client();
try {
$url = '{$ホスト名}';
$endpoint = '/api/qiita/feed/popular-items';
$http_request = $client->get($url . $endpoint);
$raw_data = $http_request->getBody()->getContents();
if (!$raw_data) {
throw new \Exception();
}
}
catch (\Exception $e) {
echo 'APIの取得に失敗.';
return;
}
// 取得JSONデータを配列に変換.
$data = json_decode($raw_data, TRUE);
// 自分のアカウントでデータを絞り込み.
$filtered_data = array_filter($data['data'], function ($item) {
// 自身のアカウント名.
return $item['author'] === 'umekikazuya';
});
// Slackに送信するメッセージの構築.
$blocks = [];
foreach ($filtered_data as $item) {
$blocks[] = [
"type" => "section",
"text" => [
"type" => "mrkdwn",
"text" => "<{$item['link']}|{$item['title']}> - {$item['published']}",
],
];
}
$slack_message = [
"blocks" => $blocks,
];
// 環境変数.
$token = getenv('slack_token');
$channel_id = getenv('slack_channel_id');
// Slackに送信.
$client = new Client();
$client->post('https://slack.com/api/chat.postMessage', [
'headers' => [
'Authorization' => "Bearer {$token}",
'Content-Type' => 'application/json',
],
'json' => [
'channel' => $channel_id,
'blocks' => $slack_message['blocks'],
],
]);
echo "Slackに送信しました。";
// ※ 記事内では細かい例外処理は省略しています。.
003. Cron の設定
その前に...。
先程のPHP関数を実行するBashを実装しました。
$DRUSH_PATH php:script $PATH/script/batch/trend-notice-slack.php
※ Drushは、Drupalと親和性の高いCLIツールです。
では ShellをCronで実行しましょう。
1. Crontab を開く
crontab -e
2. Cron の設定
最近人気の記事を毎日5時/17時に更新
とありますが、ちょっと時間のズレがある気かもしれないので 更新の1時間後に Cron を設定しましょう。
0 6,18 * * * bash {PATH}/script/batch/trend-notice-slack.bash
Cron設定は以上です。
執筆
記事を書きましょう。
待機
トレンド入りするかどうかは保証できません。
まとめ
それぞれの機能の単体テストはしましたので動作は問題ないかと。
ただ、トレンド入りしてないので通しで動くかはわかりません。現在待機中です。(記事の質悪いのかな 😥)