Archive for June, 2005

The Death of Property Rights

It’s amazing how something so fundamental as property rights can be dissolved so easily, all in the name of “public good”.

Today, the US Supreme Court ruled in favor of Big Business with a 5-4 opinion that granted private developers the power to demolish people’s homes in favor of business parks, malls, and gyms for the purpose of economic development and increased tax revenues.

Any why wouldn’t the government be in favor of increased tax revenues?

The poor souls in New London, CT who are poised to lose their homes (some of which have been in their family’s posession for generations) will be “fairly compensated,” which means that a 80-year-old Victorian will get market value.  This rarely enables the owners to find new adequate housing, because of the hyper-inflated housing costs in the Northeast.  So what’s a person to do?  Chain yourself to your front door.  Gather 400 friends and family to form a solid human wall around your property and prevent the government from taking your home.

It’s clearly up to you to protect what’s yours; when the government fails to uphold the very ideals upon which this country was founded, the responsibility fails squarely upon the shoulders of the citizens.

Seven states allow private business development on seized property:  Connecticut, Kansas, Maryland, Michigan, Minnesota, New York and North Dakota.

It should be noted that New Hampshire and Massachusetts have indicated they probably will find this alarming new power to be unconstitutional.  I URGE you to contact your representatives and senators to outlaw the ability to seize property for private development.

Otherwise… Don’t get too comfortable.  Your home may be next.

Senator Judd Gregg (R)
393 Russell Senate Office Building
Washington, DC 20510-2904
Phone: (202) 224-3324
Official website

Senator John Sununu (R)
111 Russell Senate Office Building
Washington, DC 20510-2903
Phone: (202) 224-2841
Official website

Integrating Winamp With a Website



This took me some time to figure out, and based on the number of posts in online forums, I can tell I am not th eonly person interested in integrating my Winamp playlists with a website.

In case you haven’t noticed, I have added a block on the right-hand side of this website entitled “Now Playing…”.  The contents of this block reflects what is currently on my Winamp media player.  There was a trick to getting that to work properly, but the other trick which has little to do with Winamp, is the display of the CD cover art.

There are several steps to this project:

Step 1: Data has to be sent from Winamp to the website.  In order to do this, I used a plugin called “DoSomething” http://www.oddsock.org/tools/dosomething, which has the capability to export ID3 metadata to files, which can then be sent to the website via FTP.  Once you have the plugin downloaded and installed, you need to configure it.

The first part of configuring the plugin is to create a template that the plugin can write data to.  I chose to use an XML format for my template, which looks like this:



<?xml version="1.0" encoding="iso-8859-1" ?>
<winamp>
<current>

<artist>%%CURRENTARTIST%%</artist>
<album>%%CURRENTALBUM%%</album>
</current>
<second>

<artist>%%ARTIST2%%</artist>
<album>%%ALBUM2%%</album>
</second>
<third>
<artist>%%ARTIST3%%</artist>
<album>%%ALBUM3%%</album>
</third><lastupdated>%%LASTUPDATED%%</lastupdated>
</winamp>

I saved this template as C:\temp\winamp.template.txt.  In the DoSomething configuration dialog box, select “Generate HTML Playlist” from the Actions pulldown box.  In the “Template In” field, enter the path to your template file.  In the “Template Out” field, I entered C:\temp\winamp.xml.  Press the Add button to add this to the list of actions.

You’ll probably want to enable Error Messages, as well as ID3 Info Gathering.

Next, select “FTP A File” from the Actions pulldown.  Configure your ftp host, username, and password.  Specify the local file as the path to your template out file (in my case, C:\temp\winamp.xml), and specify the path and file name of the remote file on your FTP server.

Now, everytime the song changes, this file will get updated and sent to your website via FTP.

Step 2:Now you have the data on your website, you have to do something with it.  My solution was to use PHP5 to parse the XML.  With PHP5, parsing XML is very very easy.  I placed the following code in a file called “nowPlaying.php”:



