Twitterで写真が4枚まで添付できるようになりました、アクセスできるAPIがなかなか公開されませんでした。
そして、ようやく(日本時間の)今日から使えるようになりました。
Twitter gemは優秀なのでそのままアクセスできますが、ツイート添付写真に関する情報を取得するTwitter::Entities#media
メソッドは、当然ながら写真1枚の情報しか取得できません。
これを拡張するモンキーパッチを作成しましたので公開します。
おそらくTwitter gemも同様の実装で対応する(追記:v5.10.0 で対応済)でしょうが、それまでご利用ください。
あと、おそらく対応してくれないであろうTwitter gem バージョン4でも動くパッチも書くつもりです。
パッチ
とりあえずTwitter gem 5.9.0で動作確認しましたが、おそらくバージョン5全てで動作すると思います。
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枚添付されています。
タグ付けされた側は通知が来る。そしてタグ付けを含むツイートには(ツイートした垢が鍵付きじゃなければ、タグ付けに関係しない垢からも)タグ付けされた垢名を確認できる。 新機能の写真タグ付けに加え、写真は1ツイート4枚まで追加可能になった。 pic.twitter.com/Mljw3xOY3B
— riocampos(りおかんぽす) (@riocampos) March 29, 2014
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
などがあります。
attrs
はTwitter::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>]