ボトムズ日記

プログラミングのことをつぶやく日記です。

Twitterのメンションに反応するRubyスクリプトを書いた

この記事は下記の記事の続きです。

leokun0210.hatenablog.com

Twitter botを作成していましたが、メンションに反応するために必要なUser Streams APIが2018年に終わっていました。したがってTwitter APIで実現させなければなりません。そこで今回は自前でメンションに反応するスクリプトを作成しました。このスクリプトは、cronで1分ごとに実行しています。前回に引き続きtwitter gemを使用します。

Twitterの“User Streams API”が完全終了 ~それでもリアルタイム更新を楽しむ方法 - やじうまの杜 - 窓の杜

require "twitter"
require "redis"

class Card
#省略
end

def get_image(client)
#省略
end

client = Twitter::REST::Client.new do |config|
  config.consumer_key = ""
  config.consumer_secret = ""
  config.access_token = ""
  config.access_token_secret = ""
end

redis = Redis.new

client.mentions_timeline.each do |tweet|
  tweet_id = tweet.id
  unless redis.get(tweet_id)
    pos = tweet.text =~ /ドロー|draw|Draw/
    if pos
      retry_count = 0
      card = nil

      while true
        card = get_image(client)
        if card || retry_count > 5
          break
        end
        retry_count += 1
      end

      if card
        client.update_with_media("@#{tweet.user.screen_name} あなたが引いたカードは『#{card.name}", card.img_uri, in_reply_to_status: tweet)
      end
    end
  end
  redis.set(tweet_id, tweet.user.screen_name)
end

メンションされたツイートのタイムラインを取得します

Twitter::REST::Client#mentions_timeline を呼び出して、メンションされたツイートのタイムラインを取得します。optionで取得件数を制限できるようですが、今回はしませんでした。

client.mentions_timeline.each do |tweet|

Redisで過去に返したメンションを記録します

下記の部分はRedisを用いて、過去にメンションされて返信済みのツイートか判定しています。DBを構築するほどではなかったので、Redisで手軽にできないかどうか模索してい見ました。unless redis.get(tweet_id)で、過去に返信したツイートを取得できなかった場合は、返信を行った後にredis.set(tweet_id, tweet.user.screen_name)でRedisのキーにツイートIDを記録します。Valueはなんでもよいので適当にしています。

redis = Redis.new
# 省略
  unless redis.get(tweet_id)
# 省略
  redis.set(tweet_id, tweet.user.screen_name)

正規表現で返信するワードを制限します

Twitter::Tweet#textでツイートの内容を取得できます。すべてのメンションされたツイートに反応するのではなく、特定のワードのみに反応したいので、正規表現を利用しています。ここでは「ドロー」「draw」「Draw」の3つの単語に反応するようにします。

    pos = tweet.text =~ /ドロー|draw|Draw/
    if pos
#省略
    end

メンション元のユーザIDを取得します

tweet.user.screen_nameは、メンション元のユーザIDです。したがって、このユーザIDにメンションします。

        client.update_with_media("@#{tweet.user.screen_name} あなたが引いたカードは『#{card.name}", card.img_uri, in_reply_to_status: tweet)

これぐらいの規模であればRDBではなく、Redis(KVS)で十分だと思いましたが、予想通りでした。特にスクリプトを実行するうえで不便はしてません。またこれぐらいの軽い処理を行うときはKVSを用いるかもしれません。