GolangでHolodule Botを作った話
これは みす54th Advent Calendar 2021 の4日目の記事です. 54代プロ研のI.TKです.
ホロライブとGolangの話をします.
はじめに
最近6期生がデビューしてホロライブがアツいですね!
少し前までVはおろかYouTubeすら見ていなかった自分ですが,最近は暇さえあればYouTubeでVを見ており,YouTube Premiumも契約してしまいました...
そうなるとホロライブメンバーの配信スケジュールが知りたい!となるのですが,そんなときに便利な配信スケジュールを掲載しているWebサイトHolodule を運営様が作ってくれています.
しかし,突発的に生える配信もあるし,気づくと時間を過ぎているなんてことも多々有りました. そこで,これをスクレイピングして取ってきて通知をするDiscord Botがあれば最高じゃね?と思ったので作りました.
作ったもの
毎日0:30にその日の配信スケジュールを通知する"daily"と,配信の1〜2時間前に通知をする"coming-soon"の2つの通知機能を作りました. Discord鯖にはdailyとcoming-soon用の2つのチャンネルを作っておいて,そこに通知を投げます.
Daily
上の画像は一部で,この後にズラッとまだ並んでます.
Coming Soon
環境と使用ライブラリ
なぜGolang?
普段PythonとDjangoばかり使っている自分ですが,ずっとPythonばかり使っているのもアレだし,何より静的な型がほしい!と思うようになったので,気になっていたGolangを使うことにしました. 幸いなことにGoにはgoqueryというスクレイピング用ライブラリがあったので,そこには困りませんでした. (ちなみにPythonにもBeautiful Soupというよく知られたスクレイピング用ライブラリがあります.)
仕様
スクレイピング方法
配信のデータをhtmlから抜き取らなくてはいけないわけですが,特にその項目ごとにIDが振られてるようなことはなかったため,ダグ名とclass名で無理やり取得しました.
取得項目
- 配信者
- 配信者名
- 配信者アイコンURL
- 配信日時
- サムネイル画像URL
DB
DB設計は下図のような感じ.基本は上の取得項目を保存して,それに加えて"coming-soon"の通知をしたかどうかを判断するために notified_at フィールドを加えています.
通知の流れ
dailyについては簡単で,毎日0:30にholoduleからデータを取ってきて当日の分だけDiscord APIを叩いて通知を送るだけです.
coming-soonについては,通知をしたかどうかを判断するため,DBにデータを格納する必要がありました. まず,毎時30分にholoduleからデータを取ってきて,新規追加分と更新をDBに反映します. 次に,現在時刻が配信時刻の1〜2時間前であるもののうち,通知済みでない配信をDBから取得してDiscord APIを叩いて通知を送ります. それが成功したら,notified_atに現在時刻を挿入し,通知済みとします.
Discord API Embed(s)の落とし穴
※ EmbedというのはDiscordに文字・リンク・画像なんかをまとめてカードのように表現して送ることができるメッセージの形態です.リンクをチャット欄に貼ったときにも出てきますね.アレです.これを使っています.
Discord に通知を送るためにDiscord APIのEmbedを使ったのだが,2つの落とし穴がありました.
まず1つめは,dailyはその日のすべての配信を取得するため相当な数があり,Embedでひとつひとつ通知をすると「API叩きすぎだ.少し待て.」と怒られました.Hololiveって一日にこんなに配信してるんですね... すごい
2つめは,1つめの問題を解決するためにEmbedsというEmbedをまとめて送れるのもあり,これを使おうとしたのですが,1つあたり10個のEmbedしかまとめることが出来ないそうで,分けて送る必要がありました. さらに,Embedsを使っても「API叩きすぎだ.少し待て.」と怒られ,仕方なく最初のテキストのところはWebhookで送ることにして,やっとAPIの呼び出し制限を回避しました.
これでも怒られたらどうしようもなかったので本当に良かったです...
おわりに
Golangを使って思ったのは
型って素晴らしい!!!!!!!!!!!!!!!!
これに尽きます.Pythonでも型ヒントはあるんですがつけやがらねえ奴もいるし,そもそもライブラリに付いてなかったりもします. まあ,型がほしいなら別の言語使えってことですね.ハイ.
あと,今回ORMを使わずにSQLを直で書いて実行するようにしました. sqlxがうまい具合にstructにマッピングしてくれたので,そこまで大変ではなかったですが,まあ,ORMに頼らない分やることは増えましたね. 以前からそれぞれのORMの学習コストが高いのと,SELECTでJOINするときにそのORMに対応しているものをドキュメントから漁らなきゃいけなかったこともあって,もやもやしていたのでいい経験になったかと思います.プロジェクトでORMを使うかどうかは,どこまでカバーするかも含めて適材適所って感じですかね.
今回実装したコードはGithubに載せてあります. よかったら見てってネ.もしアドバイスなどあればDiscordでもSlackでもTwitterでも何でもいいのでくれたら泣いて喜びます.
最後に,これを作ったおかげて配信の見逃しが少なくなりました.ですが,ホロライブメンバー全員分の配信通知がDiscordに来るので,すごいことになっています.通知をする配信者を絞る機能を早急に作らなければいけないなと感じています.
Hololiveはいいぞ.