del.icio.us .:. tweet

First Steps with the MyBlogLog API .:. kentbrewster.com

After much hard work, the team at MyBlogLog and the Yahoo! Developer Network--including but definitely not limited to Todd Sampson, Ian Kennedy, J.R. Conlin, and the one and only Chris Goffinet--have released the MyBlogLog API into limited public beta.

Included in the API are the usual goodies already found in the reader roll, plus other stuff like tags, discussion, and outside communities.

That last bit is important: suddenly there's a wide-open source of information about who lives where on the Web. Over the past week I've begun pinging various services as they come up for my users; as of right now, we should see:

  • Sites authored -- if you click an image, the app will re-load and show you the readers from there. This is fun; try it out!
  • Photos from Flickr
  • Status updates from Twitter
  • Current professional status from LinkedIn
  • Bookmarks from del.icio.us
  • Pages shared through Digg
  • Songs scrobbled through Last.fm
  • Next events on Upcoming
  • Last five videos favorited on YouTube

My Recent Visitors

Things to Do and Notice

  • The most recent visitor might not be you if you just got here and have not seen anything else on the site; I can't imagine the API could possibly be that fast. (I'm willing to be pleasantly surprised, though.)
  • If you've been tagged on MyBlogLog, they ought to show up here. If you haven't, go do it now!
  • If you've registered an outside social service id (like Myspace or Flickr) via MyBlogLog, you ought to see it listed. If you click it, you'll go straight on over to your profile there.

Caveats and Gotchas

  • Right, sorry, it's an invite-only beta. Please trust me on this when I say there are Good and Sufficient Reasons for this, and the closed period will be kept as short as humanly possible.
  • Missing from the API is an easy way to simply link a user's name to his or her designated home page. If everybody delegated their openIDs through their home pages--I use idproxy.net--this would become a non-problem.
  • There's a fair bit of bouncing around; we have to make an API call to get user details for each reader from MyBlogLog, and then there's a call to each outside service that person might have listed. So far nothing's terribly broken, mostly due to the fact that I'm leaning on Pipes quite heavily.

Please Note

Although I am a developer who works for Yahoo!, I don't work on MyBlogLog or any of the other services that show up here. Absolutely nothing you see on this page--including random stuff written and broadcast by any of the services that are being returned as a result of connections between the MyBlogLog API and outside services--should be taken as official messaging from Yahoo!

In addition to MyBlogLog, data for this hack comes from a wide variety of sources, including Yahoo's MyBlogLog, Flickr, Upcoming, and del.icio.us services. I believe I've attributed it properly, by linking to http://developer.yahoo.com/about, as requried by YDN's attribution page.

The Code

// API-powered mybloglog badge, case-hardened
// copyright Kent Brewster, 2008
// see http://kentbrewster.com/first-steps-with-the-mybloglog-api for details
// currently includes:
// sites authored (with recursive exploration; click to go!)
// most recent Twitter tweet, last five Flickr photos, last five del.icio.us bookmarks,
// last five pages Dugg, last five songs scrobbled at last.fm, next five events from upcoming,
// last five movies favorited on YouTube, 
// current positions from LinkedIn, if you have a public profile at linkedin.com/yourname

