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:
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.
// 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.