Today's article is a discussion about some of the infrastructure for running this site. So far as I can tell from the logs and analytics, nearly everyone reading this blog does so via RSS. The RSS feed for this site is provided by FeedBurner, now part of Google. FeedBurner supports FeedFlares, small widgets appended after the content which can supply additional information or link to other services. I currently use several FeedFlares in the RSS feed, for del.icio.us and friendfeed. The friendfeed flare is new, and is the topic of this writeup.
friendfeed is a social media aggregation service, collecting updates from services like Digg, Flickr, and various blog platforms into a single stream of updates. Many good articles about friendfeed can be found on louisgray.com.
The RSS feed for this blog is imported into friendfeed where people can see it, mark it as something they liked, or leave comments. At the time I started working on this project there was not a FeedFlare for friendfeed. There is now, but I decided to finish my version anyway and post it here. As Google App Engine is my favorite new toy, the FeedFlare is a GAE application.
We'll go straight to the code which gathers information from friendfeed to create the FeedFlare. I'm going to skip the boilerplate code for an application on the Google App Engine. It can be found on an earlier article about the App Engine, if needed. The complete source for this feedflare is also available for download.
class FriendfeedFlare(webapp.RequestHandler): def get(self): self.response.headers['Content-Type'] = "text/plain" scheme, host, path, param, query, frag = urlparse.urlparse(self.request.url) args = cgi.parse_qs(query) url = self.parseArg(args, "url") nickname = self.parseArg(args, "nickname") api_key = self.parseArg(args, "api_key") if (url == None): self.response.out.write("<FeedFlare><Text>No URL specified!</Text></FeedFlare>\n") return subscribed = 1 if (nickname != None and api_key != None) else 0
try: ffsession = friendfeed.FriendFeed(nickname, api_key); entries = ffsession.fetch_url_feed(url, subscribed); except IOError: self.error(503); return
totalshares = 0 totalcomments = 0 likers = set() linkurl = "http://friendfeed.com/" linkcomments = -1 for entry in entries["entries"]: totalshares += 1 numcomments = len(entry["comments"]) totalcomments += numcomments if (numcomments > linkcomments): linkurl = "http://friendfeed.com/e/" + entry["id"] linkcomments = numcomments for like in entry["likes"]: liker = like["user"] likers.add(liker["name"]) totallikes = len(likers)
self.response.out.write("<FeedFlare>\n") if (totalshares == 0): self.response.out.write(" <Text>On Friendfeed: 0 shares</Text>\n") else: self.response.out.write(" <Text>On Friendfeed: " + \ self.fmtTotal(totalshares, "Share") + ", " + \ self.fmtTotal(totallikes, "Like") + ", " + \ self.fmtTotal(totalcomments, "Comment") + \ "</Text>\n"); self.response.out.write(" <Link href=\"" + linkurl + "\"/>\n"); self.response.out.write("</FeedFlare>") return
def fmtTotal(self, count, descr): suffix = "" if (count == 1) else "s" return str(count) + " " + descr + suffix def parseArg(self, args, argname): try: ret = args[argname] except: ret = None return ret
Thats it, or rather thats the interesting part. The complete source can be downloaded.
The next question is, what is missing? What does it not do, that perhaps it should?
- There is no caching of the result. Every request for the FeedFlare results in another API request to friendfeed.com. I believe this is acceptable because FeedBurner limits the rate of FeedFlare requests to about one per two hours.
- The link in the generated FeedFlare points to the friendfeed entry with the most comments. This is a compromise. I'd rather to link to a search results page with all of the entries regarding the given URL, but can not find a good way to do it. I'd have to make the FeedFlare dynamically construct a page populated with all of the links, showing all of the likes and comments... and that is too much work for this little project. I hope that someday, friendfeed.com will provide a way to supply multiple entry IDs to appear on a single page.
Using the FeedFlare
If you are interested in using this FeedFlare on your own blog, please feel free. You have a few options:
- To use it without a specific nickname (so the results will include Everyone on friendfeed whether they follow you or not) you can use this link as the Flare Unit URL in the Feedburner -> Optimize -> FeedFlares page for your feed.
To configure it to only include people who subscribe to you on friendfeed, download http://feedflare.geekhold.com/feedflareunit/friendfeeduser.xml">friendfeeduser.xml. Replace MY_NICKNAME with your friendfeed account name, and MY_API_KEY with your Remote API Key, and put the modified file somewhere on your own site to be used to configure FeedBurner.
The functionality to restrict the results to your subscribers is not working right now. Please stay tuned. I'll post an update on friendfeed.com if I get it working again.
- If you don't like something about the way this code works, you're free to modify it. You can download the source code, set up your own Google App Engine application, and modify it as desired.