( function() {
   var trueName = '';
   for (var i = 0; i < 16; i++) { trueName += String.fromCharCode(Math.floor(Math.random() * 26) + 97); }
   window[trueName] = {};
   var $ = window[trueName];
   $.f = function() {
      return {
         init : function(el) {
            $.f.getDetails = [];
            $.f.pingDelicious = [];
            $.f.pingDugg = [];
            $.f.pingLastFM = [];
            $.f.pingLinkedIn = [];
            $.f.pingUpcoming = [];
            $.f.pingYouTube = [];
            $.f.svcUrl = {
               "30 boxes":"~",
               "bebo":"http://bebo.com/Profile.jsp?MemberId=~",
               "blogger":"http://www.blogger.com/profile/~",
               "del.icio.us":"http://delicious.com/~",
               "digg":"http://www.digg.com/users/~",
               "ebay":"http://myworld.ebay.com/~",
               "facebook":"http://www.facebook.com/profile.php?id=~",
               "flickr":" http://www.flickr.com/photos/~/",
               "friendster":"http://~.blogs.friendster.com/",
               "google calendar":"http://~.jaiku.com/",
               "jaiku":"http://~.jaiku.com/",
               "jumpcut":"http://www.jumpcut.com/~",
               "kiva":"http://www.kiva.org/lender/~",
               "last.fm":"http://www.last.fm/user/~",
               "linkedin":"http://www.linkedin.com/in/~",
               "livejournal":"http://~.livejournal.com/",
               "myspace":"http://myspace.com/~",
               "netflix":"http://rss.netflix.com/QueueRSS?id=~",
               "openid":"~",
               "plaxo":"~",
               "pownce":"http://www.pownce.com/~",
               "second life":"~",
               "shelfari":"http://www.shelfari.com/~",
               "stumbleupon":"http://~.stumbleupon.com",
               "technorati":"http://www.technorati.com/people/technorati/~",
               "textamerica":"http://~.textamerica.com/",
               "the dj list":"http://www.thedjlist.com/djs/~",
               "twitter":"http://www.twitter.com/~",
               "typekey":"http://profile.typekey.com/~",
               "upcoming":"http://upcoming.yahoo.com/user/~",
               "wakoopa":"http://www.wakoopa.com/~",
               "wink":"http://wink.com/profile/~",
               "yelp":"http://www.yelp.com/user_details?userid=~",
               "youtube":"http://youtube.com/user/~",
               "zorpia":"http://www.zorpia.com/~"
            };
            if (document.getElementById(el)) {

               if (mbl_recent_visitor) {
                  $.f.currentUser = mbl_recent_visitor;
               }

               $.w = document.getElementById(el);
               $.w.innerHTML = '';
               
               $.w.h = document.createElement('H3');
               $.w.appendChild($.w.h);
               
               $.w.c = document.createElement('DIV');
               $.w.appendChild($.w.c);

               $.w.f = document.createElement('DIV');
               $.w.f.className = 'attrib';
               var a = document.createElement('A');
               a.innerHTML = 'Web services by Yahoo!';
               a.href = 'http://developer.yahoo.com/about/';
               a.target = '_blank';
               $.w.f.appendChild(a);
               $.w.appendChild($.w.f);
               
               $.f.callback = trueName + '.f.getUsers';
               $.f.appid = '[my api key here]';
               $.f.count = 16;
               $.f.orgCommunityId = '2006110818574284';
               $.f.communityId = $.f.orgCommunityId;
               $.w.c.innerHTML = '';
               $.w.h.innerHTML = 'Pinging the MyBlogLog API....';
               $.f.getUsers();
            }
         },
         getCurrentUser : function() {
            $.f.getCurrentVisitorCallback = function(r) {
               delete $.f.getCurrentVisitorCallback;
               $.f.removeScript(trueName + '.f.getCurrentVisitorCallback');
               $.f.renderUser(r);                 
            };
            var callback = trueName + '.f.getCurrentVisitorCallback';
            var url = 'http://mybloglog.yahooapis.com/v1/user/';
            url += $.f.currentUser;
            url += '?format=json&callback=' + callback;
            url += '&appid=' + $.f.appid;
            $.f.runScript(url, callback);         
         },
         getUsers : function() {
            $.w.c.innerHTML = '';
            $.f.foundCurrentUser = false;
            $.f.pingUsers = function(r) {
               
               delete $.f.pingUsers;

               $.w.h.innerHTML = ''
               $.w.h.appendChild(document.createTextNode('Recent Visitors to '));

               var a = document.createElement('A');
               a.innerHTML = r.name;
               a.href = 'http://www.mybloglog.com/buzz/community/' + r.id;
               a.target = '_blank';
               $.w.h.appendChild(a);
               
               if ($.f.communityId != $.f.orgCommunityId) {
                  $.w.h.appendChild(document.createTextNode(' - '));
                  var a = document.createElement('A');
                  a.innerHTML = 'back to BFG';
                  a.style.color = '#00f';
                  a.rel = $.f.orgCommunityId;
                  a.onclick = function() {
                     $.f.communityId = this.rel;
                     $.f.getUsers();
                  }
                  $.w.h.appendChild(a);
               }
               
               $.f.removeScript($.f.callback);
               if (r.users && r.users.user) {
                  var max = r.users.user.length;
                  for (var i = max; i > 0; i--) {
                     var t = i - 1;
                     $.f.renderUser(r.users.user[t]);                 
                  }
               } else {
                  $.w.h.appendChild(document.createTextNode(' - No readers found, sorry!'));
               }
               if ($.f.currentUser) {
                  $.f.getCurrentUser();
               }
            };
            var url = 'http://mybloglog.yahooapis.com/v1/community/';
            url += $.f.communityId;
            url += '/readers?format=json&callback=' + trueName + '.f.pingUsers';
            url += '&count=' + $.f.count;
            url += '&appid=' + $.f.appid;
            $.f.runScript(url, $.f.callback);
         },
         renderUser : function(u) {
            var div = document.createElement('DIV');
            div.className = 'r';
            div.id = u.id;
            
            var p = document.createElement('P');;
            var img = document.createElement('IMG');
            img.src = u.pict;
            img.height = '48';
            img.width = '48';
            img.alt = u.nickname;
            img.title = u.nickname;
            img.align = 'absmiddle';
            p.appendChild(img);
            p.appendChild(document.createTextNode(' '));
            var a = document.createElement('A');
            a.href = u.url;
            a.target = '_blank';
            a.innerHTML = u.nickname.replace(/<em>/, '').replace(/<\/em>/, '');
            p.appendChild(a);

            if ($.f.currentUser) {
               if (div.id == $.f.currentUser) {
                  p.appendChild(document.createTextNode(' -- this is you!'));
               }
            }
            
            div.appendChild(p);
            $.w.c.appendChild(div);
            $.f.getReaderDetails(div.id);
         },
         getReaderDetails : function(id) {
            var n = $.f.getDetails.length;
            $.f.getDetails[n] = function(r) {
               delete $.f.getDetails[n];
               $.f.removeScript(trueName + '.f.getDetails[' + n + ']');

               var s = r.sites_authored;
               if (s && s.site) {
                  var p = document.createElement('P');
                  p.appendChild(document.createTextNode('Sites Authored -- click to explore reader communities!'));
                  p.appendChild(document.createElement('BR'));
                  var cj = s.site.length;
                  if (cj > 6) {
                     cj = 6;
                  }
                  for (var j = 0; j < cj; j++) {
                     var a = document.createElement('A');
                     a.title = s.site[j].description;
                     a.rel = s.site[j].id;
                     a.onclick = function() {
                        $.f.communityId = this.rel;
                        $.f.getUsers();
                     }
                     var img = document.createElement('IMG');
                     img.src = s.site[j].pict;
                     a.appendChild(img);
                     p.appendChild(a);
                  }
                  document.getElementById(id).appendChild(p);
               }


               var p = document.createElement('P');
               if (r.tags && r.tags.tag && r.tags.tag.length) {
                  p.appendChild(document.createTextNode('Tags: '));
                  var t = r.tags.tag.length;
                  for (var i = 0; i < t; i++) {
                     var a = document.createElement('A');
                     a.href = r.tags.tag[i].url;
                     if (i) {
                        p.appendChild(document.createTextNode(', '));
                     }
                     a.innerHTML = r.tags.tag[i].name.toLowerCase();
                     a.title = 'Tagged "' + r.tags.tag[i].name + '" by '  + r.tags.tag[i].count + ' user';
                     if (r.tags.tag[i].count > 1) {
                        a.title += 's';
                     }
                     a.title += '.';
                     a.alt = a.title;
                     p.appendChild(a);
                  }
                  p.appendChild(document.createTextNode('. Know this person? '));
                  var a = document.createElement('A');
                  a.innerHTML = 'Add some tags.';
                  a.target = '_blank';
                  a.href = 'http://www.mybloglog.com/buzz/members/' + r.screen_name;
                  p.appendChild(a);
               } else  {
                  p.appendChild(document.createTextNode('No tags found. Know this person? '));
                  var a = document.createElement('A');
                  a.innerHTML = 'Go play tag!';
                  a.target = '_blank';
                  a.href = 'http://www.mybloglog.com/buzz/members/' + r.screen_name;
                  p.appendChild(a);
               }
               document.getElementById(r.id).appendChild(p);
               if (r.profile.services && r.profile.services.service && r.profile.services.service.length) {
                  var p = document.createElement('P');
                  p.appendChild(document.createTextNode('Meet Me On: '));
                  for (var i = 0; i < r.profile.services.service.length; i++) {
                     if (i) {
                        p.appendChild(document.createTextNode(', '));
                     }
                     var a = document.createElement('A');
                     a.innerHTML = r.profile.services.service[i].name;
                     if ($.f.svcUrl[r.profile.services.service[i].name]) {
                        a.href = $.f.svcUrl[r.profile.services.service[i].name].replace(/~/,r.profile.services.service[i].id);
                     }
                     a.target = '_blank';
                     p.appendChild(a);
                     if (r.profile.services.service[i].name == 'upcoming') {
                        $.f.getUpcoming(r.id, r.profile.services.service[i].id);
                     }
                     if (r.profile.services.service[i].name == 'twitter') {
                        $.f.getTweet(r.id, r.profile.services.service[i].id);
                     }
                     if (r.profile.services.service[i].name == 'flickr') {
                        $.f.getFlickr(r.id, r.profile.services.service[i].nsid);
                     }
                     if (r.profile.services.service[i].name == 'del.icio.us') {
                        $.f.getDelicious(r.id, r.profile.services.service[i].id);
                     }
                     if (r.profile.services.service[i].name == 'linkedin') {
                        $.f.getLinkedIn(r.id, r.profile.services.service[i].id);
                     }
                     if (r.profile.services.service[i].name == 'digg') {
                        $.f.getDugg(r.id, r.profile.services.service[i].id);
                     }
                     if (r.profile.services.service[i].name == 'last.fm') {
                        $.f.getLastFM(r.id, r.profile.services.service[i].id);
                     }
                     if (r.profile.services.service[i].name == 'youtube') {
                        $.f.getYouTube(r.id, r.profile.services.service[i].id);
                     }
                  }
                  p.appendChild(document.createTextNode('. '));
                  document.getElementById(r.id).appendChild(p);
               }
            };
            var callback = trueName + '.f.getDetails[' + n + ']';
            var url = 'http://mybloglog.yahooapis.com/v1/user/';
            url += id;
            url += '?format=json&callback=' + callback;
            url += '&count=' + $.f.count;
            url += '&appid=' + $.f.appid;
            $.f.runScript(url, callback);
         },
         getYouTube : function(id, nick) {
            var n = $.f.pingYouTube.length;
            var p = document.createElement('P');
            p.rel = nick;
            p.id = 'youtube_' + n;
            document.getElementById(id).appendChild(p);
            var callback = trueName + '.f.pingYouTube[' + n + ']';
            $.f.pingYouTube[n] = function(r) {
               var o = document.getElementById('youtube_' + n);
               delete $.f.pingYouTube[n];
               $.f.removeScript(trueName + '.f.pingYouTube[' + n + ']');
               if (r.value.items) {
                  o.parentNode.insertBefore(document.createTextNode('YouTube Movies:'), o);
                  var c = r.value.items;
                  var b = c.length;
                  if (b > 5) { b = 5; }
                  for (var i = 0; i < b; i++) {
                     var a = document.createElement('A');
                     var img = document.createElement('IMG');
                     img.src = c[i]['media:group']['media:thumbnail'][0].url;
                     img.height = c[i]['media:group']['media:thumbnail'][0].height;
                     img.width = c[i]['media:group']['media:thumbnail'][0].width;
                     img.title = c[i]['media:group']['media:title'].content;
                     a.appendChild(img);
                     a.href = c[i].link;
                     a.target = '_blank';
                     o.appendChild(a);
                  }
               }
            };
            var url = 'http://pipes.yahoo.com/kentbrew/youtube_getmovies?_render=json&_callback=' + callback + '&s=' + nick;
            $.f.runScript(url, callback);
         },
         getUpcoming : function(id, nick) {
            var n = $.f.pingUpcoming.length;
            var p = document.createElement('P');
            var ul = document.createElement('UL');
            ul.rel = nick;
            ul.id = 'upcoming_' + n;
            p.appendChild(ul);
            document.getElementById(id).appendChild(p);
            var callback = trueName + '.f.pingUpcoming[' + n + ']';
            $.f.pingUpcoming[n] = function(r) {
               var o = document.getElementById('upcoming_' + n);
               delete $.f.pingUpcoming[n];
               $.f.removeScript(trueName + '.f.pingUpcoming[' + n + ']');
               if (r.value.items && r.value.items[0] && r.value.items[0].channel.item) {
                  o.parentNode.insertBefore(document.createTextNode('Upcoming events:'), o);
                  var c = r.value.items[0].channel.item;
                  var b = c.length;
                  if (b > 5) { b = 5; }
                  for (var i = 1; i < b; i++) {
                     var li = document.createElement('LI');
                     var a = document.createElement('A');
                     a.innerHTML = c[i]['xCal:summary'];
                     a.href = c[i]['link'];
                     a.target = '_blank';
                     li.appendChild(a);
                     var d = c[i]['xCal:dtstart'];
                     var pd = d.substr(0, 4) + '-' + d.substr(4, 2) + '-' + d.substr(6, 2);
                     li.appendChild(document.createTextNode(' - ' + pd));
                     o.appendChild(li);
                  }
               }
            };
            var url = 'http://pipes.yahoo.com/kentbrew/upcoming_getevents?_render=json&_callback=' + callback + '&s=' + nick;
            $.f.runScript(url, callback);
         },
         getLastFM : function(id, nick) {
            var n = $.f.pingLastFM.length;
            var p = document.createElement('P');
            var ul = document.createElement('UL');
            ul.rel = nick;
            ul.id = 'lastFM_' + n;
            p.appendChild(ul);
            document.getElementById(id).appendChild(p);
            var callback = trueName + '.f.pingLastFM[' + n + ']';
            $.f.pingLastFM[n] = function(r) {
               var o = document.getElementById('lastFM_' + n);
               delete $.f.pingLastFM[n];
               $.f.removeScript(trueName + '.f.pingLastFM[' + n + ']');
               if (r.value.items && r.value.items[0] && r.value.items[0].channel.item) {
                  o.parentNode.insertBefore(document.createTextNode('Recently scrobbled tracks from last.fm:'), o);
                  var c = r.value.items[0].channel.item;
                  var b = c.length;
                  if (b > 6) { b = 6; }
                  for (var i = 1; i < b; i++) {
                     var li = document.createElement('LI');

                     var t = c[i].title.split(' \u2013 ');

                     var artist = document.createElement('A');
                     artist.href = c[i].description;
                     artist.innerHTML =t[0];
                     artist.target = '_blank';
                     li.appendChild(artist);

                     li.appendChild(document.createTextNode(' : '));

                     var song = document.createElement('A');
                     song.innerHTML = t[1];
                     song.href = c[i].link;
                     song.target = '_blank';
                     li.appendChild(song);

                     o.appendChild(li);
                  }
               }
            };
            var url = 'http://pipes.yahoo.com/kentbrew/lastfm_getrecenttracksbyuser?_render=json&_callback=' + callback + '&s=' + nick;
            $.f.runScript(url, callback);
         },
         getDugg : function(id, nick) {
            var n = $.f.pingDugg.length;
            var p = document.createElement('P');
            var ul = document.createElement('UL');
            ul.rel = nick;
            ul.id = 'dugg_' + n;
            p.appendChild(document.createTextNode('Recently Dugg:'));
            p.appendChild(ul);
            document.getElementById(id).appendChild(p);
            var callback = trueName + '.f.pingDugg[' + n + ']';
            $.f.pingDugg[n] = function(r) {
               var o = document.getElementById('dugg_' + n);
               delete $.f.pingDugg[n];
               $.f.removeScript(trueName + '.f.pingDugg[' + n + ']');
               if (r.value.items && r.value.items[0]) {
                  var c = r.value.items[0].story;
                  var b = c.length;
                  if (b > 5) { b = 5; }
                  for (var i = 0; i < b; i++) {
                     var li = document.createElement('LI');
                     var a = document.createElement('A');
                     a.href = c[i].link;
                     a.innerHTML = c[i].title;
                     a.target = '_blank';
                     li.appendChild(a);
                     o.appendChild(li);
                  }
               }
            };
            var url = 'http://pipes.yahoo.com/kentbrew/digg_getduggbyuser?_render=json&_callback=' + callback + '&s=' + nick;
            $.f.runScript(url, callback);
         },
         getLinkedIn : function(id, nick) {
            var n = $.f.pingLinkedIn.length;
            var p = document.createElement('P');
            var ul = document.createElement('UL');
            ul.rel = nick;
            ul.id = 'linkedin_' + n;
            p.appendChild(document.createTextNode('Current Positions from LinkedIn:'));
            p.appendChild(ul);
            document.getElementById(id).appendChild(p);
            var callback = trueName + '.f.pingLinkedIn[' + n + ']';
            $.f.pingLinkedIn[n] = function(r) {
               var o = document.getElementById('linkedin_' + n);
               delete $.f.pingLinkedIn[n];
               $.f.removeScript(trueName + '.f.pingLinkedIn[' + n + ']');
               if (r.value.items) {
                  var c = r.value.items;
                  var b = c.length;
                  if (b > 5) { b = 5; }
                  for (var i = 0; i < b; i++) {
                     var li = document.createElement('LI');
                     li.innerHTML = c[i].content;
                     o.appendChild(li);
                  }
               }
            };
            var url = 'http://pipes.yahoo.com/kentbrew/linkedin_getcurrent?_render=json&_callback=' + callback + '&s=' + nick;
            $.f.runScript(url, callback);
         },
         getDelicious : function(id, nick) {
            var n = $.f.pingDelicious.length;
            var p = document.createElement('P');
            var ul = document.createElement('UL');
            ul.rel = nick;
            ul.id = 'delicious_' + n;
            p.appendChild(document.createTextNode('Bookmarked on del.icio.us:'));
            p.appendChild(ul);
            document.getElementById(id).appendChild(p);

            var callback = trueName + '.f.pingDelicious[' + n + ']';

            $.f.pingDelicious[n] = function(r) {
               var o = document.getElementById('delicious_' + n);
               delete $.f.pingDelicious[n];
               $.f.removeScript(trueName + '.f.pingDelicious[' + n + ']');
               var b = r.length;
               if (b > 5) { b = 5; }
               for (var i = 0; i < b; i++) {
                  var li = document.createElement('LI');
                  var a = document.createElement('A');
                  a.innerHTML = r[i].d;
                  a.href = r[i].u;
                  a.target = '_blank';
                  li.appendChild(a);
                  li.appendChild(document.createElement('BR'));
                  if (r[i].t) {
                     li.appendChild(document.createTextNode('Tags: '));
                     var z = r[i].t.length;
                     if (z > 5) { z = 5; }
                     for (var j = 0; j < z; j++) {
                        var a = document.createElement('A');
                        a.innerHTML = r[i].t[j];
                        a.href = 'http://del.icio.us/' + o.rel + '/' + r[i].t[j];
                        a.target = '_blank';
                        li.appendChild(a);
                        if (j < z - 1) {
                           li.appendChild(document.createTextNode(', '));
                        }
                     }
                  }
                  o.appendChild(li);
               }
            };
            var url = 'http://del.icio.us/feeds/json/' + nick + '?callback=' + callback;
            $.f.runScript(url, callback);
         },
         getTweet : function(id, nick) {
            var p = document.createElement('P');
            p.id = 'twitterStatus_' + nick;
            p.innerHTML = '';
            document.getElementById(id).appendChild(p);
            var callback = trueName + '.f.pingTweet';
            var url = 'http://twitter.com/statuses/user_timeline/' + nick + '.json?callback=' + callback;
            $.f.runScript(url, 'tweet_' + nick);
         },
         pingTweet : function(r) {
            if (r.error) {
            } else {
               if (r[0]) {
                  var nick = r[0].user.screen_name;
                  if (document.getElementById('twitterStatus_' + nick)) {
                     var t = document.getElementById('twitterStatus_' + nick);
                     var p = document.createElement('P');
                     p.innerHTML = 'Twittering:';
                     t.appendChild(p);
                     var p = document.createElement('P');
                     var tweet = r[0].text;
                     p.innerHTML = tweet;
                     t.appendChild(p);
                  }
               }
            }
            // sometimes fails; if there are no updates, there's no nick, so the script tags stays inline
            $.f.removeScript('tweet_' + nick);
         },
         getFlickr : function(id, nick) {
            var p = document.createElement('P');
            p.id = 'flickrStream_' + nick;
            p.innerHTML = '';
            document.getElementById(id).appendChild(p);
            var callback = trueName + '.f.pingFlickr';
            var url = 'http://api.flickr.com/services/feeds/photos_public.gne?id=' + nick + '&lang=en-us&format=json&jsoncallback=' + callback;
            $.f.runScript(url, callback + '_' + nick);
         },
         pingFlickr : function(r) {
            var nick = r.title.split('from ')[1];
            var nsid = r.items[0].author_id;
            if (document.getElementById('flickrStream_' + nsid)) {
               var p = document.getElementById('flickrStream_' + nsid)
               p.innerHTML = 'Flickr Photos:<br />';
               var max = r.items.length;
               if (max > 7) { max = 7; }
               for (var i = 0; i < max; i++) {
                  var a = document.createElement('A');
                  a.href = r.items[i].link;
                  a.title = r.items[i].title;
                  a.target = '_blank';
                  var img = document.createElement('IMG');
                  img.src = r.items[i].media.m.replace(/m.jpg/, 's.jpg');
                  a.appendChild(img);
                  p.appendChild(a);
               }
               var scriptId = trueName + '.f.pingFlickr_' + nsid;
               $.f.removeScript(scriptId);
            }
         },
         runScript : function(url, id, p) {
            var s = document.createElement('script');
            s.id = id;
            s.type ='text/javascript';
            s.src = url;
            if (!p) {
               p = document.getElementsByTagName('body')[0];
            }
            p.appendChild(s);
         },
         removeScript : function(id) {
            if (document.getElementById(id)) {
               var s = document.getElementById(id);
               s.parentNode.removeChild(s);
            }
         }
      };
   }();
   var init = function() { $.f.init('mbl'); };
   if(typeof window.addEventListener !== 'undefined') {
      window.addEventListener('load', init, false);
   } else if(typeof window.attachEvent !== 'undefined') {
      window.attachEvent('onload', init);
   }
} )();