/**
* Parse XML playlist
*
* This function parses an XML playlist file that was generated by Winamp, and
* uploaded to the webserver via FTP
*
* @access    public
* @param     string $file The path to the xml file to parse
* @return    mixed Associative array containing the playlist data
*/
function parsePlaylist($file)
{
$playlist = array();

$dom = new DomDocument();
$dom->load($file);

// Loop through all the nodes
foreach ($dom->documentElement->childNodes as $entries)
{
// if node is an element
if ($entries->nodeType == 1)
{
// Loop through the inner set of nodes
foreach ($entries->childNodes  as $item)
{
// Populate the array
$playlist[$entries->nodeName][$item->nodeName] = $item->textContent;
}
}
}
return $playlist;

} // End Function

// Call the parsePlaylist function, which returns an array
$arrPlaylist = parsePlaylist("../winamp/winamp.xml");

$title = $arrPlaylist['current']['title'];
$artist = $arrPlaylist['current']['artist'];
$album = $arrPlaylist['current']['album'];

// Force the page to refresh every 60 seconds
print '<meta HTTP-EQUIV="refresh" content="60">';

if($title != "")
{
print '
<div style="color:#000;font-weight:bold;font-size:12pt;font-family:Helvetica;">
Title:</div>

'.
'
<div style="color:red;font-weight:bold;font-size:11pt;font-family:Helvetica;">
&nbsp;&nbsp;'.$title.
'</div>

';
}

if($artist != "")
{
print '
<div style="color:#000;font-weight:bold;font-size:12pt;font-family:Helvetica;">
Artist:</div>

'.
'
<div style="color:red;font-weight:bold;font-size:11pt;font-family:Helvetica;">
&nbsp;&nbsp;<i>'.$artist.'</i></div>

';
}

if($album != "")
{
print '
<div style="color:#000;font-weight:bold;font-size:12pt;font-family:Helvetica;">
From the album:</div>

'.
'
<div style="color:red;font-weight:bold;font-size:11pt;font-family:Helvetica;">
&nbsp;&nbsp;'.$album.'</div>

';
}

It’s fairly ugly to have all the css code within the print statements – these should be placed with an external css file as classes, and referenced as such within the

</p> <div></div> <p> tags.

Step 3: Now that we have the playlist displayed on a webpage, we have to get the CD cover art.  This was fairly tricky to do, and took some trial and error, but it works fairly reliably.  The cover art is retrieved dynamically from Amazon.com using their search API.  I borrowed some code written by Calin Uioreanu at php9.com, which did a very good job of performing a search and returning a bunch of results.  However, I did not want multiple results; I only wanted the CD image.

There are three components to this approach:

- amazon_layout.php

- amazon_config.php

- amazon_class.php

The amazon_layout.php is what displays the actual image.  The code for it is as follows:



<?php
/**
* filename:     amazon_layout.php
* created:      7/17/2002, © 2002 php9.com Calin Uioreanu
* descripton:   display template for Amazon API
*/

// This images array is populated by the amazon class
$myImage = $ARRIMAGES[6][0];

// if Amazon returned an empty Image (1x1), do not display the HTML code
$arImageSize = getImageSize($myImage) ;

