Google Gadgets are fragments of HTML wrapped in custom Google XML tags. You can include JavaScript in the HTML, and most gadgets are mostly JavaScript. Each gadget has a ModulePrefs tag (one of Google's custom XML tags) that includes its title, description, and author information. Another custom tag called UserPref can save a user's individual settings.
Here is a simple "Hello, World" example, that replaces the word "World" with the user's name if it has been entered into the gadget's settings dialog box:
<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs title="hello world example" />
<UserPref name="userName" display_name="Your Name" default_value="world" />
<Content type="html"><![CDATA[
Hello,
<script>
var thePrefs = new gadgets.Prefs();
var userName = thePrefs.getBool("userName");
document.write(userName);
</script>
]]></Content>
</Module>
A user can enter their name through the settings dialog box. The link to the dialog box ("Edit Settings") is created automatically by iGoogle when it detects that a UserPref tag is present.
YouTube videos can be played in a Google Gadget by using the YouTube player itself. It's easy to generate the HTML to embed the standard YouTube player from any YouTube page. But if you'd like your player to have a different set of controls from YouTube's player you will need to build a custom Flash video player.
Playing a video from YouTube introduces two challenges for a custom Flash video player:
Here's how to work around these two issues.
The URL to a YouTube video's underlying video file changes hourly. This is to prevent YouTube from being used as a simple file storage server. Google owns YouTube and makes the following technique available for Google Gadget developers to reliably obtain a URL to a YouTube video.
In a gadget's JavaScript, the token below can be used in place of the FLV's URL. The iGoogle container will replace the token with a valid URL at run time. The token's name is __YOUTUBE_VIDEO_URL(videoID)__, where videoID is the YouTube's ID of your uploaded video. You can see this ID in the page's URL when you play a video on YouTube.com.
For example, here is a YouTube video page's URL and the video's corresponding ID:
Video URL: http://www.youtube.com/watch?v=3HrSN7176XI
Video ID:
3HrSN7176XI
And here is the JavaScript that uses the token and ID to set a gadget's variable to this YouTube video's URL:
var YouTubeURL = '__YOUTUBE_VIDEO_URL(3HrSN7176XI)__';
As we have just seen, YouTube video URLs include a query string as a security mechanism. The FLVPlayback component in Flash, which is typically used to play video in a Flash application, assumes that Flash video files end in extensions such as ".flv" and do not contain query strings. URLs containing query strings are assumed to point to XML playlists. As a result, without modification the FLVPlayback component will think that a YouTube dynamic URL points to an XML playlist rather than an FLV file, and will try to parse the FLV file as XML. This will cause a Flash runtime error.
To update the FLVPlayback component to properly accept YouTube URLs as video files you must modify its source code. Download and place the latest Adobe source code for FLVPlayback into your project. When you download FLVPlayback into your project, your directory structure will typically look like this:

After downloading FLVPlayback, you will need to update the part of it that manages its network connections. Open NCManager.as and make the following change to the "connectToURL" function (line 665 in the file as of February 2010):
Change
if ( name.indexOf("?") < 0 &&
to
if ( name.indexOf(".flv") > 0 &&
Below is an example of the new NCManager.as class, with this change having been made. The 2 changed lines are highlighted in yellow.

There are many other ways to update the FLVPlayback component to work with YouTube URLs, but this is one of the fastest. NCManager is changed from thinking that any URL containing a question mark is an XML file, to thinking that any URL including the ".flv" extension anywhere within it is an FLV file. Now add a dummy name-value pair to the end of the YouTube URL to include the extension. For example, the following JavaScript creates a variable for a YouTube FLV's URL, together with its dummy name-value pair so that it still ends in the ".FLV" extension:
var YouTubeURL = '__YOUTUBE_VIDEO_URL(3HrSN7176XI)__';
YouTubeURL += '&dummy=1.flv';
You must now tell the your Flash application to use this customized version of NCManager.as. Add the following lines to your FLA's ActionScript just before you create an FLVPlayback component:
Here is the change in my example FLA's ActionScript, highlighted in yellow. (The package name is different from the lines above as I saved the FLVPlayback component in a directory called "fl" rather than "flash".)

After making this change your Flash video player will be able to play back files from YouTube.
Google provides the embedFlash() helper function to embed a Flash file into a gadget. It works similarly to SWFObject, and automatically caches your SWF on Google's servers to improve performance. It appears that previous version of iGoogle offered the embedCachedFlash() function to embed a cached copy of your SWF, but this function is no longer necessary or available as caching is now always enabled.
One thing to watch out for in the embedFlash() function is that it cannot pass parameters from the gadget's html to the SWF via the FlashVars variable. To work around this, pass them as name-value pairs on the URL to the SWF itself.
Just as your gadget's videos can be served by YouTube, your gadget's images can be hosted by Google Sites, so that your web server will not need to handle your gadget's image requests. To do this, create a web page on Google Sites, and place images that you wish to use in your gadget into the page. You can use the URL to these images on your Google Site page directly in your Google Gadget as well. For example, this image comes from this web page on Google Sites.
The Flash source code for the custom YouTube video player example can be downloaded here. Its ActionScript Code follows on page 2 of this article. The gadget built with it is viewable on iGoogle, and its source code is on page 3.
See the code below....
// main flash action script file
import fl.video.*;
import flash.display.Sprite;
stop();
debugText.visible = false;
log("Real Fireplace Video Player v0.1");
// switch to a custom ncmanager
var _forceNCManager:fl.video.NCManager;
fl.video.VideoPlayer.iNCManagerClass = fl.video.NCManager;
// use videoplayer instead of an flvplayback component (we have no controls so don't need it)
var theMovie:VideoPlayer;
theMovie = new VideoPlayer();
theMovie.height = 240;
theMovie.width = 328;
theMovie.x = 0;
theMovie.y = y;
addChild(theMovie);
// get parameters from flash vars
var theParameters:Object = LoaderInfo(this.root.loaderInfo).parameters;
var playMusic:Boolean = (theParameters["playMusic"] == "true");
var musicURL:String = theParameters["musicURL"];
var clickURL:String = theParameters["clickURL"];
var movieURL:String = theParameters["movieURL"];
// output parameters to debug log
var theName:String;
var theValue:String;
var theParams:Object = LoaderInfo(this.root.loaderInfo).parameters;
for (theName in theParams)
{
theValue = String(theParams[theName]);
log("Received "+theName+"="+theValue);
}
// parameter validation
if ( ( (musicURL == null) || (musicURL.length < 1) ) && (playMusic) )
{
musicURL = "With_The_Sea_low.mp3";
log("musicURL not passed; using default");
}
if ( (clickURL == null) || (clickURL.length < 1) )
{
clickURL = "http://www.amazon.com/Real-Fireplace-Beau-Blazer/dp/B001S2Q5QW";
log("clickURL not passed; using default");
}
if ( (movieURL == null) || (movieURL.length < 1) )
{
movieURL = "realsmallfireplace.f4v";
log("movieURL not passed; using default");
}
log("Validated playMusic:"+playMusic+"; musicURL:"+musicURL+"; clickURL:"+clickURL+"; movieURL:"+movieURL);
// set up click handler
function clickMovie(event:MouseEvent):void
{
log("in clickMovie()");
// show debug text on shift click
if (event.shiftKey)
{
debugText.visible = (!(debugText.visible));
return;
}
// open window on normal click
var theRequest:URLRequest = new URLRequest(clickURL);
try
{
navigateToURL(theRequest, '_blank');
}
catch (e:Error)
{
log("I couldn't open a new browser window for " + clickURL);
}
}
// create a transparent overlay over the video as mouse click events cannot be detected on the movie itself
movieOverlayInstance.alpha = 0;
movieOverlayInstance.addEventListener(MouseEvent.MOUSE_DOWN, clickMovie);
// set up movie loop
function loopMovie(event:Object)
{
theMovie.play();
}
theMovie.autoRewind = true;
theMovie.bufferTime = 0;
theMovie.addEventListener("complete", loopMovie);
// set up movie URL and play
theMovie.play(movieURL);
// set up and play sound loop
var theSound:Sound;
var theChannel:SoundChannel;
if (playMusic)
{
log("About to play music");
theSound = new Sound(new URLRequest(musicURL));
theChannel = theSound.play(0,100); // repeat a hundred times
}
function log(theText:String)
{
// write to console window
trace(theText);
// write to swf text field
if (debugText.text.length < 2)
debugText.text = theText + "; ";
else
debugText.text += theText + "; ";
}
Again, see the code below ...
<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs author="Your name here"
author_link="A link to your web site"
author_email="Your email address"
screenshot="http://sites.google.com/site/fireplacegadget/_/rsrc/1257258844722/home/screenshot_better.jpg" category="lifestyle"
thumbnail="http://sites.google.com/site/fireplacegadget/_/rsrc/1257258844722/home/screenshot_better.jpg" width="300" height="230" scaling="false"
title="Real Fireplace" directory_title="Real Fireplace"
title_url="http://www.amazon.com/Real-Fireplace-Beau-Blazer/dp/B001S2Q5QW"
description="All the sights and sounds of an authentic Boston fireplace, with an optional piano accompaniment. Music by Kevin MacLeod (www.incompetech.com).">
<Require feature="flash" />
</ModulePrefs>
<UserPref name="playMusic" display_name="Piano Music" datatype="bool" default_value="false"/>
<UserPref name="musicURL" display_name="Custom MP3" datatype="string" default_value=""/>
<Content type="html">
<![CDATA[
<div id="flashcontainer"><img src="http://sites.google.com/site/fireplacegadget/_/rsrc/1257258844722/home/screenshot_better.jpg" width="328" height="240" /></div>
<script language="JavaScript" type="text/javascript">
// Create the link to the FLV files on YouTube
var flvNoPianoShortURL = '__YOUTUBE_VIDEO_URL(EK9h6RJTyr8)__';
var flvPianoLongURL = '__YOUTUBE_VIDEO_URL(hCD0XBRAJp0)__';
flvNoPianoShortURL += '&dummy=1.flv';
flvPianoLongURL += '&dummy=1.flv';
// parameters from igoogle
var thePrefs = new gadgets.Prefs();
var playMusic = thePrefs.getBool("playMusic");
var musicURL = thePrefs.getString("musicURL");
// default parameters
var theSWF = "http://www.haik.org/fireplace/gadget/realfireplace.swf";
var theF4V = "";
var theMP3 = "";
var theLink = "http://www.amazon.com/Real-Fireplace-Beau-Blazer/dp/B001S2Q5QW";
// choose URLs for video and audio depending on parameters
var useYouTubeForPiano = true;
theF4V = flvNoPianoShortURL;
if (playMusic)
{
if (useYouTubeForPiano)
{
// if no mp3 url, let the video handle the music
if (musicURL == "")
{
playMusic = false;
theF4V = flvPianoLongURL;
}
}
}
playMusic = (playMusic) ? "true" : "false";
// construct flashvars string
var theFlashvars = "";
function htmlEncode(theString)
{
return escape(theString);
}
function addToFlashvars(theName, theValue)
{
var tempString = "";
var tempSeperator = "";
if (theFlashvars.length > 1) tempSeperator = "&";
tempString = tempSeperator + theName + "=" + htmlEncode(theValue);
theFlashvars += tempString;
}
addToFlashvars("movieURL", theF4V);
addToFlashvars("clickURL", theLink);
addToFlashvars("musicURL", musicURL);
addToFlashvars("playMusic", playMusic);
// hack to work around iGoogle bug with not passing flashvars via object
theSWF = theSWF + "?" + theFlashvars;
// embed the flash swf
var success = gadgets.flash.embedFlash(theSWF, "flashcontainer", {wmode: "window", width:328, height: 240, flashvars: theFlashvars});
log(theFlashvars);
// or not
// if (!success) document.getElementById("flashcontainer").innerHTML = "Please <a href="http://get.adobe.com/flashplayer/">upgrade</a> Flash";
</script>
]]>
</Content>
</Module>