Home » Labs »

Yahoo Connected TV Widgets

Yahoo Connected TV Widgets

Connected TV`s are the new PINK, so read about how to get started writing code for Television sets.

Note: this tutorial is meant for Debian-powered machines, but anyone can be Debian-powered in VirtualBox.

First Things First: Get the WDK!


It's a .deb file, so all you have to do is double-click. This will install the codebase along with a bunch of TV emulators.

This installer will also create the /devwidgets folder. This is a magical folder as all your widget code will live here. When I say live, I mean it. When you fire up the emulators, these widgets are compiled automagically and uploaded into the virtual TVs.

Now, we chose a twitter client because, let's face it, they're the new "Hello, World!" app. All we need is a means to make some cross-domain GET request and display the results.

So let's get down to business!

To start off, unarchive the Template.widget file from your /usr/local/Konfabulator/TV/Widgets folder to your /devwidgets folder. Rename the newly created Template.widget folder to something more representative, like Twitter.widget. This template widget is great for a scaffold plus this will give us the directory structure straight-up.

Edit the widget.xml file to reflect what we're building. 

  1. <identifier>com.odeon.widgets.tv.twitter</identifier>
  2. <version>0.1</version>
  3. <name>Twitter Client</name>
  4. ...
  5. <image usage="960x540.logo" src="Images/960x540/twitter.png"/>
  6. <image usage="1920x1080.logo" src="Images/1920x1080/twitter.png"/>

Make sure to fill out all the fields in the xml file. I'll tell you why later.
Now take a look at main.TV -- This is the entrance point of your application, and it tells the platform which Javascript files to include.

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <widget>
  3. <script src="Platform/platform.js" />
  4. <script src="Javascript/pickmeup.js" />
  5. </widget>

Now let's execute some code in our included Javascript files, eh?

  1. include("Framework/kontx/1.0.0/src/all.js");
  2. include("Javascript/views/MainView.js");
  3. ...
  4. include('Javascript/app/API.js');
  5. KONtx.application.init({
  7. { id: 'view-Main', viewClass: MainView },
  8. { id: 'view-UserTimeline', viewClass: UserTimeline, data: {timeline: 'user_timeline'} },
  9. ...
  10. ],
  11. defaultViewId: 'view-Main',
  12. settingsViewId: 'view-About'
  13. });

pickmeup.js is our initialization file. As you can see, we're loading the files we require for our widget to run. This includes views and library files.

Also, this is the place where we register our views, or the different screens of our application.

First stop: the main view, defined in MainView.js

We want to keep it simple for now, so it's a simple list of common twitter functions: Your Timeline, Your Mentions and Your Own Tweets. Since all we're doing is listing tweets, we'll create a separate view for this task and we'll just feed it different tweets. Here's some of the code from the UserTimeline view file.

  1. var UserTimeline = new KONtx.Class({
  2. ClassName: 'UserTimelineView',

  3. Extends: KONtx.system.SidebarView,
  4. config: {
  5. tweetsLoadedKey: 'tweets-r-here'
  6. },
  7. initialize: function(){
  8. this.parent();
  9. this.registerMessageCenterListenerCallback(this.messageHandler);
  10. },
  11. ...
  12. });

For the list, we'll be using the built-in Grid widget, which is super-cool to work with.

I also love the logic of this system: you have on function that creates the grid cells and another one to populate them with data when it's available. In our case, we're setting up a text object for the tweet-er, another text object for the tweet and we're also throwing in the user's avatar for good measure. These are all created in the cellCreator function. Then it's just a matter of filling in the data:

  1. cellUpdater: function(cell, dataitem) {
  2. cell.tweetText.data = dataitem.text;
  3. cell.avatar.src = dataitem.user.profile_image_url;
  4. cell.username.data = dataitem.user.name;
  5. }

Another fun thing about the Grid control is the fact that it can do functional decorators. Look at how easy it is to attach a paginator.

  1. this.controls.page_indicator = new KONtx.control.PageIndicator({
  2. threshold: 333,
  3. styles: {'vOffset': this.controls.tweets.height }
  4. }).appendTo(this);

  5. this.controls.tweets.attachAccessories( this.controls.page_indicator );

Ok, let's get the tweets!

  1. $API = (function(){

  2. var _key = 'twitter-upair';

  3. function get(url, callback){
  4. var u = new URL();
  5. u.callback = callback;
  6. u.location = url;

  7. log( " > Twitter API [get] :: " + u.location );

  8. u.fetchAsync( function(u) {
  9. log( " < Twitter API [" + u.response + "] :: " + u.location );
  10. if ( u.response == 200 ) {
  11. KONtx.application.setNetworkRequestFailed(false);
  12. u.callback( u.result );
  13. }
  14. else {
  15. KONtx.application.setNetworkRequestFailed(true);
  16. log('\n%%% Twitter API: bonk! %%% --- http response --->' + u.response + "\nResult:\n" + u.result);
  17. }
  18. } );
  19. }

  20. function credentials(callback){
  21. var upair = currentAppData.get(_key);
  22. if(! upair){
  23. var dialog = new KONtx.dialogs.Login({
  24. title: $_('dialog-login-title'),
  25. message: $_('dialog-login-message'),
  26. callback: function(response){
  27. currentAppData.set(_key, JSON.stringify(response));
  28. credentials(callback);
  29. }
  30. });
  31. dialog.initialize();
  32. dialog.show();
  33. } else {
  34. callback(JSON.parse(upair));
  35. }
  36. }

  37. return {
  38. 'getTweets': function(timeline, since_id){
  39. timeline = timeline || 'user_timeline';
  40. credentials(function(userpass){
  41. get('http://' + userpass.username + ':'
  42. + userpass.password +
  43. '@twitter.com/statuses/' + timeline + '.json' +
  44. ( since_id ? '?since_id=' + since_id : '' ),
  45. function(response){
  46. KONtx.messages.store('tweets-r-here', JSON.parse(response));
  47. })
  48. })
  49. },
  50. key: _key
  51. }
  52. })()

The thing to take away from this code snippet is the use of url.fetchAsync(function(response){...}). The Konfabulator platform enforces the use of asynchronous resource retrieval because the UI would freeze up otherwise.
It's like AJAX, only on steroids.

We need a username and a password in order to use Twitter's API, so how could we get them?

Remember, this widget will be running on a TV set, so text input can be a problem. Luckily, the fine folk at Yahoo! thought about this and they provide us with a super-duper Login Dialog.

All you need to do is invoke it and pass it a callback for when the user completes the text entry. Thumbs up to that bit!

  1. var dialog = new KONtx.dialogs.Login({
  2. title: $_('dialog-login-title'),
  3. message: $_('dialog-login-message'),
  4. callback: function(response){
  5. currentAppData.set(_key, JSON.stringify(response));
  6. credentials(callback);
  7. }
  8. });
  9. dialog.show();

Naturally, we don't want the user to have to enter their username and password for every action, so we need to save them somewhere.

Konfabulator provides an easy way to do this: currentAppData. This is am app-specific persistent dictionary that stores key-value pairs, perfect for what we need. All you need to do is call currentAppData.set('unique-key', 'any string you want!'); to save the information and you can later retrieve it by calling currentAppData.get('unique-key');

So let's fire it up!

From your Application menu, select TV Widgets, then a Simulator of your choosing. My favorite is Vizio, but that's just me. Select Vizio Simulator Update Widgets. This will recreate its data folder and sources, then start a TV inside your OS. (I'm still having a hard time getting over how awesome that is!)

Now, I promised I'd tell you about the widget.xml file and why it's a good idea to be thorough filling it out. Here's why: you can choose to have your About page generated from your widget.xml file via a built-in Konfabulator view, KONtx.views.AboutBox. Cool, eh? :-)

I hope you enjoyed this tutorial. Make sure you play with the source, too!


  1. Allan on Dec 18, 2010 - 20:17 said:

    Hello, thats a cool widget, but I'm having some problem trying to load this widget in the simulator. I've downloaded the source code under the /devwidgets folder, and added the .widget extension. However, the simulator does not seems to be picking this widget up? Hope you could enlighten me on this. Thanks.

  2. Allan on Dec 18, 2010 - 21:17 said:

    Hi, i got it working :). Forgot to put them under contents folder

  3. Ignacio on Jan 03, 2011 - 17:36 said:

    I'm starting with this TV emulator and I've a pair of problems, maybe you could help me.
    First of all when I launch the simulator it responds me that I have not a network connection but it is not true because I can access internet with the browser, and then the Konfabulator window doesn't start.
    If I start KOnfabulator directly at de Vizio directory it start the Konfabulator window but it is permanently black. I've tried to change all monitor resolutions, without changes, continue black.
    I have Virtualbox running an Ubuntu 10.10 VM.

  4. Tom on Jan 09, 2011 - 8:35 said:

    Hi, has anyone tried playing with this source? I couldn't login this app, it says connection unavailable. Anyone able to help? Thanks.

  5. lauzy on Mar 20, 2011 - 20:36 said:

    What does upair means?

  6. jesus on May 20, 2011 - 6:23 said:

    I have a problem. I don't get to load the widget. I put the widget in the directory "admin/TVWidgets/Konfabulator-Lastest/TV/Widgets", Is the correct directory? I did a .zip with the name "twitter.widget" and inside there is a folder with the name "twitter.widget" and inside there is other directory with the name "Contents". I don't know why this doesn't load. Can you help me please?

  7. Chris Harrison on Dec 01, 2011 - 15:37 said:

    Im also getting the "connection unavailable" error,
    The Yahoo documentation is terrible just a list of api methods and classes with no real tutorial on how to get started.

    This is the only one I've found and even it doesn't seem to work!


Leave a Comment :




Page generated in: 0.17s