If you're curious about the coding style, please take a look at Case-Hardened JavaScript. More about implementing nothing-but-net API clients using the SCRIPT tag hack may be found under Presentations, in BBC Search Widget and Wikipedia Search Widget. I do take these presentations on the road; if you're interested in seeing it in person, please hit me up in Contact.

Comments from before Disqus:

Kent Brewster .:. 2008-02-06 16:29:47
Been doing some more upfluffing in preparation for Tuesday; I'm about ready to declare the prototyping over and go try building something more robust.

Got the most recent user thing figured out, thanks to a quick conversation yesterday with Todd and Chris and Ian before Hack Lunch. They've added a global variable to the MyBlogLog tracker, mbl_recent_visitor. If you're signed in to MyBlogLog, you ought to show up at the very bottom of the stack, with "this is you!" next to your screen name.

In other interesting news, YUI now supports the script tag hack, with the new Get utility. I may finally have to break down and give it a try....

Oh, and: it looks like I may be putting on my booth-bunny ears and heading to ETech. Fun fun fun!
Kent Brewster .:. 2008-02-05 16:31:51
Okay, so now there's recursive surfing around reader sites. If a reader is listed as a site author elsewhere on MyBlogLog, you'll see a thumbnail for the site; click it to go see who's been there recently. For more details, click the link in the "Recent Visitors To" headline to visit the MyBlogLog page for the community.
Kent Brewster .:. 2008-02-05 14:50:49
Got YouTube working a moment ago. If all goes well, you should be seeing thumbnailed links to the user's last five favorite movies.

