Home

Site converted to django-friendly: FriendFeed integration


I posted about it on Twitter this afternoon, but I finally succumbed to the FriendFeed trend and I’m going to let them do the hard work of aggregating my life stream and normalizing it. Honestly, I don’t need to fight the never-ending battle of scraping and parsing a billion feeds when a company flush with cash and smart people can do it for me, right? :)

What’s great is that they provide a fabulous API and so I took some time yesterday to build a Django application I call django-friendly that you can pop into your site to integrate everything on your FriendFeed (entries, likes, comments, media) into your own site!

  • Download and install the Python FriendFeed API module somewhere on your Python path
  • Grab the application from the Google Code project site
  • Add the line friendly to your settings.py
  • Add a setting to your settings.py called FRIENDFEED_NICKNAME and set it to your FriendFeed username.
  • Perform a ./manage.py syncdb
  • Go through the management commands I detail below to back fill in some information if you’d like. Alternatively you can just set up a cron tab to periodically call the general case: ./manage.py feed --feeds --likes
  • Dig into the template tags I detail below to start displaying the information on your site in interesting ways!

There are a few models that implement all of the normalized fields that FriendFeed can return back to you, such as your entries, services, FriendFeed users, media, thumbnails, et cetera.

There’s a few management commands you can script to call on a regular basis to synchronize your database. Here are some possible usage cases:

This will pull the most recent 30 entries and insert any new comments, likes, entries, and so forth.

./manage.py feed --feeds

This will go back as far as it can (around 330 entries) and gather all the appropriate links and such:

./manage.py feed --feeds --all

You can get more items from other services by filtering what you pull like this. This will pull the 30 most recent Flickr entries

./manage.py feed --feeds --service flickr

This will pull all the Flickr entries it can get at:

./manage.py feed --feeds --service flickr --all

The service name you supply is a FriendFeed specified nickname for the service. They are typically pretty guessable (googlereader, twitter, pownce, googletalk, lastfm, et cetera). The only one that might not be apparent are pure FriendFeed items which are specified using the internal nickname.

You can pull in your liked items with the following command:

./manage.py feed --likes

All of the other arguments (–all, –service) apply for likes as well. In fact you can pull your items and likes at the same time like so:

./manage.py feed --feeds --likes --all

Template tags

There are currently only two template tags for pulling FriendFeed information into your templates.

get_friendfeed_entry_list

This is a fairly complex tag; it was built to the specifications I needed for my blog here, and I think it’s fairly applicable to nearly any use case. Here’s how it works, first you’ve got the load the friendly template tags:

{% load friendly %}

Then you can call the tag like this (simple case):

{% get_friendfeed_entry_list for 'all' 30 as friendfeed_entries %}

This will pull 30 most recent entries from all services and stick the resulting list of entries into a context variable called friendfeed_entries which you can loop over and access just like any other template variable. For example:


{% for entry in friendfeed_entries %}
<li>
  <img src="{{ entry.service.iconURL}}"> 
  <a href="{{ entry.link }}">{{ entry.title }}</a>
</li>
{% endfor %}

You can get a lot more complex. Lets say you wanted to pull any kind of entry except Flickr photos:


{% get_friendfeed_entry_list for 'all' except 'flickr' as no_flickr %}

You can even specify multiple services to exclude:


{% get_friendfeed_entry_list for 'all' except 'flickr|picasa|smugmug' as no_photos %}

As you might’ve excpected, you can do the same when you filter. You can specify only certain services to be pulled instead of all of them like so:


{% get_friendfeed_entry_list for 'lastfm|pandora' 30 as music %}
{% get_friendfeed_entry_list for 'reddit|digg|googlereader' 100 as links %}

Getting likes

You can use standard model methods to get the likes on an entry. For example to show a like-count:

{{ entry.num_likes }} {{ entry.num_likes|pluralize:"person,people" }} liked this.

You could alternative iterate over entry.like_set.all to print out each like.

Issues with this tag

Currently, the process of pulling out media thumbnails is a bit ugly. I hope to write some convenience methods. This is how you have to do it now:

{% get_friendfeed_entry_list for 'flickr' 12 as flickr_photos %}
{% for photo in flickr_photos %}
  <a href="{{ photo.link }}" rel="photo" class="image" title="{{ photo.title }}">
    <img src="{{ photo.media_set.all.0.mediathumbnail_set.all.0.url }}">
  </a>
{% endfor %}

Nasty, right?

get_friendfeed_comment_list

For any FriendFeed entry, there’s the possibility that you or others have left comments. In the case of Google Reader (and Reddit and Digg I believe) your comments on a story are imported into FriendFeed as the first comment.

You can use this tag to pull out comments by everyon or by a specific person. The specific case is what I use to filter out just my comments. You can use it like thus:


{% get_friendfeed_entry_list for 'all' as object_list %}
{% for entry in object_list %}
  {% get_friendfeed_comment_list for entry.ff_id as my_comments by 'clint' %}
       <dt>
         <img src="{{ entry.service.iconURL }}"> 
         <a href="{{ entry.link }}">{{ entry.title }}</a>
       </dt>
    
       {% if my_comments %}
       {% for comment in my_comments %}
         <dd>{{ comment.body }}</dd>
       {% endfor %}
       {% endif %}
{% endfor %}

You could leave out the by 'clint' argument to get comments by all users on the entries.

I think that’s all there is right now. You can see how I’ve put all of this into action here on my site in the middle sidebar and in my Life Stream page. I paginated the results using the awesome django-pagination application.