titi: Agile Monkeying around with Activity Streams
Titi is a first stab at a universal ActivityStream interface.
How you can help
- Give the coders something to target: a) Pick an API or feed to add. For ideas, choose one not yet implemented from “Supported Feeds” list, below. b) Get a sample of the raw API or feed output (use your own account so noone files a copyright violation bug report). c) create an appropriately-named file, say
spec/data/providers/PROVIDER_NAME/PROVIDER_FEED_NAME-raw_feed.xml
orspec/data/providers/PROVIDER_NAME/PROVIDER_FEED_NAME-raw_api.json
or whatever. d) If that feed is not yet in activity_streams format, use the raw sample to create an example activity_streams output. e) Issue a pull request. - Take an API or feed that has example input and output and code its interface.
Example
Let’s define a super-simple twitter user and status model:
User = Struct.new(
:id, :screen_name, :protected, :followers_count, :friends_count, :statuses_count, :favourites_count, :created_at,
:name, :url, :location, :description, :time_zone, :utc_offset,
:profile_background_color, :profile_text_color, :profile_link_color, :profile_sidebar_border_color, :profile_sidebar_fill_color, :profile_background_tile, :profile_background_image_url, :profile_image_url
)
Status = Struct.new( :id, :created_at, :user, :favorited, :truncated,
:in_reply_to_user_id, :in_reply_to_status_id, :text, :source,
:in_reply_to_screen_name )
With no other work, we can pull a raw JSON hash off the wire and create model instances:
raw_json_resp = RestClient.get("http://twitter.com/statuses/show/12233609555.json")
Twitter::Status.adapt(JSON.load(raw_json_resp.to_s))
#=> #<struct Titi::Provider::Twitter::Status id=12233609555, created_at="Thu Apr 15 17:01:52 +0000 2010", user=#<struct Titi::Provider::Twitter::User id=1468401, screen_name="sockington", protected=false, followers_count=1520814, friends_count=457, statuses_count=6234, favourites_count=2, created_at=Mon, 19 Mar 2007 03:45:00 +0000, name="Sockamillion", url="http://www.sockington.org/", location="Waltham, MA", description="I am Jason Scott's Cat.", time_zone="Eastern Time (US & Canada)", utc_offset=-18000, profile_background_color="48484c", profile_text_color="000000", profile_link_color="000000", profile_sidebar_border_color="79c021", profile_sidebar_fill_color="585e7e", profile_background_tile=false, profile_background_image_url="http://a1.twimg.com/profile_background_images/6682718/SocksTwitter.jpg", profile_image_url="http://a3.twimg.com/profile_images/77537329/IMG_3738_normal.JPG">, favorited=false, truncated=false, in_reply_to_user_id=nil, in_reply_to_status_id=nil, text="THANK GOODNESS THE LIBRARY OF CONGRESS HAS UNDERSTOOD THE IMPORTANCE OF MY TWEETS what do you mean others are getting in too", source="<a href=\"http://apiwiki.twitter.com/\" rel=\"nofollow\">API</a>", in_reply_to_screen_name=nil>
Titi lets you write a straightforward and compact adaptor to activity stream format:
class Titi::Provider::Twitter::Status
def to_activity_stream_entry
ActivityStreams::Entry.adapt(
:id => %Q{tag:twitter.com,2007:http://twitter.com/#{user.screen_name}/statuses/#{id}},
:title => text,
:content => text,
:published => created_at,
:verb => :post
) do |entry|
entry.has_author user.name, user.url
entry.has_obj do |activity_obj|
activity_obj.id = id
activity_obj.title = text
activity_obj.published = created_at
activity_obj.updated = created_at
activity_obj.author = entry.author
end
end
end
end
Where the mapping is direct, you can use an attribute => attribute hash, as shown in the call to ActivityStreams::Entry.adapt. For anything more complex, you can run arbitrary code in the method’s block (the part within the do … end segment)
Here’s example output. note: this isn’t canonical activity streams format: the XML serialization needs work.
tweet = Twitter::Status.get(12233609555)
entry = tweet.to_activity_stream_entry
puts entry.to_xml
<?xml version="1.0" encoding="UTF-8"?>
<entry>
<verb type="symbol">post</verb>
<mood nil="true"></mood>
<category nil="true"></category>
<author>
<name>Sockamillion</name>
<uri>http://www.sockington.org/</uri>
</author>
<title>THANK GOODNESS THE LIBRARY OF CONGRESS HAS UNDERSTOOD THE IMPORTANCE OF MY TWEETS what do you mean others are getting in too</title>
<actor nil="true"></actor>
<published type="datetime">2010-04-15T17:01:52+00:00</published>
<rank nil="true"></rank>
<sync nil="true"></sync>
<id>tag:twitter.com,2007:http://twitter.com/sockington/statuses/12233609555</id>
<content>THANK GOODNESS THE LIBRARY OF CONGRESS HAS UNDERSTOOD THE IMPORTANCE OF MY TWEETS what do you mean others are getting in too</content>
<target nil="true"></target>
<link nil="true"></link>
<object>
<author>
<name>Sockamillion</name>
<uri>http://www.sockington.org/</uri>
</author>
<title>THANK GOODNESS THE LIBRARY OF CONGRESS HAS UNDERSTOOD THE IMPORTANCE OF MY TWEETS what do you mean others are getting in too</title>
<published>Thu Apr 15 17:01:52 +0000 2010</published>
<id type="integer">12233609555</id>
<vevent nil="true"></vevent>
<content nil="true"></content>
<link nil="true"></link>
<updated>Thu Apr 15 17:01:52 +0000 2010</updated>
<object-type nil="true"></object-type>
</object>
<source nil="true"></source>
<updated nil="true"></updated>
</entry>
Supported Feeds
The goal is to cover all the following services. Thanks to Cliqset and Rob Dolin for the list:
:social => %w[ AvatarsUnited Bebo Brightkite Friendster Friendfeed GamerDna Gather Hi5 Hyves Identica
Jaiku Multiply Myspace Netlog Plurk Raptr Skyrock Twitter Facebook LinkedIn Plaxo Xing ],
:blogging => %w[ Ameba Baidu Blogger Douban Livejournal Posterous Tumblr Wordpress Xanga TypePad MoveableType WlSpaces ],
:bookmarking => %w[ Delicious Digg Diigo GoogleReader Hatena Meneame Mixx Newsvine Propeller Reddit Stumbleupon Twine ],
:music => %w[ Blipfm Buzznet Ilike Lastfm Pandora Zooomr Zune ],
:video => %w[ BuddyTv TwelveSeconds Bliptv Cinchcast DailyMotion FunnyOrDie Hulu Joost Metacafe Qik Revver Vimeo Youtube ],
:photos => %w[ DeviantArt Flickr Fotolog MobyPicture Photobucket Picasa Photocase Slideshare Smotri Smugmug Visualizeus MetroFlog WlSkyDrive ],
:reviews => %w[ Blippr Corkd Flixster Goodreads Librarything Qype Readernaut Yelp ],
:messengers => %w[ AIM WlMessenger ],
:location => %w[ Gowalla Foursquare Tripit UrbanSpoon Whirl ],
:gaming => %w[ Zynga Playdom MsgrGames ],
Copyright
Copyright © 2010 Infochimps, Inc. Available under Apache license: see LICENSE for details.