In other interesting news: looks like I'll be speaking on behalf of the MyBlogLog crew at Search SIG: Search & The Social Graph, next Tuesday the 12th at 6:30pm. Details are online at SDForum; it says you should register fast, since these events fill up. (They do.)

Also: the requests for a call to determine the current user's MyBlogLog ID have been relayed to the Powers that Be ... hopefully we'll have an answer soon.

Kent Brewster .:. 2008-02-01 08:15:25
Twitter has been up and down for a couple of days; sorry if this has made the mash-up perform strangely. (Note to self: build in a preliminary probe of each API before tossing out a bunch of queries, and skip 'em if it's not talking.)
Kent Brewster .:. 2008-01-29 13:50:12
Got Upcoming working just now, via the Upcoming_getEvents pipe. The sort order is odd in some cases; this may be due to some cached requests in my updated pipe.
Ian Kennedy .:. 2008-01-28 21:30:59
Kent, this is just great. I love coming back each day just to see what new goodies you've managed to added into the mix. Hitting this page is like walking into a bar and catching up with the latest from old friends. It may be time to change my avatar to Norm Peterson.
Scott Holdren .:. 2008-01-28 21:10:44
This is an awesome js mashup. We've created a PHP class for the MyBlogLog API. It includes caching of API requests, which has been handy since the MyBlogLog server has not been completely reliable over the past few weeks. Feedback and contributions welcome.

