Help us understand the problem. What is going on with this article?

複数枚写真が添付されたツイートの写真URL等を取得するTwitter gemモンキーパッチ

More than 5 years have passed since last update.

Twitterで写真が4枚まで添付できるようになりました、アクセスできるAPIがなかなか公開されませんでした。
そして、ようやく(日本時間の)今日から使えるようになりました。
Twitter gemは優秀なのでそのままアクセスできますが、ツイート添付写真に関する情報を取得するTwitter::Entities#mediaメソッドは、当然ながら写真1枚の情報しか取得できません。
これを拡張するモンキーパッチを作成しましたので公開します。
おそらくTwitter gemも同様の実装で対応する(追記:v5.10.0 で対応済)でしょうが、それまでご利用ください。
あと、おそらく対応してくれないであろうTwitter gem バージョン4でも動くパッチも書くつもりです。

パッチ

とりあえずTwitter gem 5.9.0で動作確認しましたが、おそらくバージョン5全てで動作すると思います。

extended_entities_patch.rb
module Twitter
  module Entities
    # @return [Array<Twitter::Media>]
    def media
      extended_entities(MediaFactory, :media)
    end

    private

    # @param klass [Class]
    # @param key [Symbol]
    def extended_entities(klass, key)
      if @attrs[:extended_entities].nil?
        []
      else
        @attrs[:extended_entities].fetch(key.to_sym, []).collect do |entity|
          klass.new(entity)
        end
      end
    end
  end
end

動作確認

Twitter gemでattrsを確認

このツイートをAPIで取得します。写真は3枚添付されています。


Twitter gemでの取得結果はこうなります。