if ( is_array($arImageSize) &#038;&#038; $arImageSize[1] == 1)
{
$sImageUrl = '';
}
else
{
$sImageUrl = '<img '. SMALL_IMAGE_PROPERTIES .' xsrc="'. $myImage .'" alt="'.
$PRODUCTNAME .'" hspace="5" vspace="5" border="0" align="left" />';
}

echo
'
<table border="0" cellpadding="2" cellspacing="2">
<tr>
<td rowspan="7" bgcolor="white">',
$sImageUrl,
'</td>
</tr>
</table>

',
'
'
;
?>

Again, this code was modified from Colin’s original to use only the first image in the array of data, as opposed to displaying all the images returned from the Amazon.com search.

The next file, amazon_conf.php contains configuration code for accessing the Amazon API:



<?php
/**
* filename:   amazon_config.php
* created:    7/17/2002, © 2002 php9.com Calin Uioreanu
* descripton: configuration variables for Amazon Parser
*/

// if you have a valid Amazon associate Id, place it here to be
// rewarded for the traffic you generate to Amazon
define('ASSOCIATE_ID', 'php9comweblot-20');

// Amazon specific constants
define('IMAGEURLMEDIUM_HEIGHT',    140);
define('IMAGEURLMEDIUM_WIDTH',        107);

// Do not change this constant
define('DEVELOPER_TOKEN','D37FFQXOC3MRYZ');

//  XSL live transform Amazon data to HTML
define('PRODUCT_DETAIL_URL','http://xml.amazon.com/onca/xml3?t='.ASSOCIATE_ID.
'&#038;dev-t='.DEVELOPER_TOKEN.
'&#038;type=heavy&#038;f=http://www.php9.com/php9-data-to-htmls.xsl&#038;AsinSearch=');

// Set the default place to look
$sCurrentMode = 'music';

$arModes = array (
'baby' => 'baby (Baby)',
'books' => 'books (Books)',
'classical' => 'classical (Classical Music)',
'dvd' => 'dvd (DVD)',
'electronics' => 'electronics (Electronics)',
'garden' => 'garden (Outdoor Living)',
'kitchen' => 'kitchen (Kitchen &#038; Housewares)',
'magazines' => 'magazines (Magazines)',
'music' => 'music (Popular Music)',
'pc-hardware' => 'pc-hardware (Computers)',
'photo' => 'photo (Camera &#038; Photo)',
'software' => 'software (Software)',
'toys' => 'toys (Toys &#038; Games)',
'universal' => 'universal (Tools &#038; Hardware)',
'vhs' => 'vhs (Video)',
'videogames' => 'videogames (Computer &#038; Video Games)'
);

// sort by salesRank by default
if (!$sCurrentModeSortType = $_GET['SortBy'])
{
$sCurrentModeSortType = '+salesrank';
}

// Sort Types
$arModeSortType = array (
'baby' => array(
'+pmrank' => 'Featured Items',
'+salesrank' => 'Bestselling',
'+titlerank' => 'Alphabetical (A-Z)',
),
'books' => array(
'+pmrank' => 'Featured Items',
'+salesrank' => 'Bestselling',
'+reviewrank' => 'Average Customer Review',
'+pricerank' => 'Price (Low to High)',
'+inverse-pricerank' => 'Price (High to Low)',
'+daterank' => 'Publication Date',
'+titlerank' => 'Alphabetical (A-Z)',
'-titlerank' => 'Alphabetical (Z-A)',
),
'classical' => array(
'+pmrank' => 'Featured Items',
'+salesrank' => 'Bestselling',
'+titlerank' => 'Alphabetical (A-Z)',
),
'dvd' => array(
'+salesrank' => 'Bestselling',
'+titlerank' => 'Alphabetical',
),
'electronics' => array(
'+pmrank' => 'Featured Items',
'+salesrank' => 'Bestselling',
'+titlerank' => 'Alphabetical',
'+reviewrank' => 'Review',
),
'garden' => array(
'+psrank' => 'Featured Items',
'+salesrank' => 'Bestselling',
'+titlerank' => 'Alphabetical (A-Z)',
'-titlerank' => 'Alphabetical (Z-A)',
'+manufactrank' => 'Manufacturer (A-Z)',
'-manufactrank' => 'Manufacturer (Z-A)',
'+price' => 'Price (Low to High)',
'-price' => 'Price (High to Low)',
),
'kitchen' => array(
'+psrank' => 'Featured Items',
'+salesrank' => 'Bestselling',
'+titlerank' => 'Alphabetical (A-Z)',
'-titlerank' => 'Alphabetical (Z-A)',
'+manufactrank' => 'Manufacturer (A-Z)',
'-manufactrank' => 'Manufacturer (Z-A)',
'+price' => 'Price (Low to High)',
'-price' => 'Price (High to Low)',
),
'magazines' => array(
'+pmrank' => 'Featured Items',
'+salesrank' => 'Bestselling',
'+titlerank' => 'Alphabetical (A-Z)',
),
'music' => array(
'+psrank' => 'Featured Items',
'+salesrank' => 'Bestselling',
'+artistrank' => 'Artist Name',
'+orig-rel-date' => 'Original Release Date',
'+titlerank' => 'Alphabetical',
),
'pc-hardware' => array(
'+psrank' => 'Featured Items',
'+salesrank' => 'Bestselling',
'+titlerank' => 'Alphabetical (A-Z)',
'-titlerank' => 'Alphabetical (Z-A)',
),
'photo' => array(
'+pmrank' => 'Featured Items',
'+salesrank' => 'Bestselling',
'+titlerank' => 'Alphabetical (A-Z)',
'-titlerank' => 'Alphabetical (Z-A)',
),
'software' => array(
'+pmrank' => 'Featured Items',
'+salesrank' => 'Bestselling',
'+titlerank' => 'Alphabetical',
'+price' => 'Price (Low to High)',
'+price' => 'Price (High to Low)',
),
'toys' => array(
'+pmrank' => 'Featured Items',
'+salesrank' => 'Bestselling',
'+titlerank' => 'Alphabetical (A-Z)',
),
'universal' => array(
'+psrank' => 'Featured Items',
'+salesrank' => 'Bestselling',
'+titlerank' => 'Alphabetical (A-Z)',
'-titlerank' => 'Alphabetical (Z-A)',
'+manufactrank' => 'Manufacturer (A-Z)',
'-manufactrank' => 'Manufacturer (Z-A)',
'+price' => 'Price (Low to High)',
'-price' => 'Price (High to Low)',
),
'vhs' => array(
'+psrank' => 'Featured Items',
'+salesrank' => 'Bestselling',
'+titlerank' => 'Alphabetical',
),
'videogames' => array(
'+pmrank' => 'Featured Items',
'+salesrank' => 'Bestselling',
'+titlerank' => 'Alphabetical',
'+price' => 'Price (Low to High)',
'-price' => 'Price (High to Low)',
),
);

$sUrl  = 'http://xml.amazon.com/onca/xml3';
$sUrl .= '?t='. ASSOCIATE_ID;
$sUrl .= '&#038;dev-t='. DEVELOPER_TOKEN;
$sUrl .= '&#038;mode=' . $sCurrentMode;
$sUrl .= '&#038;type=lite&#038;page=1';
$sUrl .= '&#038;f=xml';
$sUrl .= '&#038;KeywordSearch=';

// The searchFor variable is set as a global variable in the calling php script
$sUrl .= urlencode($GLOBALS['searchFor']);

$sUrl .= '&#038;sort='. $sCurrentModeSortType;

?>

At this point, you can see that the config file sets a bunch of variables that the Amazon class needs to use.  A very important piece of this is what you wish to search for.  This data comes from your calling script; in my case, it’s defined in nowPlaying.php, which is listed in step 1.  You will need to add the following code to your calling script to set the global variables containing the search criteria:


global $searchFor;
$searchFor = $arrPlaylist['current']['album'].'+'.$arrPlaylist['current']['artist'];

Add this code somewhere after you call the parsePlaylist() function.  By combining the name of the album with the name of the artist, we increase the chances that we’ll get accurate matches from Amazon.

Lastly, we have the actual class which is the heart and soul of this entire project:


parser = xml_parser_create();
} // end func