You can see it in action on the Raven SEO Blog, where we provide full profile pages promoting each of our community members.
Kent Brewster .:. 2008-01-28 17:31:07
Last few songs scrobbled at Last.fm should now show up, using the LastFM_getRecentTracksByUser pipe.
Kent Brewster .:. 2008-01-28 14:45:23
Got Digg working at lunch. Very frustrating experience; Digg's ListStories endpoint will give you back JSON wrapped in the callback of your choice ... except you can't have any dots or square brackets in the callback.

Since Digg--unlike Twitter--doesn't give you back the user name you were querying, it's impossible to fire off five different queries for five different users and be sure that the results will go into the proper DOM elements ... so I punted, and used Pipes, which will allow proper callbacks. (See the Digg_getDuggByUser pipe for grisly details.) This is also probably easier on Digg, since Pipes caches repeated calls.
Kent Brewster .:. 2008-01-28 11:28:55
Just got the current status from LinkedIn working; if you have 1) a public profile on http://linkedin.com/in/yourname which 2) has your current position(s) listed, you ought to be seeing it here. For this we're using Pipes; see the Get Current LinkedIn Position pipe for details.
Kent Brewster .:. 2008-01-28 10:24:18
Got del.icio.us working this morning. I'm seeing a couple of instances where the Flickr feed isn't coming up, mostly because the user entered the wrong ID into the MyBlogLog services screen. If your Flickr feed isn't coming up, you may need to enter your Flickr screen name again, and check that it's not your Yahoo! login.
Kent Brewster .:. 2008-01-24 09:48:56
Just added a Flickr feed for each user, and removed the "getting feed X" message from Twitter. Some users specified a public Twitter status feed on MyBlogLog and then made it private on Twitter, so what comes back is an error. Naughty, naughty....

