Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

A Gadget for Browsing the Astronomy Picture of the Day

4.32/5 (35 votes)
29 Jan 20079 min read 2   1.1K  
This article shows a Vista Sidebar gadget that you can use to browse the APOD site and view previews of each day's picture.

Contents

Introduction

Ever since I was a wee lad, I've been interested in astronomy. I've also been a long-time reader of the Astronomy Picture of the Day site (APOD), which has hundreds of interesting and informative pages about various subjects in astronomy. (To see the full archive going back to June 1995, visit the index page.) However, APOD doesn't have an RSS feed, and the index page is text-only, so it isn't easy to browse through APOD to find an interesting picture. That's where the gadget comes in! The sidebar gadget presented in this article lets you easily browse through APOD pages, and shows a thumbnail of each day's picture.

Installing and Using the Gadget

When you download the source code from the link at the top of the article, you'll see the APODViewer.gadget file in the root of the zip file. Double-click this file and click Install at the prompt to install the gadget. This will automatically add the APOD gadget to the Sidebar, however there is one manual step you need to do.

The gadget installation procedure cannot register DLLs. The APOD viewer uses an ActiveX control in a DLL, so the gadget won't work until the DLL is registered. Follow these steps to register the DLL:

  1. Remove the APOD Viewer gadget from the Sidebar so it gets unloaded.
  2. Open an elevated command prompt.
  3. Navigate to this directory: %USERPROFILE%\AppData\Local\Microsoft\Windows Sidebar\Gadgets\APODViewer.gadget\bin
  4. Run the command regsvr32 apodhelper.dll to register the DLL.

Once the DLL is registered, the gadget will be fully functional. You can add it back to the Sidebar using the Add Gadgets dialog. In this screen shot, the APOD gadget is in the top-left:

Image 1

The gadget will then run and show the APOD page for the current date. Here is the gadget showing the APOD picture for January 29:

Image 2

The four links at the top of the window change the APOD page. The left-arrow and right-arrow buttons move one day backward and forward, respectively. Click the Today link to return to the APOD page for the current date, and click Random to jump to a random APOD page. Clicking the date below the links brings up a date picker, where you can jump to any date between 1995 and the present:

Image 3

A new feature for version 1.1 is the search field. You can enter keywords in the edit box, and click the OK button to search the APOD site for those words. When you click OK, the flyout window closes and the gadget opens a new browser window that shows the search results.

The bottom part of the gadget shows the title of the APOD page, along with a thumbnail of that day's picture. Click the title to open the APOD page in a new browser window, and click the thumbnail to jump directly to the full-sized picture.

If you browse to a date for which there is no APOD, the gadget will display an error message saying that no APOD page is available.

Another new feature in version 1.1 is a slide show mode, where the gadget changes to a random APOD page every so often. To turn on slide show mode, click the options button next to the gadget window (the one that looks like a little wrench) to open the options dialog:

Image 4

Check the View random APOD pages box to enable slide show mode. You can also change the interval at which the picture changes; the choices range from 30 seconds to 5 minutes.

How the Gadget Works

Initialization

Since the APOD site doesn't have an RSS feed, the gadget has to scrape the web pages and extract the information that it's interested in. Since I'm more proficient in C++ than JavaScript, much of the interesting work is done in C++ and packaged in an ActiveX control. The ActiveX control is initialized in the gadget_init() function in APODViewer.js, which is called when the gadget is loaded:

JavaScript
var g_helper;
 
function gadget_init()
{
  // Create our helper AX object.
  g_helper = new ActiveXObject("MDunn.APODViewer.Helper");
 
  if ( g_helper )
    {
    // Tell it what dir it can create files in,
    // and start off with today's APOD.
    g_helper.SetGadgetPath ( System.Gadget.path );    
    OnTodayButton();
    }
}

As one of the initialization steps, gadget_init() tells the ActiveX object what directory it can create temporary files in by passing the predefined variable System.Gadget.path to the object's SetGadgetPath() method.

Getting APOD Info

When you change the date in the gadget, the gadget tells the ActiveX object what the new date is, then calls the object's GetApodInfo() method. For example, clicking the Today button runs this script:

JavaScript
function OnTodayButton()
{
  if ( g_helper )
    {
    g_helper.GoToToday();
    UpdateApodInfo();
    }
}
 
function UpdateApodInfo()
{
  // Update the date display: eg 1/17/2007
  datepicker.innerText = g_helper.CurrDateString;
 
  // Call the AX object to read the APOD page.
  // Error-handling is not shown here.
  if ( g_helper.GetApodInfo() )
    {
    apodtitle.href = g_helper.ApodPageURL;
    apodtitle.innerText = g_helper.ApodPageTitle;
    apodimg.src = g_helper.SmallImgURL;
    apodimglink.href = g_helper.LargeImgURL;
    }
}