/**
* boolean parse(void)
* parses a XML file
*/
function parse()
{
if (!$this->testLock())
{
// prevent html caching
$_GLOBALS['bFeedError'] = true;
return false;
}

// set the handlers
xml_set_object($this->parser, $this);
xml_set_element_handler($this->parser, 'startHandler', 'endHandler');
xml_set_character_data_handler($this->parser, 'cdataHandler');

if (!is_resource($this->fp))
{
$this->createLock();
return false;
}

/**
* Read the XML file and store the chunks into an array.  This is done because
* the Amazon search will return many results, and we only want the first result
* which will be the most relevant (and most likely, the correct one)
*/
while ($data = fread($this->fp, 2048))
{
$chunks[] = $data;
}

// Close the xml file
fclose($this->fp);

// Parse the XML contained within the first chunk of data
$err = xml_parse($this->parser, $chunks[0]);
if (! $err)
{
return $err;
}

// free the parser resource
xml_parser_free($this->parser);

return true;

} // end func

/**
* void startHandler (obj , str , arr)
* Event handler called by the expat library when an element's begin tag is encountered.
*/
function startHandler($parser, $sTag, $arAttr)
{
//  Start with empty sData string.
$this->sData = '';

//  Put each attribute into the Data array.
foreach ($arAttr as $Key=> $Val)
{
$this->arAtribute["$sTag:$Key"] = trim($Val);
}
} // end func

