(修正) Sinatra で Google Reader の共有アイテムをつぶやくアプリを作ってみた

前回の記事 の続きです

アプリを使っていて時々、
"共有アイテムを追加したタイミングで、過去に追加したものがつぶやかれてしまう"
という事が起きていました。

しばらくの間、publish されてくる xml をファイルにはきだし様子を見てみたところ、以下のような事がわかりました。

  • 追加したアイテムに加え、過去に追加したアイテムも含んだ xml が publish される。
  • アイテムの順番は、追加した時刻でソートされておらず、バラバラに並んでいる。

こんなイメージです。

<?xml version="1.0" encoding="utf8"?>
<feed>
  <entry gr:crawl-timestamp-msec="1316865492109">
    ...
  </entry>
  <entry gr:crawl-timestamp-msec="1316943113824">
    ...
  </entry>
  <entry gr:crawl-timestamp-msec="1316826628148">
    ...
  </entry>
</feed>

entry タグの gr:crawl-timestamp-msec という属性値には、"共有アイテムに追加した時刻" が記録されています。

というわけで、publish された時刻とこの属性値の時刻を比較し、最近追加されたものだけをつぶやくように修正します。

しゅうせい!

※ 前回の "4. 新着フィードの受信" の部分の修正です。

[code lang="ruby" highlight="14,15,27,28,30,31"]
# 購読要求時の入力情報
secret = 'foofoo'

post '/sub.rb' do
  # リクエストボディの取得
  payload = request.body.read

  # X_Hub_Signature ヘッダの値を取得
  hub_sig = request.env['HTTP_X_HUB_SIGNATURE']
  # HMAC-SHA1 の計算
  my_sig = OpenSSL::HMAC::hexdigest(OpenSSL::Digest::SHA1.new, secret, payload)

  if hub_sig.include?(my_sig) then
    # 現在時刻の取得
    timenow = Time.now.to_i        # (*1)
    # xml の解析
    doc = REXML::Document.new(payload.gsub('<br>', '<br />'))

    # entry 毎に処理
    doc.elements.each('/feed/entry') do |ele|
      title = ele.elements['title'].text
      link = ele.elements['link[@rel="alternate"]'].attributes['href']
      # コメントはない場合もあるので分けて処理
      comment_ele = ele.elements['gr:annotation/content']
      comment = comment_ele ? comment_ele.text : ''

      # 追加された時刻の取得
      timepub = ele.attributes['gr:crawl-timestamp-msec'].to_i / 1000   # (*2)

      # 300sec 以内に追加されたものだけつぶやく
      if timenow - timepub < 300 then            # (*3)
        t = Tweet.new
        begin
          t.tweet(title, link, comment)
        rescue
          true
        end
      end
    end
  end

  # 成功を返す
  status 200
end

つぶやき済みのアイテムの gr:crawl-timestamp-msec をどこかに保持する、という方法でも良かったのですが、面倒だったので 300 秒以内ということで妥協しました。

さいごに

この修正後は過去のものがつぶやかれることはなく、快適に使えています。