Developing Feeds with Rss and Atom
10.12. Podcasting Weather Forecasts
The podcasting technique described in Chapter 4 is a hotbed of development at the moment. One idea put forward was to use it to deliver weather forecasts via a web service and a text-to-speech application. Jorge Velázquez put together a script to do just that. Released at http://www.jorgev.com/archives/000115.html, it requires an account with weather.com and an installation of Lame (from http://lame.sourceforge.net/) and text2wave on the server. 10.12.1. How to Use It
The URL accepts two parameters, locid and unit. The locid is the weather.com location identifier for the city you require. For U.S. cities, this can be a zip code, and for non-U.S. cities, it is a special weather.com code. (e.g., 92126 for San Diego, CA, or ITXX0067 for Rome, Italy). The unit parameter is optional and can be either m for metric or s for imperial measurements. It defaults to imperial. The location code for Florence, Italy, is ITXX0028, so the URL for the feed would be http://www.example.com/cgi-bin/weather.cgi?locid=ITXX0028. Simple. 10.12.2. The Code Itself
Jorge's code is, in his own words, very simple. This is how he describes it: A brief explanation of how the script works, it's actually quite simple: I first call into weather.com's XML Data Feed. Then I use XPath to extract the data in which I am interested. I format this information into a text file, which I then pass onto the text2wave utility which performs the text-to-speech conversion. Finally, since wav files are so huge, I convert it to MP3 using the LAME encoder. Piece of cake, eh? #!/usr/bin/perl -w # 2004-12-13 Jorge Velázquez use strict; use CGI qw(:standard); use XML::RSS; use XML::XPath; use LWP::Simple; use File::Temp; use File::Basename; # partner and key information my $par = 'partneridhere'; my $key = 'keyhere'; # get parameters my $cgi = CGI::new( ); my $locid = $cgi->param('locid'); my $unit = $cgi->param('unit'); if ( not $unit ) { $unit = 's'; } my $mp3dir = 'enter/mp3/path/here'; # query weather info, current conditions with 2 day forecast my $xml = get( "http://xoap.weather.com/weather/local/ $locid?cc=*&dayf=2&prod=xoap&par=$par&key=$key&unit=$unit" ); #load it into XPath object my $xp = XML::XPath->new($xml); # extract unit information from feed my $ut = $xp->findvalue('/weather/head/ut'); my $ud = $xp->findvalue('/weather/head/ud'); my $us = $xp->findvalue('/weather/head/us'); # create rss 2.0 feed my $rss = new XML::RSS( version => '2.0' ); # channel information $rss->channel( title => 'Weather Podcast', link => 'http://www.weather.com/', description => 'Local weather podcasting feed', language => 'en' ); # get current weather conditions my $dnam = $xp->findvalue('/weather/loc/dnam'); my $ccobst = $xp->findvalue('/weather/cc/obst'); my $cclsup = $xp->findvalue('/weather/cc/lsup'); my $cctemp = $xp->findvalue('/weather/cc/tmp'); my $ccwind = $xp->findvalue('/weather/cc/wind/s'); my $cct = $xp->findvalue('/weather/cc/t'); my $ccbarr = $xp->findvalue('/weather/cc/bar/r'); my $ccbard = $xp->findvalue('/weather/cc/bar/d'); # convert the units to words my $utword = $ut eq 'F' ? 'fahrenheit' : 'celsius'; # build the text file for converting to speech my $text = "Current conditions for $dnam. $cct. The temperature is $cctemp $utword."; # write the file and get the stats my $filename = &writefile($text); my $basename = basename $filename; my $filesize = ( stat $filename )[7]; # add rss item for current weather $rss->add_item( title => "Current weather conditions for $ccobst", link => "http://www.weather.com/weather/local/$locid", description => $text, pubDate => $cclsup, enclosure => { url => "$mp3dir$basename", length => $filesize, type => 'audio/mpeg' } ); # get forecast timestamp my $lsup = $xp->findvalue('/weather/dayf/lsup'); # iterate through forecast days my $nodeset = $xp->find('/weather/dayf/day'); foreach my $node ( $nodeset->get_nodelist ) { # get the items of interest to our script my $t = $node->findvalue('@t'); my $dt = $node->findvalue('@dt'); my $hi = $node->findvalue('hi'); my $low = $node->findvalue('low'); my $d = $node->findvalue('part[@p="d"]/t'); my $n = $node->findvalue('part[@p="n"]/t'); # build the text file for converting to speech $text = "Weather forecast for $t, $dt in $dnam. "; if ( $d eq 'N/A' ) { $text .= "Daytime conditions not available. "; } else { $text .= "Daytime $d. "; } if ( $n eq 'N/A' ) { $text .= "Nighttime conditions not available. "; } else { $text .= "Nighttime $n. "; } if ( $hi eq 'N/A' ) { $text .= "The high is unavailable. "; } else { $text .= "The high is $hi $utword. "; } if ( $low eq 'N/A' ) { $text .= "The low is unavailable. "; } else { $text .= "The low is $low $utword. "; } # write the file and get the stats $filename = &writefile($text); $basename = basename $filename; $filesize = ( stat $filename )[7]; # add this forecast $rss->add_item( title => "Weather forecast for $t, $dt at $dnam", link => "http://www.weather.com/weather/local/$locid", description => $text, pubDate => $lsup, enclosure => { url => "$mp3dir$basename", length => $filesize, type => 'audio/mpeg' } ); } print header('application/rss+xml'); print $rss->as_string; sub writefile { # write the text file my $fhtxt = new File::Temp( suffix => '.txt' ); print $fhtxt $_[0]; close $fhtxt; # write the wav file my $fhwav = new File::Temp( suffix => '.wav' ); system "text2wave", "-o", $fhwav->filename, $fhtxt->filename; # convert it to mp3 my $fhmp3 = new File::Temp( unlink => 0, dir => '../mp3', suffix => '.mp3' ); system "lame", "-h", $fhwav->filename, $fhmp3->filename; # return the file name return $fhmp3->filename; }
|