TruveoCast: Building a Mac OS X Dashboard Widget to Share Your Truveo Video Favorites

By John Fronckowiak
December 13, 2007

Anything that comes along that gives people a new way to have social contact, they adopt it.Trip Hawkins

AOL's Truveo is a one-stop site for searching and browsing the millions of videos available on the Internet. Truveo Video Search provides a rich searching mechanism, and an associated API that give users the ability to find the content they need. In addition, Truveo users can create a list of their favorite videos, and if they choose to make the favorites list public, other users can search it by using the user: search modifier.

The TruveoCast widget I discuss in this article provides a mechanism to instantly browse the video favorites of a specified user (User1). Another Truveo user (User2) can browse thumbnail images of User1's favorites; a description of the video is displayed beneath the TruveoCast television image. When User2 clicks the video image displayed inside the TruveoCast television, the video opens in a new window of the web browser and User2 can watch the entire video.

Using TruveoCast

The TruveoCast widget, shown in Figures 1 and 2, uses a television set metaphor for browsing the saved favorites of a Truveo user (User1). Another Truveo user (User2) types User1's ID in the user ID search box. When User2 presses ENTER or clicks the Search for Favorites button, a query is made to Truveo for User1's favorites. User2 can browse the set of User1's favorites that is returned by using a television channel metaphor. Each favorite video is treated as its own channel. User2 can click the Channel Up and Channel Down buttons to browse or type a number in the Channel Number edit box (not shown in Figure 1—it's displayed after query results are returned) to go directly to a specific channel (one of User1's favorites) in the set.

Tooltips are displayed when User2 moves the cursor over any of the user interface elements. Sound effects are generated when the channel is changed, when a related-users query is initiated, or when an error occurs. User2 can turn sound effects and tooltips on or off on the back of the widget.

As shown in Video 1, when User2 moves the cursor over the thumbnail preview area or the television set itself, the title of the selected video is displayed beneath the television. Figure 3 also demonstrates the related-users query, which returns the list of users who also have the current video saved to their favorites list.

Figure 1. The front of the TruveoCast widget

Figure 2. The back of the TruveoCast widget

Video 1. The TruveoCast widget in action

About Truveo

Truveo.com, shown in Figure 3, is the one-stop destination for searching video resources available all over the Internet, including AOL Music, AOL Video, YouTube, CNN, NBC, Fox News, and much more. You can search, browse, and play videos you find at Truveo. Truveo provides quick access to the Top Ranked, Most Viewed, Highest Rated, and Most Recent videos.

Figure 3. The Truveo UI

Saving Your Favorites

You must be logged in to the Truveo web site to save your favorites. After you have logged in and selected a video, you can save the video to your list of favorites. To do this, in the Snag This Video section beneath the video preview image, click the Save this video to My Favorites link (see Figure 4). After you click the link, a pop-up dialog box will confirm the action, as shown in Figure 5.

Figure 4. Saving a video to your favorites

Figure 5. Saved to Favorites confirmation dialog box

To view the list of videos you've saved, click the See all favorite videos link in the Truveo My Video Center, as shown in Figure 6.

Figure 6. Viewing your favorites on the Truveo web site

Making Your Favorites Public

To enable other users to search your favorites, you must first make your favorites accessible to the public. You can do this in the Truveo My Video Center, shown in Figure 7. In the My Accounts Settings section, for the Would you like others to see your public name and favorites? setting, click Yes, and then click Save Settings.

Figure 7. Making your favorites available to the public

Widget Development Using Dashcode

TruveoCast was developed using Dashcode, a widget-development tool that was released by Apple with its latest operating system, Mac OS X 10.5 Leopard (see Figure 8). Dashcode provides a GUI-based tool for widget development, and combines a code editor with visual layout tools. Dashcode provides the mechanism to run and debug Dashboard widgets outside of the actual Dashboard environment. You can read a brief introduction to Dashcode at the Apple Developer Connection site.

Figure 8. The Dashcode widget development environment

Truveo APIs and the Truveo Developer Center

Let's look at what goes on behind the scenes of the TruveoCast widget. Before you can integrate Truveo APIs into your application, you must create a Video Search API account at the Truveo Developer Center. Truveo supports your application for up to 10,000 queries per day. Agreeing to the terms and conditions provides you with two keys for your application. The first is the Application ID, a unique key that provides access to the Truveo APIs. The second key is the Shared secret, which is required for methods that require user authentication. TruveoCast currently does not implement user authentication. To obtain your API keys, click the My API Account at the Truveo Developer Center, shown in Figure 9. If you haven’t yet logged in to Truveo, you’ll be asked for your user name and password first. After you fill out the web form and agree to the terms and conditions, you'll receive your API key.

Figure 9. Obtain your API key at the Truveo Developer Center

Truveo Video Search Object

Before you can access the Truveo Asynchronous JavaScript and XML (AJAX) API in your web page, you must import the AJAX API JavaScript library. Listing 1 shows how to place the <script> tag in the widget's HTML page.

Listing 1. Adding the Truveo AJAX API JavaScript library

<!-- Include the Truveo Video Search JavaScript Library -->
<script type="text/javascript" src="http://xml.truveo.com/TruveoVideoSearchAPIv3.js"></script>

Truveo access using AJAX is made possible through the TruveoVideoSearch (TVS) object. Before you can access Truveo from your application, you must create the TruveoVideoSearch object by using the Application ID key you previously created at the Truveo Developer Center. As shown in Listing 2, the TruveoVideoSearch object, TVS, is created and initialized when the widget is loaded. After the TruveoVideoSearch object is created, the initialize method is called. The initialize method initializes the current state of the AJAX API.

Before any queries are executed, the TruveoVideoSearch object attributes are initialized. The results attribute is initialized to the constant MAX_RESULTS (which is initialized to 50, the maximum value permitted). This constant determines the maximum number of results that are returned when a query is executed in the widget.

Finally, it's important to understand that the TruveoVideoSearch object processes asynchronously; that is, when a user makes a request to Truveo, the request is processed in the background, and only when the results become available is the application notified. Request completion is signaled through an event. You must specify which application functions will process these events. In TruveoCast, two events are registered for the TruveoVideoSearch object: onerror and onupdate. Events are attached using the attachEvent method of the TruveoVideoSearch object. The TVSError method receives two parameters, errorCode and errorMessage. These are strings that specify information about the error that occurred. The TVSQueryResult method receives one parameter, methodName, a string that contains the name of the method that initiated the query request.

Listing 2. The TruveoCast widget load event

// *****
// Function: load()
// Purpose: Called by HTML body element's onload event when 
//		 the widget is ready to start
//
// Author: Fronckowiak
// *****
function load()
{
    	setupParts();
	
	// check the current preferences version - if not available 
        // or version changed recreate them
	if(loadPref("version") != "0.1") {
		// store the current version
		createPref("version","0.1");
		// save the sounds flag
		createPref("sounds","true");	
		// save the tooltips flag
		createPref("tooltips","true");	
	}
		
    	// create the Truveo Video Search object using the 
        // Application ID created at Truveo.com
    	TVS = new TruveoVideoSearch(MY_API_KEY);

	// initialize the Truveo Video Search object
    	TVS.initialize();

        // set the maximum number of results returned at one time
    	TVS.results = MAX_RESULTS;
	
    	// attach an error handling event handler - called whenever 
        // Truveo Video Search throws an error
    	TVS.attachEvent("onerror", "TVSError(errorCode, errorMessage);");
	
    	// attach an update event handler - called when a query returns results
    	TVS.attachEvent("onupdate", "TVSQueryResult(methodName);");

	// display tooltips based on preference flag
	checkToolTips();
}
Building a User's Favorites Query

To obtain the favorites of a user, the getVideos method of the TruveoVideoSearch object is called. The getVideos method accepts a single parameter's string that contains the query and any filter or modifier directives. When an ID is typed in the user ID search box, or if the Search button on the television is clicked, the userSearch function in Listing 3 is called. If the user ID box isn't empty, the indices, which track the current video that is being displayed, are reset to 0, and the getVideos method is called. Truveo supports a number of search modifiers that can be used in the search string passed to getVideos. These modifiers are detailed on the Truveo site at http://developer.truveo.com/UsingModifiers.php. TruveoCast relies on the user: modifier. You can use the user: modifier to find all videos available in a specific user's favorite videos list. It's important to note that this modifier will return results only for users who have chosen to make their favorites list publicly viewable by other users.

Listing 3. The userSearch function

// *****
// Function: userSearch 
// Purpose: Called when a user name is typed in the user search box, or 
//		 when the userSearch button is clicked.
//		 Reset all indices, and perform a call the Truveo Video Search 
//		 object getVideos query. If the user search box is empty - sound 
//		 an alarm.
//				event - When ENTER is pressed in the user search box or 
//					  the userSearch button is clicked
//
// Author: Fronckowiak
// *****
function userSearch(event) 
{
	// is the user search box blank?
    	if(trim($('user').value) != "") {
		// reset the video search indices
		currentAbsIndex = 0;
		currentRelIndex = 0;
		currentPageNum = 0;
		// run the getVideos query
		TVS.getVideos('user:'+$('user').value);
	} else {
		// user name is blank - sound alarm!
		PlaySound('shortalarm');
	}
}
Processing User-Favorites Query Results

When the TruveoVideoSearch object was initialized in the load function, the attachEvent method was called to attach a function to the onupdate event of the TruveoVideoSearch object. The update event is called whenever functions such as getVideos asynchronously return their results. TruveoCast has attached the TVSQueryResult function to the onupdate event. Shown in Listing 4, the TVSQueryResult function takes a single parameter, methodName. The parameter methodName is the name of the TruveoVideoSearch method that was called to obtain results. In TruveoCast, three query methods are used: getVideos, which is used to retrieve the list of the user's favorites; getRelatedUsers, used to retrieve other users that have the same video in their favorites; and goToPage, which is used to page though the set of returned video favorites. As shown in Figure 10, in any video list query, only MAX_RESULTS (which is set to the maximum of 50) videos are returned at a time, even though a user might have more than 50 videos in their favorites list. The goToPage method is used to page through the result set. TruveoCast uses two indices to determine the current video being displayed: currentAbsIndex tracks the index of a video in the complete set of all favorites, and currentRelIndex tracks the relative index of the video in the current page that has been retrieved.

Listing 4. The TVSQueryResult function

// *****
// Function: TVSQueryResult
// Purpose: Called by the Truveo Video Service to return the results of a query
//				methodName - The name of the method which was called to 
//						  return the results this will be either 
//						  getVideos (when a set of videos is requested)
//						  or goToPage (when more videos are requested) or
//						  getRelatedUsers (when the set users related to 
//						  the current video is requested)
//
// Author: Fronckowiak
// *****
function TVSQueryResult(methodName) {
	// is this a result of a getVideos or goToPage call?
	if(methodName == "getVideos") {
		// determine the total number of videos in the favorites set
		maxChannels = parseInt(TVS.VideoSet.totalResultsAvailable);
		// were any videos returned?
		if(maxChannels != 0) {
			// add a tooltip to the channel number edit box with the range 
                        // of allowable channels
			new Tip(channelNumber, "Enter Channel Number 1-"+maxChannels,{delay: 
2.0, offset: {x:0, y:3}, hook:{target:'bottomRight', tip:'topRight'}}); // display the video thumbnail for the first favorite (channel 0) showCurrentVideo(); } else { // set the error in title flag errorInTitle = true; // show the error in place of the title... $("titleText").innerText = "User Not Found Or Favorites Not Available -
Try Again!"; // make the title div visible... Effect.Appear('title'); } // is this result of a goToPage call? } else if(methodName == "goToPage") { // display the thumbnail of the next video in this set showCurrentVideo(); // is this a result of a getRelatedUsers call? } else if(methodName == "getRelatedUsers") { // fill the related users pop-up menu with the other users that have // this video listed as a favorite fillRelatedUsers(); } }

Figure 10. TruveoCast indexing of the video search result set

Using JavaScript Libraries

TruveoCast uses the Prototype, Script.aculo.us, and Prototip JavaScript libraries extensively . I have introduced the Prototype library in my blog at http://dev.aol.com/blog/johnfronck/PrototypePower, the Script.aculo.us library in my blog at http://dev.aol.com/blog/johnfronck/ScriptaculousAnimation, and Prototip in my blog at http://dev.aol.com/blog/johnfronck/PrototipTooltips. If the TruveoCast user ID search returns any favorites, the showCurrentVideo method, shown in Listing 5, is called. The showCurrentVideo method determines whether the video to display is in the current page or a new page must be obtained. The Script.aculo.us Effect methods are used to fade out the relatedUsers information, and also to create the dynamic flickering, through the Pulsate method, when a new video thumbnail is displayed. The title of the video is saved in the titleText div that appears when the user moves the cursor over the thumbnail or the television image.

Listing 5. The showCurrentVideo method

// *****
// Function: showCurrentVideo 
// Purpose: This will display the current video thumbnail based on the 
//		 current index.
//
// Author: Fronckowiak
// *****
function showCurrentVideo() {
	// is the current index beyond the beginning?
    	if(currentAbsIndex < 0) {
		// reset to the beginning of the list
		currentAbsIndex = 0;
		currentRelIndex = 0;
		// sound the alarms!
		PlaySound('shortalarm');
		return;
	// is the current index beyond the last?
	} else if(currentAbsIndex >= maxChannels) {
		// reset the index to the last video
		currentAbsIndex = maxChannels - 1;
		// reset the current relative index
		currentRelIndex = currentAbsIndex % MAX_RESULTS;
		// sound the alarms!
		PlaySound('shortalarm');
		return;
	}
	
	// if the related user's information is visible - make them fade away...
	Effect.Fade('relatedUsersLabel');
	Effect.Fade('relatedUsers');
	
	// determine the page number we need to go to the rounding down 
        // randomIndex / maxresults (number of items per page)
  	var pageNum = Math.floor(currentAbsIndex / MAX_RESULTS);	
	if(pageNum != currentPageNum) {
		currentPageNum = pageNum;
		// get the next virtual page of videos
		TVS.goToPage(currentPageNum);
	}

	// set the relative index in this page set
	currentRelIndex = currentAbsIndex % MAX_RESULTS;	
	
	// Play channel change sound
	PlaySound("channelchange");
	
	// get the URL of the video from the video set
    	videoURL = TVS.VideoSet.Video[currentRelIndex].videoUrl;

	// display the thumbnail in the preview div
    	$("thumbNail").innerHTML = "<img src='" + TVS.VideoSet.Video[currentRelIndex].
thumbnailUrl + "' height='116px' width='152px' />"; // make the thumbnail flicker like an old TV set Effect.Pulsate('thumbNail', {duration: 0.5}); errorInTitle = false; // store the title as the text of the title div $("titleText").innerText = TVS.VideoSet.Video[currentRelIndex].title; // update the channel number and make it visible $("channelID").innerText = currentAbsIndex + 1; $("channelNumber").value = currentAbsIndex + 1; // make the channel ID in the upper right of the video area appear // and then fade away after 4 seconds Effect.Appear('channelID'); Effect.Fade('channelID',{delay: 4.0}); // display the title information Effect.Appear('channelNumber'); Effect.Appear('title'); }
Building A Related Users Query

A key feature of TruveoCast is the ability to explore other users who also have a selected video saved to their favorites. This is a great way to find other users who have similar interests! When User2 clicks the Related Users button on the television set that displays one of User1's favorites, the clickRelatedUsers function, shown in Listing 6, is called. As long as a video thumbnail is displayed, the TruveoVideoSearch object's getRelatedUsers method is called. Once again, search modifiers are used. In this case, the id: modifier is used to return the results for the specified user ID. The favorites user ID of the currently displayed thumbnail image is retrieved and used to create the query string. This string will return a result set that contains all of the users that also have this video listed in their favorites.

Listing 6. The clickRelatedUsers function

// *****
// Function: clickRelatedUsers 
// Purpose: Create a query using the ID of the currently selected video – 
//		 run a getRelatedUsers search. If a video has not been selected – 
//		 display an error message
//				event - The relatedUsers button click event
//
// Author: Fronckowiak
// *****
function clickRelatedUsers(event)
{
	var e = null;
	
	try {
		// get the ID of the current video
		var query = 'id:' + TVS.VideoSet.Video[currentRelIndex].id;
		// play search sound
		PlaySound('search');
		// run a query on with the specified video ID and get the 
                // related users
		TVS.getRelatedUsers(query);
	} catch (e) {
		// we'll wind up here if a video hasn't been selected yet
		// sounds the alarms!
		PlaySound('shortalarm');
		errorInTitle = true;
		// show the error in place of the title...
		$("titleText").innerText = "You Must First Selected A Video";
		// make the title div visible...
		Effect.Appear('title');
	}
}
Processing the Related Users Query Results

As discussed earlier, when the getRelatedUsers query returns results, the TVSQueryResult function, shown earlier in Listing 4, is called. If the methodName is getRelatedUsers the fillRelatedUsers function, shown in Listing 7, is called. The UserSet object is filled with all users related to the current video. This information is used to fill the relatedUsers pop-up menu, which lists each related user's ID. The releatedUsersLabel and relatedUsers pop-up menu is displayed. When User2 selects a user ID (User3) from the relatedUsers menu, a video search is triggered, and User2 can begin to explore User3's list of favorites.

Listing 7. The fillRelatedUsers function

// *****
// Function: fillRelatedUsers 
// Purpose: When the query is made to return the users that also have the current 
//		 video listed as a favorite is returned the results are in the 
//		 TVS.UserSet. TVS.userSet.totalResultsReturned contains the total 
//		 number of users returned. Add each user to the pop-up menu by 
//		 creating and adding an option element for each user in the UserSet.
//		 Make the relatedUsers label and pop-up menu visible.
//			event - relatedUsersButton div click
//
// Author: Fronckowiak
// *****
function fillRelatedUsers(event)
{
	var i = 0;

	// make the title div fade away
	Effect.Fade('title');

	// delete all items in the relatedUsers pop-up menu
	$('relatedUsers').options.length = 0;

	// loop through the UserSet - it contains the Truveo user IDs of all 
        // users that have the current video saved as a favorite
	for(i = 0; i < TVS.UserSet.totalResultsReturned; i++) {
		// create an option element to add 
		var userOption = document.createElement("OPTION");
		// set the option element text and value attributes
		userOption.text = TVS.UserSet.User[i].name;
		userOption.value = TVS.UserSet.User[i].name;
		// add the options element to the popup menu
		$('relatedUsers').options.add(userOption);
	}

	// display the relatedUsers pop-up menu and label
	Effect.Appear('relatedUsersLabel');
	Effect.Appear('relatedUsers');
}
Profiling Your Truveo Applications

As noted earlier, to use Truveo in your applications you need to first create an API account, and obtain an Application API key, which must be built into your Truveo-enabled application. After you log in to the Truveo Developer Center using your API account, you can obtain a rich set of reports, including the API Usage Report, the Top Queries Report, and the Channel Redirects Report. I review and dissect these reports in a blog post on the AOL Developer Network at http://dev.aol.com/node/623.

More...

For more about AOL technologies, applying those technologies on the Mac, and much more, please visit my blog on the AOL Developer Network: http://dev.aol.com/node/623.

Resources

Special thanks to Becky Straka of Straka-Digital for essential help with the television design and graphics.

Download

You can download the complete TruveoCast widget at http://widgets.idcc.net/truveocast

Thank you!

Thanks so much for provided links
Bst Rgds,
Michael B.