client.status(449746301857447936).attrs
=> {:created_at=>"Sat Mar 29 03:14:08 +0000 2014",
 :id=>449746301857447936,
 :id_str=>"449746301857447936",
 :text=>
  "タグ付けされた側は通知が来る。そしてタグ付けを含むツイートには(ツイートした垢が鍵付きじゃなければ、タグ付けに関係しない垢からも)タグ付けされた垢名を確認できる。\n新機能の写真タグ付けに加え、写真は1ツイート4枚まで追加可能になった。 http://t.co/Mljw3xOY3B",
 :source=>
  "<a href=\"http://twitter.com/download/iphone\" rel=\"nofollow\">Twitter for iPhone</a>",
 :truncated=>false,
 :in_reply_to_status_id=>nil,
 :in_reply_to_status_id_str=>nil,
 :in_reply_to_user_id=>nil,
 :in_reply_to_user_id_str=>nil,
 :in_reply_to_screen_name=>nil,
 :user=>
  {:id=>56997313,
   :id_str=>"56997313",
   :name=>"riocampos(りおかんぽす)",
   :screen_name=>"riocampos",
   :location=>"Osaka, Japan",
   :description=>
    "plz call me rio☆ favorite: cycle road race & figure skate, Mac!, iPhone!, Ruby, Fine-Art, Science, Black/Green Tea. | Gender:♂ (FB: http://t.co/71QgiSwca0 )",
   :url=>"http://t.co/cRXTvrEpoN",
   :entities=>
    {:url=>
      {:urls=>
        [{:url=>"http://t.co/cRXTvrEpoN",
          :expanded_url=>"http://about.me/riocampos",
          :display_url=>"about.me/riocampos",
          :indices=>[0, 22]}]},
     :description=>
      {:urls=>
        [{:url=>"http://t.co/71QgiSwca0",
          :expanded_url=>"http://on.fb.me/MvEV7P",
          :display_url=>"on.fb.me/MvEV7P",
          :indices=>[132, 154]}]}},
   :protected=>false,
   :followers_count=>2121,
   :friends_count=>2326,
   :listed_count=>191,
   :created_at=>"Wed Jul 15 12:02:35 +0000 2009",
   :favourites_count=>2947,
   :utc_offset=>32400,
   :time_zone=>"Osaka",
   :geo_enabled=>true,
   :verified=>false,
   :statuses_count=>182220,
   :lang=>"en",
   :contributors_enabled=>false,
   :is_translator=>false,
   :is_translation_enabled=>false,
   :profile_background_color=>"48E0B7",
   :profile_background_image_url=>
    "http://pbs.twimg.com/profile_background_images/378800000158576090/WjPzbAXY.jpeg",
   :profile_background_image_url_https=>
    "https://pbs.twimg.com/profile_background_images/378800000158576090/WjPzbAXY.jpeg",
   :profile_background_tile=>true,
   :profile_image_url=>
    "http://pbs.twimg.com/profile_images/3462273402/f331afb1b57c7d39688229e86de95881_normal.jpeg",
   :profile_image_url_https=>
    "https://pbs.twimg.com/profile_images/3462273402/f331afb1b57c7d39688229e86de95881_normal.jpeg",
   :profile_banner_url=>
    "https://pbs.twimg.com/profile_banners/56997313/1365179721",
   :profile_link_color=>"009999",
   :profile_sidebar_border_color=>"FFFFFF",
   :profile_sidebar_fill_color=>"EFEFEF",
   :profile_text_color=>"333333",
   :profile_use_background_image=>true,
   :default_profile=>false,
   :default_profile_image=>false,
   :following=>false,
   :follow_request_sent=>false,
   :notifications=>false},
 :geo=>nil,
 :coordinates=>nil,
 :place=>nil,
 :contributors=>nil,
 :retweet_count=>0,
 :favorite_count=>1,
 :entities=>
  {:hashtags=>[],
   :symbols=>[],
   :urls=>[],
   :user_mentions=>[],
   :media=>
    [{:id=>449746301068926976,
      :id_str=>"449746301068926976",
      :indices=>[118, 140],
      :media_url=>"http://pbs.twimg.com/media/Bj3R4MJCYAAqnMg.jpg",
      :media_url_https=>"https://pbs.twimg.com/media/Bj3R4MJCYAAqnMg.jpg",
      :url=>"http://t.co/Mljw3xOY3B",
      :display_url=>"pic.twitter.com/Mljw3xOY3B",
      :expanded_url=>
       "http://twitter.com/riocampos/status/449746301857447936/photo/1",
      :type=>"photo",
      :sizes=>
       {:medium=>{:w=>600, :h=>537, :resize=>"fit"},
        :small=>{:w=>340, :h=>304, :resize=>"fit"},
        :thumb=>{:w=>150, :h=>150, :resize=>"crop"},
        :large=>{:w=>640, :h=>573, :resize=>"fit"}}}]},
 :extended_entities=>
  {:media=>
    [{:id=>449746301068926976,
      :id_str=>"449746301068926976",
      :indices=>[118, 140],
      :media_url=>"http://pbs.twimg.com/media/Bj3R4MJCYAAqnMg.jpg",
      :media_url_https=>"https://pbs.twimg.com/media/Bj3R4MJCYAAqnMg.jpg",
      :url=>"http://t.co/Mljw3xOY3B",
      :display_url=>"pic.twitter.com/Mljw3xOY3B",
      :expanded_url=>
       "http://twitter.com/riocampos/status/449746301857447936/photo/1",
      :type=>"photo",
      :sizes=>
       {:medium=>{:w=>600, :h=>537, :resize=>"fit"},
        :small=>{:w=>340, :h=>304, :resize=>"fit"},
        :thumb=>{:w=>150, :h=>150, :resize=>"crop"},
        :large=>{:w=>640, :h=>573, :resize=>"fit"}}},
     {:id=>449746298007076864,
      :id_str=>"449746298007076864",
      :indices=>[118, 140],
      :media_url=>"http://pbs.twimg.com/media/Bj3R4AvCQAA9-Le.jpg",
      :media_url_https=>"https://pbs.twimg.com/media/Bj3R4AvCQAA9-Le.jpg",
      :url=>"http://t.co/Mljw3xOY3B",
      :display_url=>"pic.twitter.com/Mljw3xOY3B",
      :expanded_url=>
       "http://twitter.com/riocampos/status/449746301857447936/photo/1",
      :type=>"photo",
      :sizes=>
       {:medium=>{:w=>599, :h=>1024, :resize=>"fit"},
        :large=>{:w=>599, :h=>1024, :resize=>"fit"},
        :thumb=>{:w=>150, :h=>150, :resize=>"crop"},
        :small=>{:w=>340, :h=>581, :resize=>"fit"}}},
     {:id=>449746298887868416,
      :id_str=>"449746298887868416",
      :indices=>[118, 140],
      :media_url=>"http://pbs.twimg.com/media/Bj3R4EBCEAAUIgg.jpg",
      :media_url_https=>"https://pbs.twimg.com/media/Bj3R4EBCEAAUIgg.jpg",
      :url=>"http://t.co/Mljw3xOY3B",
      :display_url=>"pic.twitter.com/Mljw3xOY3B",
      :expanded_url=>
       "http://twitter.com/riocampos/status/449746301857447936/photo/1",
      :type=>"photo",
      :sizes=>
       {:small=>{:w=>340, :h=>604, :resize=>"fit"},
        :large=>{:w=>576, :h=>1024, :resize=>"fit"},
        :thumb=>{:w=>150, :h=>150, :resize=>"crop"},
        :medium=>{:w=>576, :h=>1024, :resize=>"fit"}}}]},
 :favorited=>false,
 :retweeted=>false,
 :possibly_sensitive=>false,
 :lang=>"ja"}