Jitendra: if you know a MyBlogLog ID, you can run the mybloglog.yahooapis.com/v1/user API to get details. If you run mybloglog.yahooapis.com/v1/community and ask for only one record, you should (in theory) be looking at your most current visitor ... but I see that's not always true when I compare the last face on my reader roll to the last face on the community API's return.

I think the API will be much more useful when aimed at getting an aggregate sense of the interests of your audience, and not trying to pin down each individual reader.
Jitendra .:. 2008-01-23 13:28:43
This is cool...Its great that sites can access so much more context about the users via their via the APIs...BTW, is there a way to just get the information on the current user like picture etc. without the whole community angle?
Kent Brewster .:. 2008-01-22 23:37:38
Oh, and: we made Mashup of the Day on programmableweb.com, and seem to have been StumbledUpon. Welcome, new friends!
Kent Brewster .:. 2008-01-22 23:36:14
Okay. The endpoint now correctly returns a single-element array when only one tag, service, community, or blog shows up, and if a user has a Flickr ID, it now shows up in the flickr sub-object, like so: "nsid":"12345678@N00", so you don't have to clobber the Flickr API more than is absolutely necessary. I'm going to see if I can get a few thumbnails to show up next.
Kent Brewster .:. 2008-01-22 20:36:19
Joe: my spies tell me you will be online Soon. :)
Joe Lazarus .:. 2008-01-21 20:53:40
Wow Kent, that's really interesting and exactly what I was getting at... aggregating bookmarks, music interests, etc from the various communities that congregate around a particular site's MyBlogLog. It's sort of like a decentralized "groups" feature for the web. Awesome stuff. I'm in line for the API - can't wait to check it out first hand.
Kent Brewster .:. 2008-01-21 19:02:09
Welcome, Joe. As it sits right now the API provides information for any site, so yes, I could just as easily be looking at the TechCrunch community. (This is true with the existing widget, by the way; anybody can pull anybody else's reader roll.)

Where this starts to get really fun is when we look at second-order and inter-community effects. What are TechCrunch readers bookmarking on del.icio.us? What are those Boing Boing hipsters listening to on Last.fm? When we look at the tags our readers have hung on themselves and each other, what do we see? Who ARE these guys, anyway?

I'm nodding in agreement with Marshall Kirkpatrick's post on ReadWriteWeb right now: "There may be little reason to use APML [Attention Profile Markup Language] if a website can offer personalized content based on a user's tags in Del.icio.us, Flickr, YouTube, etc. all via one easy to use service, MyBlogLog. It's not open and it's not as democratic as a distributed, portable, standards based approach would be - but it's also for better baked and will soon be ready to use."
Joe Lazarus .:. 2008-01-21 14:21:36
I'm looking forward to getting access to the beta. Out of curiosity, does the API provide the information above for any website with MyBlogLog or can you only access the information for visitors to your site (kentbrewster.com in your case)? For example, can you as a MyBlogLog developer generate a list of visitors to Techcrunch along with their tags and list of social sites?
Kent Brewster .:. 2008-01-17 11:02:23
Chris says the API will be updated in the next push to give single-element array returns and not objects for collections that have only one element.
Manny .:. 2008-01-17 09:53:19
Thats pretty cool!

"The most recent visitor might not be you if you just got here and have not seen anything else on the site; I can't imagine the API could possibly be that fast. (I'm willing to be pleasantly surprised, though.)"

On my screen I am actually the first visitor, the API is pretty snappy ;)
Kent Brewster .:. 2008-01-17 09:41:17
Just added Twitter status.
Kent Brewster .:. 2008-01-17 08:49:39
Micah: fixed, thanks! Also added eBay, which I left out.

Found something I don't understand this morning. If a user has exactly one tag or service, the result is an object:

{"tags":{"tag":{"name":"foo"}}}

Otherwise it's an array:

{"tags":{"tag":[{"name":"foo"},{"name":"bar"}]}}

Since my script is looking for an array, users with exactly one tag or service see nothing. I've alerted the Proper Authorities; sorry for any confusion.
Micah .:. 2008-01-17 01:43:17
Kent! Great work as always, man.

Just a heads up: looks like there's a typo in the code right now... pownce is being spelled "pounce" in the generated URL. Didn't scan over them all, but that one popped out.
Kent Brewster .:. 2008-01-16 21:43:48
Thanks, Todd. Really nice work from the team ... can't wait to see what everybody else comes up with!
Todd Sampson .:. 2008-01-16 18:06:49
Wow! You rock Kent. I can't believe you already got a MyBlogLog API mashup out into the wild. It makes me love you even more then when you did the first de.licio.us mashup as our welcome to Yahoo!

Thanks man!

Copyright Kent Brewster 1987-2014 .:. FAQ .:. RSS .:. Contact