Ruby × RMagick でTwitterフォロワーアイコンを並べたビンゴ風画像を作る


この手順でできること

フォロワーさんのアイコンを5x5-1(真ん中を除くため-1)に並べたビンゴ画像を自動生成できる。

・実行ごとに並ぶ人は変わる(完全ランダム。何のデータも考慮しない)
・中心には常に自分の画像が表示される

「絡みのきっかけ作り」にどうぞ。
名前は並記しないので、まずは「アイコンと名前を一致させるところから」としてもいいが、それはちょっと厳しい人用に、名前のリストをテキストで出力するようにもしている。

概要図

対象読者

環境構築がある程度わかる人向け(各種インストール・登録手順省略のため)
※個別での問い合わせ対応は可能

必要なもの

・Twitterアカウント
・開発用パソコン
 (Windowsは、RMmagickでつまづくらしいので、MacかLinuxがオススメ)
・お好みのテキストエディタor統合開発環境
・英文の読み書きに耐えられるメンタル(Twitter Developer登録がまだの場合)

0.環境構築

以下をインストールする。手順は割愛。基本はaptとかbrewとかyum、gemでいけるはず。Ruby は、この先も使うなら、rbenvとかrvmで入れた方がよいかも。

・Ruby
・Twitter Gem
・RMagick

※[参考]筆者環境(MacOS X 10.10.5 / Ruby 2.4.1 / Twitter Gem 6.2.0 / RMagick 2.16.0)

・SSL証明書を作成orインストールする
自身の証明書を作る必要があるが、ちょっと試したいだけなら、ひとまずCA certificates extracted from Mozillaの cacert.pem を保存して使うのもあり。

1.Twitter Developer登録

TwitterAPIを使うために、Developer登録が必要になる。

未登録の人はTwitter Developer Platformから登録を。
Twitterアカウントでログインして、右上の「Apply」へ。

お金はかからないし、個人情報も書かないので、気軽に登録して良いと思う。
英語でどんなことをしたいのかの説明を求められるので、Google翻訳を使って頑張ろう。
または、私の適当英語をそのままどうぞ。

I want to makes a follower's bingo image from Twitter APIs. It is used to increase communication opportunities between us and followers by reply, like and retweet.Since followers are chosen randomly, we will have opportunities to communicate with various followers.

訳: ぼくはTwitter APIからフォロワーさんのビンゴ画像を生成したいクポ。これはリプやいいね、リツイートによって、我々とフォロワーさんの交流機会を増やすために使われるクポよ。フォロワーさんはランダムで選ばれるから、様々なフォロワーさんとの交流機会が増えるクポね。

2.Twitterアプリケーションの作成

「Twitter Developer登録」が済んだら、

ユーザー名横の矢印から「Apps」を選び、「Create an App」から新規アプリケーションを作成する。

作成が終わったら、アプリケーションのDetailの画面で「Keys and tokens」タブを選び、そこに記載されている「Consumer API keys」を2種類どこかにメモしておく。

プログラムからAPIを利用する場合には、Access token が必要なので「Access token & access token secret」の「Create」ボタンを押す。

すると、tokenとsecretが表示されるので、こちらも「Consumer API keys」と同様にどこかにメモしておく。

3.プログラムの作成

以下のコードを作成する。twitterID、各種token, token secret は自分用に変えること。

make_follower_bingo.rb
require "twitter"
require 'rmagick'

### 設定ここから ###
# SSL証明書へのパス
ENV["SSL_CERT_FILE"] = "SSL証明書へのパスを記載"

# 自身のTwitterID
MY_TWITTER_ID = "Twitter IDを記載"

# 各種Token/Secret
CONSUMER_KEY         = "メモしたCONSUMER_KEYを記載" 
CONSUMER_SECRET      = "メモしたCONSUMER_SECRETを記載"
ACCESS_TOKEN        = "メモしたACCESS_TOKENを記載" 
ACCESS_TOKEN_SECRET = "メモしたACCESS_TOKEN_SECRETを記載"

### 設定ここまで ###

class TwitterClient
  NUMBER_OF_COL = 5 
  NUMBER_OF_ROW = 5 
  DEFAULT_FILE_NAME = "bingo.jpg"

  def initialize(consumer_key, consumer_secret, access_token, access_token_secret, my_twitter_id)
    @client = Twitter::REST::Client.new do |config|
      config.consumer_key        = consumer_key
      config.consumer_secret     = consumer_secret
      config.access_token        = access_token
      config.access_token_secret = access_token_secret
    end
    @my_twitter_id = my_twitter_id
    @number_of_followers = @client.user(@my_twitter_id).followers_count
  end

  def choice_followers(count)
    puts "Error: Number of follower is less than #{count}." if @number_of_followers < count 
    @chosen_followers_indexes = []
    index = -1
    count.times do
      loop do
        index = rand(@number_of_followers)
        break if !@chosen_followers_indexes.include?(index)
      end
      @chosen_followers_indexes << index
    end
    @chosen_followers_indexes
  end

  def get_followers
    is_success = false
    @chosen_follower_ids = []
    @client.follower_ids(@my_twitter_id).each_with_index do |follower, index|
      @chosen_follower_ids << follower if @chosen_followers_indexes.include?(index)

      # 全員見つかった 
      if @chosen_follower_ids.size >= @chosen_followers_indexes.size
        is_success = true
        break
      end
    end
    is_success
  end

  def generate_image(output_name = DEFAULT_FILE_NAME)
    image_urls = []
    names = []
    @chosen_follower_ids.each_with_index do |follower_id, index|
      user = @client.user(follower_id)
      puts user.name
      puts user.profile_image_uri

      image_urls << user.profile_image_uri
      names << user.name
    end

    # 真ん中に自分の画像を差し込む
    image_urls.insert((NUMBER_OF_COL * NUMBER_OF_ROW) / 2, @client.user(@my_twitter_id).profile_image_url)
    names.insert((NUMBER_OF_COL * NUMBER_OF_ROW) / 2, "★")

    # 対象者名をテキストに出力
    File.open(output_name + "_names.txt", "w") do |text|
      names.each_with_index do |name, index| 
        text.write(name)
        if (index + 1)  % NUMBER_OF_COL == 0
          text.write("\n") # 改行
        else
          text.write(" | ")
        end
      end
    end

    # 1行分の画像を行の数だけ生成
    images = []
    NUMBER_OF_ROW.times do |row_index|
      image = Magick::ImageList.new
      NUMBER_OF_COL.times do |col_index|
        image.read(image_urls[row_index * NUMBER_OF_COL + col_index])
      end
      image = image.append(false)
      images << image
    end

    # 行毎の画像を結合
    joined_image = Magick::ImageList.new
    images.each_with_index do |image, index|
      joined_image.from_blob(image.to_blob)
    end
    joined_image = joined_image.append(true) 
    joined_image.write(output_name) 
  end
end

client = TwitterClient.new(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET, MY_TWITTER_ID)

3.times do
  client.choice_followers(TwitterClient::NUMBER_OF_COL * TwitterClient::NUMBER_OF_ROW - 1)
  break if client.get_followers

  # フォロワー数の減少により、chosen_indexesの値がindexを超えてしまったら、再抽選
  puts "retrying..."
end
client.generate_image

[参考]
The Twitter Ruby Gem
RMagick 2.12.0 User's Guide and Reference#ImageList

4.実行

Mac, Linuxならソースコードに実行権限を付けて実行する。

$ chmod +x make_follower_bingo.rb 

上記は初回のみでOK.

$ ruby make_follower_bingo.rb

実行ディレクトリに「bingo.jpg」「bingo_names.txt」というファイルができれば成功!