【Ruby】ツイートをニコニコ動画のコメント風に流す

ツイートを検索して、その結果をニコニコ動画のコメント風に端末に流すスクリプトを書きました。

以下は「#桐間紗路生誕祭2016」を検索した際の動画です。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="und" dir="ltr"><a href="https://twitter.com/hashtag/%E6%A1%90%E9%96%93%E7%B4%97%E8%B7%AF%E7%94%9F%E8%AA%95%E7%A5%AD2016?src=hash">#桐間紗路生誕祭2016</a> <a href="https://t.co/4H3QF4RZBP">pic.twitter.com/4H3QF4RZBP</a></p>&mdash; せーのすけ (@seinosuke_i) <a href="https://twitter.com/seinosuke_i/status/753877210939875328">2016年7月15日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

## 動作環境

* Ubuntu 14.04
* Ruby 2.2.0
* ncursesw (gem) 1.4.9
* twitter (gem) 5.16.0

必要なもののインストールは以下のコマンドで

```
$ sudo apt-get install libncursesw5-dev
$ gem install ncursesw
$ gem install twitter
```

## ソースコード

ncurses周りについては以前投稿した[【Ruby】 ncurseswでゲームをつくる](http://qiita.com/seinosuke/items/dc66f1d1a9b58563fb30) のコードをわりとそのまま使っているので、もしよろしければそちらを参照してください。

twitterのアクセストークンなどはご自分のもので置き換えてください。

```ruby:main.rb
require 'thread'
require 'nkf'
require 'twitter'
require 'ncursesw'

class RTStream
  BLANK = "  "

  def initialize
    Ncurses.initscr
    Ncurses.curs_set(0)
    Ncurses.cbreak
    Ncurses.noecho
    Ncurses.use_default_colors

    @client = Twitter::Streaming::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

    @height = Ncurses.LINES
    @width = Ncurses.COLS
    @width -= 1 if @width.odd?
    @rows = Array.new(@height) { Array.new(@width/2) { BLANK } }
    @row_queues = Array.new(@height) { Queue.new }
    @tweet_queue = Queue.new
  end

  def run(track_word = nil)
    @threads = []
    @threads << drawing_thread
    @threads << stream_thread(track_word)
    @threads << enqueue_thread
    @threads.each(&:join)
    close_scr
  rescue Interrupt
    @threads.each(&:kill)
    close_scr
  end

  private

  # 描画するスレッド
  def drawing_thread
    Thread.new do
      loop do
        @row_queues.each_with_index do |queue, i|
          @rows[i].shift
          @rows[i].push( queue.empty? ? BLANK : queue.deq )
          Ncurses.mvaddstr(i, 0, @rows[i].join)
        end
        sleep 0.1
        Ncurses.refresh
      end
    end
  end

  # ツイートを取得し enqueue 待ちツイートを enqueue していくスレッド
  def stream_thread(track_word)
    Thread.new do
      if track_word
        @client.filter(track: track_word) do |object|
          if object.is_a? Twitter::Tweet
            @tweet_queue.enq filter(object.text)
          end
        end
      else
        @client.user do |object|
        # @client.sample do |object|
          if object.is_a? Twitter::Tweet
            @tweet_queue.enq filter(object.text)
          end
        end
      end
    end
  end

  # 表示待ちツイートを enqueue していくスレッド
  def enqueue_thread
    Thread.new do
      loop do
        i = @row_queues.find_index { |queue| queue.empty? }
        sleep 0.1
        redo unless i
        tweet = @tweet_queue.deq
        tweet.each_char { |ch| @row_queues[i].enq ch }
      end
    end
  end

  # 半角を全角にするフィルター（適当）
  def filter(text)
    NKF.nkf('-w -X', text) # 半角カタカナを全角に
      .gsub(URI.regexp(["http", "https"]), "") # URLは削除
      .tr('0-9a-zA-Z', '０-９ａ-ｚＡ-Ｚ') # 半角英数字を全角に
      .gsub(/[\R\s]/, "　") # 改行とかスペースは全角スペースに
      .gsub(/[!-~]/, "") # 他の半角記号とかは削除
  end

  # ncursesの後処理
  def close_scr
    Ncurses::curs_set(1)
    Ncurses.nocbreak
    Ncurses.echo
    Ncurses.endwin
  end
end

rtstream = RTStream.new
track_word = "#桐間紗路生誕祭2016"
rtstream.run(track_word)
```

`track_word` で検索したい文字列を与えます。
`track_word` を与えない場合は自分のタイムラインが流れてきます。

## おわりに

今回は日本語のツイートを想定していたので、処理の都合上ツイートを全て全角に揃える必要がありました。そのためフィルタをいろいろ頑張ってみたのですが、文字力、正規表現力が足りず結局なんだかよくわからん感じになりました（特殊文字とかのことは何も考えてない）。まあとりあえず動作したのでよかったということに。

これで端末上でいい感じにタイムラインを眺めることができます。

参考サイト
[http://easyramble.com/convert-half-full-width-with-ruby.html](http://easyramble.com/convert-half-full-width-with-ruby.html)
[http://docs.ruby-lang.org/ja/2.2.0/class/URI.html#S_REGEXP](http://docs.ruby-lang.org/ja/2.2.0/class/URI.html#S_REGEXP)