/**
* void cdataHandler (obj, str)
* Event handler called by the expat library when Character Data are encountered.
*/
function cdataHandler($parser, $sTag)
{
$this->sData .= $sTag;
}// end func

/**
* void endHandler (obj, str)
* Event handler called by the expat library when an element's end tag is encountered.
*/
function endHandler($parser, $sTag)
{
static
$MODE,
$ASIN,
$PRODUCTNAME,
$CATALOG,
$AUTHORS,
$ARTISTS,
$STARRING,
$DIRECTORS,
$THEATRICALRELEASEDATE,
$RELEASEDATE,
$MANUFACTURER,
$IMAGEURLSMALL,
$IMAGEURLMEDIUM,
$IMAGEURLLARGE,
$ARRIMAGES,
$LISTPRICE,
$OURPRICE,
$USEDPRICE,
$REFURBISHEDPRICE,
$THIRDPARTYNEWPRICE,
$SALESRANK,
$LISTS,
$TRACKS,
$BROWSELIST,
$MEDIA,
$NUMMEDIA,
$ISBN,
$FEATURES,
$MPAARATING,
$PLATFORM,
$AVAILABILITY,
$UPC,
$ACCESSORIES,
$PRODUCTDESCRIPTION,
$REVIEWS,
$THIRDPARTYPRODUCTINFO,
$AVGCUSTOMERRATING,
$CUSTOMERREVIEW,
$THIRDPARTYPRODUCTDETAILS,
$SIMILARPRODUCTS,
$TOTALRESULTS
;

// put the $this->sData into a string.
$sData = $this->sData;
switch (strtoupper ($sTag))
{
case 'ACTOR':
// build the list
$STARRING[] = $sData;
break;
case 'ARTIST':
// build the list
$ARTISTS[] = $sData;
break;
case 'DIRECTOR':
// build the list
$DIRECTORS[] = $sData;
break;
case 'AUTHOR':
// build the Authors list
$AUTHORS .= ($AUTHORS?', ':'') . $sData;
break;
case 'LISTID':
// build the list
$LISTS[] = $sData;
break;
case 'TRACK':
// build the list
$TRACKS[] = $sData;
break;
case 'BROWSENAME':
// build the list
$BROWSELIST[] = $sData;
break;
case 'FEATURE':
// build the list
$FEATURES[] = $sData;
break;
case 'ACCESSORY':
// build the list
$ACCESSORIES[] = $sData;
break;
case 'PRODUCT':
// build the list
$SIMILARPRODUCTS[] = $sData;
break;
case 'AVGCUSTOMERRATING':
// build the list
$AVGCUSTOMERRATING = $sData;
break;
case 'CUSTOMERREVIEW':
// build the list
$REVIEWS[] = $CUSTOMERREVIEW;
break;
case 'THIRDPARTYPRODUCTDETAILS':
// build the list
$THIRDPARTYPRODUCTINFO[] = $THIRDPARTYPRODUCTDETAILS;
break;
case 'SELLERID':
case 'SELLERNICKNAME':
case 'EXCHANGEID':
case 'OFFERINGPRICE':
case 'CONDITION':
case 'CONDITIONTYPE':
case 'EXCHANGEAVAILABILITY':
case 'SELLERCOUNTRY':
case 'SELLERSTATE':
case 'SELLERRATING':
// build the list
$THIRDPARTYPRODUCTDETAILS[$sTag] = $sData;
break;
case 'RATING':
// build the list
$CUSTOMERREVIEW['Rating'] = $sData;
break;
case 'SUMMARY':
// build the list
$CUSTOMERREVIEW['Summary'] = $sData;
break;
case 'COMMENT':
// build the list
$CUSTOMERREVIEW['Comment'] = $sData;
break;
case 'ASIN':
case 'MODE':
case 'PRODUCTNAME':
case 'CATALOG':
case 'THEATRICALRELEASEDATE':
case 'MPAARATING':
case 'RELEASEDATE':
case 'MANUFACTURER':
case 'IMAGEURLSMALL':
case 'IMAGEURLMEDIUM':
$ARRIMAGES[][] = $sData;
break;
case 'IMAGEURLLARGE':
case 'LISTPRICE':
case 'OURPRICE':
case 'USEDPRICE':
case 'REFURBISHEDPRICE':
case 'THIRDPARTYNEWPRICE':
case 'SALESRANK':
case 'MEDIA':
case 'PRODUCTDESCRIPTION':
case 'NUMMEDIA':
case 'ISBN':
case 'PLATFORM':
case 'AVAILABILITY':
case 'UPC':
$$sTag = $sData;
break;

case 'ERRORMSG':
// if this is a global error, avoid caching the module
if (!$this->iNumResults)
{
global $bParseError;
$bParseError = true;
}
break;

case 'DETAILS':
// offer some details
$sBookUrl = PRODUCT_DETAIL_URL . $ASIN;
//Details finished
require($this->sTemplate);

// empty the product related information
$STARRING= array ();
$ARTISTS= array ();
$DIRECTORS= array ();
$AUTHORS = '';
$REVIEWS = array ();
$THIRDPARTYPRODUCTINFO = array();
$BROWSELIST= array ();
$FEATURES= array ();
$ACCESSORIES = array ();
$AVGCUSTOMERRATING = array ();
$CUSTOMERREVIEW = array ();
$SIMILARPRODUCTS = array ();

$ASIN='';
$PRODUCTNAME='';
$CATALOG='';
$AUTHORS='';
$THEATRICALRELEASEDATE='';
$RELEASEDATE='';
$MANUFACTURER='';
$IMAGEURLSMALL='';
$IMAGEURLMEDIUM='';
$IMAGEURLLARGE='';
$LISTPRICE='';
$OURPRICE='';
$USEDPRICE='';
$REFURBISHEDPRICE='';
$THIRDPARTYNEWPRICE='';
$SALESRANK='';
$MEDIA='';
$PRODUCTDESCRIPTION = '';
$NUMMEDIA='';
$ISBN='';
$MPAARATING='';
$PLATFORM='';
$AVAILABILITY='';
$UPC='';

// increase global counter
$this->iNumResults++;
break;

case 'TOTALRESULTS':
$this->arAtribute['TotalResults'] = $sData;
break;

case 'PRODUCTINFO':
break;
}
}