GetApodInfo() is responsible for downloading the APOD web page and caching the data that will be shown in the gadget. It begins by instantiating an HTML parser object and downloading the APOD page for the new date. The HTML is fed into the parser, and then the code iterates through all the links in the page. We're interested in the thumbnail, which is the first <a> tag that has a child <img> tag. If such a link is found, the code saves the href of the <a> tag (the URL to the full-size picture), and the src of the <img> tag (the smaller version of the picture). If those URLs are found, the code then reads the <title> from the HTML, which is shown in the gadget as the caption above the thumbnail.

If GetApodInfo() succeeds, the gadget reads the URLs and page title from properties exposed by the ActiveX object. For example, the LargeImgURL property is the URL to the full-size picture. These strings are assigned to the corresponding HTML elements in the gadget UI.

Technical Notes

The gadget relies on two details of the APOD site, both of which have been consistent over the years (and hopefully will remain that way!):

  1. The URL for a given date must be: http://antwrp.gsfc.nasa.gov/apod/apYYMMDD.html.
  2. The first link in an APOD page that has an <img> child tag must be the link to the full-size picture, and the child <img> must be the thumbnail.

Files in the Gadget Directory

If you browse to the APODViewer.gadget directory, you'll see all the files there unpacked from the original .gadget file. This section lists the contents of each directory, so you'll know what files are where if you want to look at the inner workings of the gadget.

  • root directory
    • APODViewer.js: Script that controls the main gadget UI
    • flyout.js: Script that controls the flyout page
    • options.js: Script that controls the options dialog
    • APODViewer.css: CSS file used by the main gadget UI
  • bin directory
    • APODHelper.dll: The ActiveX control used by the gadget
  • en-US directory
    • gadget.xml: This XML file describes the gadget, along with other info like the version number
    • APODViewer.html: The web page for the main gadget UI
    • flyout.html: The web page for the flyout
    • options.html: The web page for the options dialog
    • strings.js: This script file contains localizable strings
  • images directory
    • Various icons and images used in the gadget's web pages and the Add Gadgets dialog

You might notice that the en-US directory is never referenced in the other files. This directory contains localizable resources, and Vista automatically searches it when looking for files. For example, this section of gadget.xml lists the web page for the main UI:

XML
<gadget>
  ...
  <hosts>
    <host name="sidebar">
      <base type="HTML" apiVersion="1.0.0" src="APODViewer.html" />
      <permissions>Full</permissions>
      <platform minPlatformVersion="1.0" />
    </host>
  </hosts>
</gadget>

The src attribute in the <base> tag doesn't have a directory name, so Vista first looks in the gadget's root directory. Since APODViewer.html is not there, Vista then looks in en-US, and finds the file there. To localize the gadget into a new language, all that's required is to add a new language directory alongside en-US, and put the translated files in that directory.

Building and Packaging the Gadget

A .gadget file can be either a ZIP or a CAB file that contains all the files for the gadget. I chose to use a CAB for the demo download, since CABs can be digitally signed. This section lists the steps necessary to package the gadget into a CAB and sign it.

  1. Set up all the gadget files in the APODViewer.gadget directory.
  2. Build the DLL that contains the ActiveX control. Copy the DLL into the APODViewer.gadget\bin directory and register it there.
  3. Open a command prompt and navigate to the APODViewer.gadget directory.
  4. Run cabarc -p -r -s 6144 n APODViewer.cab *.* (The -s switch reserves space in the CAB for a digital signature, you should omit this switch if you don't plan on signing the CAB.)
  5. If you have a signing certificate, sign the CAB file.
  6. Rename the CAB to have a .gadget extension.

Then distribute the .gadget file! If you sign the file, the prompt will show the gadget name and the name of the company as listed in your signing certificate. The gadget file in the demo download is signed with my company's certificate, so our name appears in the prompt:

Image 5

References

See the resources section in the Gadgets Competition page at CodeProject.

"A Console Application HTML Parser Using Microsoft's XML Technologies" by Jeffrey Walton.

Copyright and License

This article is copyrighted material, ©2007 by Michael Dunn. I realize this isn't going to stop people from copying it all around the 'net, but I have to say it anyway. If you are interested in doing a translation of this article, please email me to let me know. I don't foresee denying anyone permission to do a translation, I would just like to be aware of the translation so I can post a link to it here.

The demo code that accompanies this article is released to the public domain. I release it this way so that the code can benefit everyone. (I don't make the article itself public domain because having the article available only on CodeProject helps both my own visibility and the CodeProject site.) If you use the demo code in your own application, an email letting me know would be appreciated (just to satisfy my curiosity about whether folks are benefitting from my code) but is not required. Attribution in your own source code is also appreciated but not required.

Revision History

January 17, 2007: Article first published.
January 29, 2007: Version 1.1 released, added search and random page viewing features.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here