Slackでアニメ放送時間の通知Botを作ってみた
最近、Slackを使ったアプリネタを見る機会が増えてきた気がします。
なので、自分でもやってみようと思いました。
今回は、アニメ放送時間の一時間前になったら、定期通知するBotを作ってみます。
具体的には、
- Web UIにアニメの放送時間を登録
- Cronファイルを更新
- 放送時間の一時間前になったら、Slack APIを叩いてPost
という仕組みのものを作ります。
手順
Web UIはRailsで簡単なものを用意します。
必要なモジュールの準備、Scaffold作成
$ rails new animelovers --skip-bundle $ cd animelovers
Gemfileには、以下を追記します。
slack-apiは、文字通りSlackの操作に使い、wheneverは、crontabの設定内容を管理するモジュールです。
# for slack gem 'slack-api' # for crontab gem 'whenever', require: false
bundle installします。
bundle install --path vendor/bundle
次に、scaffoldでひな形を作ります。
$ bundle exec rails g scaffold Anime title:string days_of_the_week:string start_time:time $ bundle exec rake db:migrate
Slackの設定
SlackのAPIトークンを、config/initializers/slack.rb に下記のように書きます。
APIは、Slack Web API | Slack から発行します。
#config/initializers/slack.rb require 'slack' Slack.configure do |config| config.token = 'xoxp-9469336594-9469676821-9469781495-******' end
これで、Rails内の各所から、Slackにポストできます。
Postは、次の一行で行うことができます。text, username, channelは、適宜変更します。
Slack.chat_postMessage(text: 'テスト', username: 'kenta', channel: '#random')
Wheneverの設定
UIから、新規登録、更新、削除が行われたときに、config/schedule.rbが更新され、crontabファイルも更新されるようにします。
下記のような、ヘルパーを書きます。
何点か補足しておくと、crontabに書く、* * * * * のような、実行時間はcrontimeで、適当に整形しています。
Slackのusernameや、channelは適宜変更します。
config/schedule.rbを書き換えた後は、whenever --update-crontabを実行しています。
# app/helpers/whenever_helper.rb module WheneverHelper def update_schedule schedule_path = File.join(Rails.root, 'config/schedule.rb') File.open(schedule_path, 'w') do |f| f.flock File::LOCK_EX header = "set :output, 'log/output.log'\n" header << "set :environment, :development\n" f.write(header) end animes = Anime.all animes.each do |anime| content = <<-FILE # minute, hour, day_of_month, month, day_of_week every '#{crontime(anime)}' do runner "Slack.chat_postMessage(text: '#{anime.title} が あと一時間で始まるよ!!', username: 'kenta', channel: '#random')" end FILE File.open(schedule_path, 'a') do |f| f.flock File::LOCK_EX f.write(content) end end system("bundle exec whenever --update-crontab") end private def crontime anime if anime.start_time.to_s.match(/\s(\d{2}):(\d{2}):/) hour = "%01d" % $1 hour = hour.to_i minute = "%01d" % $2 end wday = week_list[anime.days_of_the_week] if hour == 0 hour = 23 if wday == 0 wday = 6 else wday = wday - 1 end else hour = hour - 1 end "%s %s * * %s" % [minute, hour, wday] end def week_list {'Sun' => 0, 'Mon' => 1, 'Tue' => 2, 'Wen' => 3, 'Thr' => 4, 'Fri' => 5, 'Sat' => 6} end end
次に、コントローラーに、反映させます。
WheneverHelperはこのあたりに、
# app/controllers/animes_controller.rb class AnimesController < ApplicationController include WheneverHelper
update_scheduleはcreateと
# POST /animes # POST /animes.json def create @anime = Anime.new(anime_params) respond_to do |format| if @anime.save update_schedule
updateと
# PATCH/PUT /animes/1 # PATCH/PUT /animes/1.json def update respond_to do |format| if @anime.update(anime_params) update_schedule
destroyに
# DELETE /animes/1 # DELETE /animes/1.json def destroy @anime.destroy update_schedule
それぞれ、追記します。
実演
このように登録しておくと、
こうやって通知してくれます。
ちなみに、config/schedule.rbには、次の行が追記されます。
# minute, hour, day_of_month, month, day_of_week every '52 21 * * 0' do runner "Slack.chat_postMessage(text: 'テストアニメ が あと一時間で始まるよ!!', username: 'kenta', channel: '#random')" end
これで、アニメを見逃すことが無くなる、やったー\(^o^)/