/**
* bool setInputUrl(str, int)
* tries to open a connection to the given url with the given timeout
*/
function setInputUrl($sUrl, $iTimeout)
{
if (!$this->testLock())
{
// prevent html caching
$_GLOBALS['bFeedError'] = true;
return false;
}

$arUrl = parse_url($sUrl);
$sHost = $arUrl['host'];
if (!@$iPort = $arUrl['port'])
{
$iPort = 80; // default HTTP port
}
$sFullPath = $arUrl['path'] . '?' . $arUrl['query'];

$fp = fsockopen($sHost, $iPort, $errno, $errstr, $iTimeout);
if(!is_resource($fp))
{
// return an error
echo '@';
$this->createLock();
return false;
}
else
{
fputs($fp,"GET $sFullPath HTTP/1.0\r\nHost: " . $sHost. "\r\n\r\n");

// win32
if (function_exists('socket_set_timeout'))
{
@socket_set_timeout($fp, $iTimeout);
}

// in blocking mode it will wait for data to become available on the socket
socket_set_blocking($fp, true);

// get the first line and determine the answer-code
$sLine = fgets($fp , 1024);
$iCode = preg_replace("/.*(\d\d\d).*/i" , "\\1" , $sLine);

// an error occurred if code is not between 200 and 399
$error = null;
if ($iCode != 200)
{
// prevent html caching
$_GLOBALS['bFeedError'] = true;
error_log (
"\n". time() .':'. $sUrl .':'. $sLine .':'. $_SERVER['REQUEST_URI'],
3,
'htmlcache/search/return_code_failures.log'
);
fclose($fp);
$this->createLock();
return false;
}

$sHeader = '';
// no error - now determine start of data (skipping header)
while (!feof($fp))
{
$sLine = fgets($fp , 1024);
if (strlen($sLine) < 3)
{
break;
}
}

$this->fp = $fp;
return true;
}
} // end func