mediaメソッドの返値

パッチを当てる前の返値はTwitter::Media::Photoオブジェクト1要素の配列です。

tw = client.status(449746301857447936)
=> #<Twitter::Tweet id=449746301857447936>
m_ary = tw.media
=> [#<Twitter::Media::Photo id=449746301068926976>]

パッチを当てるとTwitter::Media::Photoオブジェクトの配列(1〜4要素)が返ります。

load 'extended_entities_patch.rb'
=> true
tw = client.status(449746301857447936)
=> #<Twitter::Tweet id=449746301857447936>
m_ary = tw.media
=> [#<Twitter::Media::Photo id=449746301068926976>,
 #<Twitter::Media::Photo id=449746298007076864>,
 #<Twitter::Media::Photo id=449746298887868416>]

Twitter::Media::Photoのメソッドはattrs, id, media_url, media_url_https, sizesなどがあります。
attrsTwitter::Media::Photoの中身を見れます。ハッシュとして扱えます。
その他のメソッドはそれぞれの情報を取得します。一番使うメソッドは、画像ファイルへのURLを取得出来るmedia_urlでしょう。ちなみにmedia_urlの返値であるAddressable::URIオブジェクトはURIオブジェクトみたいなものです。to_sでURL文字列になります。

m_ary.map{ |m| m.attrs }
=> [{:id=>449746301068926976,
  :id_str=>"449746301068926976",
  :indices=>[118, 140],
  :media_url=>"http://pbs.twimg.com/media/Bj3R4MJCYAAqnMg.jpg",
  :media_url_https=>"https://pbs.twimg.com/media/Bj3R4MJCYAAqnMg.jpg",
  :url=>"http://t.co/Mljw3xOY3B",
  :display_url=>"pic.twitter.com/Mljw3xOY3B",
  :expanded_url=>
   "http://twitter.com/riocampos/status/449746301857447936/photo/1",
  :type=>"photo",
  :sizes=>
   {:medium=>{:w=>600, :h=>537, :resize=>"fit"},
    :small=>{:w=>340, :h=>304, :resize=>"fit"},
    :thumb=>{:w=>150, :h=>150, :resize=>"crop"},
    :large=>{:w=>640, :h=>573, :resize=>"fit"}}},
 {:id=>449746298007076864,
  :id_str=>"449746298007076864",
  :indices=>[118, 140],
  :media_url=>"http://pbs.twimg.com/media/Bj3R4AvCQAA9-Le.jpg",
  :media_url_https=>"https://pbs.twimg.com/media/Bj3R4AvCQAA9-Le.jpg",
  :url=>"http://t.co/Mljw3xOY3B",
  :display_url=>"pic.twitter.com/Mljw3xOY3B",
  :expanded_url=>
   "http://twitter.com/riocampos/status/449746301857447936/photo/1",
  :type=>"photo",
  :sizes=>
   {:medium=>{:w=>599, :h=>1024, :resize=>"fit"},
    :large=>{:w=>599, :h=>1024, :resize=>"fit"},
    :thumb=>{:w=>150, :h=>150, :resize=>"crop"},
    :small=>{:w=>340, :h=>581, :resize=>"fit"}}},
 {:id=>449746298887868416,
  :id_str=>"449746298887868416",
  :indices=>[118, 140],
  :media_url=>"http://pbs.twimg.com/media/Bj3R4EBCEAAUIgg.jpg",
  :media_url_https=>"https://pbs.twimg.com/media/Bj3R4EBCEAAUIgg.jpg",
  :url=>"http://t.co/Mljw3xOY3B",
  :display_url=>"pic.twitter.com/Mljw3xOY3B",
  :expanded_url=>
   "http://twitter.com/riocampos/status/449746301857447936/photo/1",
  :type=>"photo",
  :sizes=>
   {:small=>{:w=>340, :h=>604, :resize=>"fit"},
    :large=>{:w=>576, :h=>1024, :resize=>"fit"},
    :thumb=>{:w=>150, :h=>150, :resize=>"crop"},
    :medium=>{:w=>576, :h=>1024, :resize=>"fit"}}}]

m_ary.map{ |m| m.id }
=> [449746301068926976, 449746298007076864, 449746298887868416]

m_ary.map{ |m| m.media_url }
=> [#<Addressable::URI:0x3fdd9a81c9ac URI:http://pbs.twimg.com/media/Bj3R4MJCYAAqnMg.jpg>,
 #<Addressable::URI:0x3fdd9a81e9c8 URI:http://pbs.twimg.com/media/Bj3R4AvCQAA9-Le.jpg>,
 #<Addressable::URI:0x3fdd9a820ad4 URI:http://pbs.twimg.com/media/Bj3R4EBCEAAUIgg.jpg>]

m_ary.map{ |m| m.media_url_https }
=> [#<Addressable::URI:0x3fdd9a82e008 URI:https://pbs.twimg.com/media/Bj3R4MJCYAAqnMg.jpg>,
 #<Addressable::URI:0x3fdd9a8caf70 URI:https://pbs.twimg.com/media/Bj3R4AvCQAA9-Le.jpg>,
 #<Addressable::URI:0x3fdd9a8ccfdc URI:https://pbs.twimg.com/media/Bj3R4EBCEAAUIgg.jpg>]

m_ary.map{ |m| m.sizes }
=> [{:medium=>#<Twitter::Size h=537 w=600>,
  :small=>#<Twitter::Size h=304 w=340>,
  :thumb=>#<Twitter::Size h=150 w=150>,
  :large=>#<Twitter::Size h=573 w=640>},
 {:medium=>#<Twitter::Size h=1024 w=599>,
  :large=>#<Twitter::Size h=1024 w=599>,
  :thumb=>#<Twitter::Size h=150 w=150>,
  :small=>#<Twitter::Size h=581 w=340>},
 {:small=>#<Twitter::Size h=604 w=340>,
  :large=>#<Twitter::Size h=1024 w=576>,
  :thumb=>#<Twitter::Size h=150 w=150>,
  :medium=>#<Twitter::Size h=1024 w=576>}]

なお、indices, url(uri), display_url, expanded_urlなどのメソッドは、ツイート本文に埋め込むURLに関連しているので、複数の返値が同じ値になります。

m_ary.map{ |m| m.indices }
=> [[118, 140], [118, 140], [118, 140]]

m_ary.map{ |m| m.url }
=> [#<Addressable::URI:0x3fdd9a8da650 URI:http://t.co/Mljw3xOY3B>,
 #<Addressable::URI:0x3fdd9a8dcedc URI:http://t.co/Mljw3xOY3B>,
 #<Addressable::URI:0x3fdd9a8df768 URI:http://t.co/Mljw3xOY3B>]

m_ary.map{ |m| m.display_url }
=> ["pic.twitter.com/Mljw3xOY3B",
 "pic.twitter.com/Mljw3xOY3B",
 "pic.twitter.com/Mljw3xOY3B"]

m_ary.map{ |m| m.expanded_url }
=> [#<Addressable::URI:0x3fdd9a8f8ba0 URI:http://twitter.com/riocampos/status/449746301857447936/photo/1>,
 #<Addressable::URI:0x3fdd9a8f9dd4 URI:http://twitter.com/riocampos/status/449746301857447936/photo/1>,
 #<Addressable::URI:0x3fdd9a8fefdc URI:http://twitter.com/riocampos/status/449746301857447936/photo/1>]
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away