/**
* createLock()
* lock
*/
function createLock()
{
if (!$handle = fopen(AWS_LOCK_FILE, 'w'))
{
echo 'cannot open lock';
return false;
}

fclose($handle);
return true;
} // end func

/**
* testLock()
* test lock for a given time, eventually release it
*/
function testLock()
{
if (!file_exists(AWS_LOCK_FILE))
{
return true;
}

if ((time() - filemtime(AWS_LOCK_FILE)) < AWS_LOCK_TIME)
{
return false;
}

// release lock
if (!$handle = unlink(AWS_LOCK_FILE))
{
return false;
}

return true;
} // end func

} // end class definition

?>

Step 4: Now that you have all of the code, you have to use it.  I added the following function to my calling script (nowPlaying.php):



/**
* Get the image
*
* This function uses the Amazon class to search for a CD for the purpose of displaying
* the cover art on a webpage
*
* @access    public
* @param      string $album The name of the album
* @return  null
*/
function getCDImage($album)
{
// configuration variables
require_once('./amazon/amazon_config.php');

// webservice class definition
require_once('./amazon/amazon_class.php');

flush();

if($album != "")
{
$oAmazon = new Amazon_WebService();

if (!$oAmazon->setInputUrl($sUrl, 20))
{
die ('cannot open input file. exiting..' . '<a xhref='. $sUrl .'>@</a>');
}

// pass the output display template
$oAmazon->sTemplate = './amazon/amazon_layout.php';

if (!$oAmazon->parse())
{
die ('XMLParse failed');
}
}
else
{
print "

No CD artwork available for this album
";
}
}

Step 5:  The final step is to embed this script into a webpage.  The script prints a meta refresh tag which causes the page to reload every 60 seconds.  I did not want the entire page to reload, so I display the script within an iframe:



<iframe xsrc="/php/nowPlaying.php" frameborder=0 width="240px" height="360px"></iframe>

Now, only this small rectangular block of content will refresh.  I know that there seems to be a lot of steps involved with this integration, and perhaps the amazon stuff can all be merged into a single class (which it probably should…), but the results are worth the effort, in my opinion!

Feel free to contact me with problems!

Return top

INFORMATION

Drupal development since v4.7