home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / xbmc-9.11.exe / scripts / TWC Supplemental / resources / lib / TWCClient.py < prev   
Encoding:
Python Source  |  2009-12-17  |  45.7 KB  |  819 lines

  1. """
  2.     TWC api client module
  3. """
  4.  
  5. # main imports
  6. import sys
  7. import os
  8.  
  9. try:
  10.     import xbmc
  11.     DEBUG = False
  12. except:
  13.     DEBUG = True
  14.  
  15. import urllib2
  16. import md5
  17. import re
  18. import shutil
  19. import time
  20. import cookielib
  21.  
  22.  
  23. class WeatherAlert:
  24.     def __init__( self, htmlSource ):
  25.         self.alert = ""
  26.         try:
  27.             self._get_alert( htmlSource )
  28.         except:
  29.             pass
  30.  
  31.     def _get_alert( self, htmlSource ):
  32.         # regex patterns
  33.         pattern_alert = "<h1>([^<]+)</h1>"
  34.         pattern_expires = "<p>(<b>.+?</b>[^<]+)</p>"
  35.         pattern_issuedby = "<p class=\"alIssuedBy\">(.+?)</p>"
  36.         pattern_narrative = "<p class=\"alNarrative\">(.*?)</p>"
  37.         pattern_moreinfo = "<h2>([^<]+)</h2>\n.+?<p class=\"alSynopsis\">"
  38.         pattern_synopsis = "<p class=\"alSynopsis\">(.+?)</p>"
  39.         # fetch alert
  40.         alert = re.findall( pattern_alert, htmlSource )[ 0 ]
  41.         # fetch expires
  42.         try:
  43.             expires = re.findall( pattern_expires, htmlSource )[ 0 ].replace( "<b>", "" ).replace( "</b>", "" )
  44.         except:
  45.             expires = ""
  46.         # fetch issued by
  47.         try:
  48.             issuedby_list = re.findall( pattern_issuedby, htmlSource, re.DOTALL )[ 0 ].split( "<br>" )
  49.             issuedby = "[I]"
  50.             for item in issuedby_list:
  51.                 issuedby += item.strip()
  52.                 issuedby += "\n"
  53.             issuedby += "[/I]"
  54.             # fetch narrative
  55.             description_list = re.findall( pattern_narrative, htmlSource, re.DOTALL )
  56.             narrative = ""
  57.             for item in description_list:
  58.                 narrative += "%s\n\n" % ( item.strip(), )
  59.             try:
  60.                 # fetch more info
  61.                 moreinfo = re.findall( pattern_moreinfo, htmlSource )[ 0 ]
  62.                 moreinfo = "[B]%s[/B]" % ( moreinfo, )
  63.                 # fetch sysnopsis
  64.                 description_list = re.findall( pattern_synopsis, htmlSource, re.DOTALL )
  65.                 synopsis = ""
  66.                 for item in description_list:
  67.                     synopsis += "%s\n\n" % ( item.strip(), )
  68.             except:
  69.                 moreinfo = ""
  70.                 synopsis = ""
  71.         except:
  72.             try:
  73.                 narrative = ""
  74.                 synopsis = ""
  75.                 issuedby = re.findall( "<p>(.+)?</p>", htmlSource )[ 0 ]
  76.                 items =  re.findall( "<B>(.+)?</B>\s.*\s.*\s.*\s.+?<IMG SRC=\"[^>]+> <B>([^<]+)</B><BR>Type: (.+)", htmlSource )[ 0 ]
  77.                 moreinfo = "\nType: %s (%s)\nLevel: %s" % ( items[ 0 ], items[ 2 ], items[ 1 ], )
  78.             except:
  79.                 pass
  80.         try:
  81.             # create our alert string
  82.             self.alert = "[B]%s[/B]\n%s\n\n%s\n%s\n\n%s\n\n%s" % ( alert, expires, issuedby, narrative.strip(), moreinfo, synopsis.strip(), )
  83.             self.alert = "%s\n%s\n\n" % ( self.alert.strip(), "-"*100, )
  84.             self.title = "[B]%s[/B]" % ( alert, )
  85.         except:
  86.             self.alert = None
  87.  
  88. class Forecast36HourParser:
  89.     def __init__( self, htmlSource ):
  90.         self.forecast = []
  91.         self.alerts = []
  92.         self.video_location = []
  93.         self._get_forecast( htmlSource )
  94.  
  95.     def _get_forecast( self, htmlSource ):
  96.         # regex patterns
  97.         #pattern_dmacode = "var omn_dmaCode=\"([0-9]+)\""
  98.         pattern_locstate = "var omn_locstate=\"([^\"]+)\""
  99.         pattern_video_location = ">Watch the ([A-Za-z]+) Forecast<"
  100.         #pattern_dmaname = "dma_names\[\"%s\"\]=\"([^\"]+)\""
  101.         pattern_alerts = "alertArray\[[0-9]+\] = new alertObj\('([^']+)','([^']+)','([^']+)'"
  102.         pattern_days = "from=[^\"]+\" class=\"[^\"]+\"><B>([^<]+)</font></B></A></td>"
  103.         pattern_icon = "<img src=\"http://image.weather.com/web/common/wxicons/[0-9]+/([0-9]+)\.gif\?[^\"]+\" alt=\""
  104.         pattern_forecast_brief = "<font CLASS=\"[^\"]+\">([^<]+)</font>"
  105.         pattern_temp = "<td valign=\"middle\" align=\"[^\"]+\"><font CLASS=\"[^\"]+\">([^<]+)<br>[^<]+<font class=\"[^\"]+\"><[^<]+>([^<]+)<[^<]+></font>"
  106.         pattern_precip_title = "<TD valign=\"[^\"]+\" width=\"[^\"]+\" class=\"[^\"]+\" align=\"[^\"]+\">([A-Za-z]+[^<]+)</td>"
  107.         pattern_precip_amount = "<TD valign=\"[^\"]+\" width=\"[^\"]+\" class=\"[^\"]+\" align=\"[^\"]+\">([0-9]+[^<]+)</td>"
  108.         pattern_outlook = "<DIV STYLE=\"padding:5px 5px 5px 0px;\">([^\n|^<]*)"
  109.         pattern_daylight = "<TD valign=\"[^\"]+\" align=\"[^\"]+\" class=\"[^\"]+\">([^<]+)</TD>"
  110.         #pattern_videos = "<a href=\"(/multimedia/videoplayer.html\?clip=[^&]+&collection=[^&]+)&from="
  111.         #pattern_region = "<A HREF=\"/multimedia/videoplayer.html\?clip=[0-9]+&collection=(regwxforecast)&from=[^<]+>(.+?)</A>"
  112.         try:
  113.             # fetch dmacode
  114.             #dmacode = re.findall( pattern_dmacode, htmlSource )[ 0 ]
  115.             # fetch state
  116.             locstate = re.findall( pattern_locstate, htmlSource )[ 0 ].lower()
  117.             # fetch video location
  118.             #self.video_location = ( re.findall( pattern_dmaname % ( dmacode, ), htmlSource )[ 0 ].lower().replace( " ", "" ), locstate, )
  119.             self.video_location = ( re.findall( pattern_video_location, htmlSource )[ 0 ].lower().replace( " ", "" ), locstate, )
  120.         except:
  121.             pass
  122.         # fetch regional video
  123.         """
  124.         try:
  125.             if ( not self.video_location ):
  126.                 self.video_location = re.findall( pattern_region, htmlSource )[ 0 ]
  127.         except:
  128.             pass
  129.         """
  130.         # fetch alerts
  131.         self.alerts = re.findall( pattern_alerts, htmlSource )
  132.         # fetch days
  133.         days = re.findall( pattern_days, htmlSource )
  134.         # fetch icon
  135.         icon = re.findall( pattern_icon, htmlSource )
  136.         # fetch brief description
  137.         brief = re.findall( pattern_forecast_brief, htmlSource )
  138.         # fetch temperature
  139.         temperature = re.findall( pattern_temp, htmlSource )
  140.         # fetch precip title
  141.         precip_title = re.findall( pattern_precip_title, htmlSource )
  142.         # fetch precip title
  143.         precip_amount = re.findall( pattern_precip_amount, htmlSource )
  144.         # fetch forecasts
  145.         outlook = re.findall( pattern_outlook, htmlSource )
  146.         # fetch daylight
  147.         daylight = re.findall( pattern_daylight, htmlSource )
  148.         # enumerate thru and combine the day with it's forecast
  149.         if ( len( days ) ):
  150.             for count, day in enumerate( days ):
  151.                 # make icon path
  152.                 if ( not DEBUG ):
  153.                     iconpath = "/".join( [ "special://temp", "weather", "128x128", icon[ count ] + ".png" ] )
  154.                 else:
  155.                     iconpath = icon[ count ] + ".png"
  156.                 # add result to our class variable
  157.                 self.forecast += [ ( day, iconpath, brief[ count ], temperature[ count ][ 0 ], temperature[ count ][ 1 ].replace( "° ", "\xb0" ), precip_title[ count ], precip_amount[ count ], outlook[ count ].strip(), daylight[ count ], ) ]
  158.  
  159.  
  160. class ForecastHourByHourParser:
  161.     def __init__( self, htmlSource ):
  162.         self.headings = []
  163.         self.forecast = []
  164.         self.alerts = []
  165.         self._get_forecast( htmlSource )
  166.  
  167.     def _get_forecast( self, htmlSource ):
  168.         # regex patterns
  169.         pattern_headings = "<div class=\"hbhTD[^\"]+\"><div title=\"[^>]+>([^<]+)</div></div>"
  170.         pattern_info = "<div class=\"hbhTDTime[^>]+><div>([^<]+)</div></div>.*\s\
  171. [^<]+<div class=\"hbhTDConditionIcon\"><div><img src=\"http://i.imwx.com/web/common/wxicons/[0-9]+/(gray/)?([0-9]+).gif\"[^>]+></div></div>.*\s\
  172. [^<]+<div class=\"hbhTDCondition\"><div><b>([^<]+)</b><br>([^<]+)</div></div>.*\s\
  173. [^<]+<div class=\"hbhTDFeels\"><div>([^<]*)</div></div>.*\s\
  174. [^<]+<div class=\"hbhTDPrecip\"><div>([^<]*)</div></div>.*\s\
  175. [^<]+<div class=\"hbhTDHumidity\"><div>([^<]*)</div></div>.*\s\
  176. [^<]+<div class=\"hbhTDWind\"><div>([^<]*)<br>([^<]*)</div></div>"
  177.         pattern_alerts = "alertArray\[[0-9]+\] = new alertObj\('([^']+)','([^']+)','([^']+)'"
  178.         # fetch alerts
  179.         self.alerts = re.findall( pattern_alerts, htmlSource )
  180.         # fetch headings
  181.         headings = re.findall( pattern_headings, htmlSource )
  182.         # fetch info
  183.         info = re.findall( pattern_info, htmlSource )
  184.         # enumerate thru and create heading and forecast
  185.         if ( len( headings ) and len( info ) ):
  186.             # fixe headings
  187.             for heading in headings:
  188.                 self.headings += [ heading.replace( "<br>", "\n" ).replace( "<BR>", "\n" ) ]
  189.             # create our forecast list
  190.             for item in info:
  191.                 # make icon path
  192.                 if ( not DEBUG ):
  193.                     iconpath = "/".join( [ "special://temp", "weather", "128x128", item[ 2 ] + ".png" ] )
  194.                 else:
  195.                     iconpath = item[ 2 ] + ".png"
  196.                 # add result to our class variable
  197.                 self.forecast += [ ( item[ 0 ], iconpath, item[ 3 ].replace( "°", "\xb0" ), item[ 4 ].replace( "°", "\xb0" ), item[ 5 ].replace( "°", "\xb0" ), item[ 6 ], item[ 7 ], item[ 8 ] + "\n" + item[ 9 ].strip(), ) ]
  198.  
  199.  
  200. class ForecastWeekendParser:
  201.     def __init__( self, htmlSource ):
  202.         self.forecast = []
  203.         self.alerts = []
  204.         self._get_forecast( htmlSource )
  205.  
  206.     def _get_forecast( self, htmlSource ):
  207.         # regex patterns
  208.         pattern_heading = "from=\"weekend[\"]+>([^<]+)</A>.*\s.*\s\
  209. [^<]+<TD width=\"[^\"]+\" class=\"wkndButton[A-Z]+\" align=\"[^\"]+\" valign=\"[^\"]+\"><FONT class=\"[^\"]+\">([^\&]+) .*\s.*\s.*\s.*\s.*\s.*\s.*\s.*\s.*\s.*\s\
  210. [^>]+>[^>]+>([^<]+)<"
  211.         pattern_observed = ">(Observed:)+"
  212.         #pattern_brief = "<IMG src=\"http://image.weather.com/web/common/wxicons/[pastwx/]*[0-9]+/([0-9]+)\.gif.*alt=\"([^\"]+)\""
  213.         #pattern_brief = "<IMG src=\"http://i.imwx.com/web/common/wxicons/[0-9]+/([0-9]+).gif.*alt=\"([^\"]+)\""
  214.         pattern_brief = "<IMG src=\"http://(?:i.imwx.com)?(?:image.weather.com)?/web/common/wxicons/(?:pastwx/)?[0-9]+/([0-9]+).gif.*alt=\"([^\"]+)\""
  215.         pattern_past = "<TD align=\"left\" class=\"grayFont10\">([^<]+)</TD>"
  216.         pattern_past2 = "<TD align=\"[left|right]+\" class=\"blueFont10\">[<B>]*<FONT color=\"[^\"]+\">([^\s|^<]+)[^\n]+"
  217.         pattern_avg = "<tr><td align=\"right\" valign=\"top\" CLASS=\"blueFont10\">([^<]+)<.*\s.*\s[^[A-Z0-9]+(.*°[F|C]+)"
  218.         #pattern_avg = "<tr><td align=\"right\" valign=\"top\" CLASS=\"blueFont10\">([^<]+)<.*\s.*\s.*\s\t*(.+?)\s"
  219.         pattern_high = "<FONT class=\"[^\"]+\">([^<]+)<BR><FONT class=\"[^\"]+\"><NOBR>([^<]+)</FONT></NOBR>"
  220.         pattern_low = "<FONT class=\"[^\"]+\">([^<]+)</FONT><BR><FONT class=\"[^\"]+\"><B>([^<]+)</B></FONT>"
  221.         ##pattern_precip = "<TD valign=\"[^\"]+\" width=\"[^\"]+\" class=\"[^\"]+\" align=\"[^\"]+\">(.*)\r"
  222.         pattern_precip = "<TD valign=\"top\" width=\"50%\" class=\"blueFont10\" align=\"[left|right]+\">(.*)"
  223.         pattern_wind = "<td align=\"[^\"]+\" valign=\"[^\"]+\" CLASS=\"[^\"]+\">([^<]+)</td><td align=\"[^\"]+\"> </td><td valign=\"[^\"]+\" CLASS=\"[^\"]+\"><B>.*\n[^A-Z]+([A-Z]+)<br>([^<]+)</B>"
  224.         pattern_uv = "<td align=\"[^\"]+\" valign=\"[^\"]+\" CLASS=\"[^\"]+\">([^<]+)</td>\s[^>]+>[^>]+>[^>]+><B>([^<]+)"
  225.         pattern_humidity = "<td align=\"[^\"]+\" valign=\"[^\"]+\" CLASS=\"[^\"]+\">([^<]+)[^>]+>[^>]+>[^>]+>[^>]+><B>([0-9]+%)"
  226.         pattern_daylight = "<td align=\"[^\"]+\" valign=\"[^\"]+\" CLASS=\"[^\"]+\">([^<]+)[^>]+>[^>]+>[^>]+>[^>]+><B>([0-9]+:[0-9]+[^<]+)</B></td>"
  227.         pattern_outlook = "<TD colspan=\"3\" class=\"blueFont10\" valign=\"middle\" align=\"left\">([^<]+)</TD>"
  228.         pattern_alerts = "alertArray\[[0-9]+\] = new alertObj\('([^']+)','([^']+)','([^']+)'"
  229.         pattern_departures = "<FONT COLOR=\"#7d8c9f\"><B>\s.*\s\s+(.+?F)"
  230.         # fetch alerts
  231.         self.alerts = re.findall( pattern_alerts, htmlSource )
  232.         # fetch headings
  233.         headings = re.findall( pattern_heading, htmlSource )
  234.         # fetch observed status
  235.         observeds = re.findall( pattern_observed, htmlSource )
  236.         # insert necessary dummy entries
  237.         for  i in range( 3 - len( observeds ) ):
  238.             observeds.append( "" )
  239.         # fetch briefs
  240.         briefs = re.findall( pattern_brief, htmlSource )
  241.         # insert necessary dummy entries
  242.         for count, i in enumerate( range( 3 - len( briefs ) ) ):
  243.             briefs.insert( count, ( "na", "", ) )
  244.         # fetch past info
  245.         pasts = re.findall( pattern_past, htmlSource )
  246.         if ( pasts == [] ):
  247.             pasts2 = re.findall( pattern_past2, htmlSource )
  248.             # create the pasts list
  249.             for count, i in enumerate( range( 0, len( pasts2 ), 2 ) ):
  250.                 pasts += [ pasts2[ count * 2 ] + pasts2[ count * 2 + 1 ] ]
  251.         # insert necessary dummy entries
  252.         for i in range( 9 - len( pasts ) ):
  253.             pasts.append( ": " )
  254.         # fetch average info
  255.         avgs = re.findall( pattern_avg, htmlSource )
  256.         # insert necessary dummy entries
  257.         for i in range( 0, 12 - len( avgs ) ):
  258.             avgs.append( ( "", "", ) )
  259.         # fetch highs
  260.         highs = re.findall( pattern_high, htmlSource )
  261.         # insert necessary dummy entries
  262.         for count, i in enumerate( range( 3 - len( highs ) ) ):
  263.             highs.insert( count, ( pasts[ count * 3 ].split( ": " )[ 0 ], pasts[ count * 3 ].split( ": " )[ 1 ], ) )
  264.         # fetch lows
  265.         lows = re.findall( pattern_low, htmlSource )
  266.         # insert necessary dummy entries
  267.         for count, i in enumerate( range( 3 - len( lows ) ) ):
  268.             lows.insert( count, ( pasts[ count * 3 + 1 ].split( ": " )[ 0 ], pasts[ count * 3 + 1 ].split( ": " )[ 1 ], ) )
  269.         # fetch precips
  270.         precips = re.findall( pattern_precip, htmlSource )
  271.         # insert necessary dummy entries
  272.         for i in range( 6 - len( precips ) ):
  273.             precips.insert( 0, "" )
  274.         # fetch winds
  275.         winds = re.findall( pattern_wind, htmlSource )
  276.         # insert necessary dummy entries
  277.         for i in range( 3 - len( winds ) ):
  278.             winds.insert( 0, ( "", "", "", ) )
  279.         # fetch uvs
  280.         uvs = re.findall( pattern_uv, htmlSource )
  281.         # insert necessary dummy entries
  282.         for i in range( 3 - len( uvs ) ):
  283.             uvs.insert( 0, ( "", "", ) )
  284.         # fetch humids
  285.         humids = re.findall( pattern_humidity, htmlSource )
  286.         # insert necessary dummy entries
  287.         for i in range( 3 - len( humids ) ):
  288.             humids.insert( 0, ( "", "", ) )
  289.         # fetch daylights
  290.         daylights = re.findall( pattern_daylight, htmlSource )
  291.         # insert necessary dummy entries
  292.         for i in range( 6 - len( daylights ) ):
  293.             daylights.insert( 0, ( "", "" ) )
  294.         # fetch outlooks
  295.         outlooks = re.findall( pattern_outlook, htmlSource )
  296.         # insert necessary dummy entries
  297.         for i in range( 3 - len( outlooks ) ):
  298.             outlooks.insert( 0, "" )
  299.         # enumerate thru and create our forecast list
  300.         if ( len( headings ) ):
  301.             for count, ( day, date, alert, ) in enumerate( headings ):
  302.                 # make icon path
  303.                 if ( not DEBUG ):
  304.                     iconpath = "/".join( [ "special://temp", "weather", "128x128", briefs[ count ][ 0 ] + ".png" ] )
  305.                 else:
  306.                     iconpath = briefs[ count ][ 0 ] + ".png"
  307.                 # add result to our class variable
  308.                 self.forecast += [ ( day, date, iconpath, briefs[ count][ 1 ], highs[count][ 0 ], highs[ count ][ 1 ].replace( "°", "\xb0" ),
  309.                 lows[ count ][ 0 ], lows[ count ][ 1 ].replace( "°", "\xb0" ), precips[ count * 2 ], precips[ count * 2 + 1 ].replace( "<B>", "" ).replace( "</B>", "" ),
  310.                 winds[ count ][ 0 ], winds[ count ][ 1 ] + " " + winds[ count ][ 2 ], uvs[ count ][ 0 ], uvs[ count ][ 1 ],
  311.                 humids[ count ][ 0 ], humids[ count ][ 1 ], daylights[ count * 2 ][ 0 ], daylights[ count * 2 ][ 1 ], daylights[ count * 2 + 1 ][ 0 ],
  312.                 daylights[ count * 2 + 1 ][ 1 ], outlooks[ count ], observeds[ count ], pasts[ count * 3 + 2 ].split( " " )[ 0 ], pasts[ count * 3 + 2 ].split( " " )[ 1 ],
  313.                 avgs[ count * 4 ][ 0 ], avgs[ count * 4 ][ 1 ].replace( "°", "\xb0" ), avgs[ count * 4 + 1 ][ 0 ], avgs[ count * 4 + 1 ][ 1 ].replace( "°", "\xb0" ),
  314.                 avgs[ count * 4 + 2 ][ 0 ], avgs[ count * 4 + 2 ][ 1 ].replace( "°", "\xb0" ), avgs[ count * 4 + 3 ][ 0 ], avgs[ count * 4 + 3 ][ 1 ].replace( "°", "\xb0" ),
  315.                 alert.strip(), ) ]
  316.  
  317.  
  318. class Forecast10DayParser:
  319.     def __init__( self, htmlSource ):
  320.         self.headings = []
  321.         self.forecast = []
  322.         self.alerts = []
  323.         self._get_forecast( htmlSource )
  324.  
  325.     def _get_forecast( self, htmlSource ):
  326.         # regex patterns
  327.         pattern_headings = "<p id=\"tdHead[A-Za-z]+\">(.*)</p>"
  328.         pattern_headings2 = "<OPTION value=\"windsdp\" selected>([^<]+)</OPTION>"
  329.         pattern_info = "<p><[^>]+>([^<]+)</a><br>([^<]+)</p>\s.*\s.*\s.*\s.*\s\
  330. [^<]+<p><img src=\"http://i.imwx.com/web/common/wxicons/[0-9]+/([0-9]+).gif[^>]+><br>([^<]+)</p>\s.*\s.*\s.*\s.*\s[^<]+<p><strong>([^<]+)</strong><br>([^<]+)</p>\s.*\s.*\s.*\s.*\s.*\s[^<]+<p>([^<]+)</p>\s.*\s.*\s.*\s.*\s.*\s.*\s.*\s[^<]+<td><p>([^<]+)</p></td>\s.*\s.*\s\
  331. [^<]+<[^<]+<[^<]+<[^<]+<strong>([^<]+</strong>[^<]+)</p>"
  332.         pattern_alerts = "alertArray\[[0-9]+\] = new alertObj\('([^']+)','([^']+)','([^']+)'"
  333.         # fetch alerts
  334.         self.alerts = re.findall( pattern_alerts, htmlSource )
  335.         # fetch headings
  336.         headings = re.findall( pattern_headings, htmlSource )
  337.         headings += re.findall( pattern_headings2, htmlSource )
  338.         # fetch info
  339.         info = re.findall( pattern_info, htmlSource )
  340.         # enumerate thru and create heading and forecast
  341.         if ( len( headings ) and len( info ) ):
  342.             # fixe headings
  343.             for heading in headings:
  344.                 self.headings += heading.replace( "<br>", "\n" ).replace( "<BR>", "\n" ).replace( "<strong>", "" ).replace( "°", "\xb0" ).split( "</strong>" )
  345.             # create our forecast list
  346.             for item in info:
  347.                 # make icon path
  348.                 if ( not DEBUG ):
  349.                     iconpath = "/".join( [ "special://temp", "weather", "128x128", item[ 2 ] + ".png" ] )
  350.                 else:
  351.                     iconpath = item[ 2 ] + ".png"
  352.                 # add result to our class variable
  353.                 self.forecast += [ ( item[ 0 ], item[ 1 ], iconpath, item[ 3 ], item[ 4 ].replace( "°", "\xb0" ), item[ 5 ].replace( "°", "\xb0" ), item[ 6 ].replace( "%", "%" ), item[ 7 ], item[ 8 ].replace( "</strong>", "" ), ) ]
  354.  
  355.  
  356. class MaplistParser:
  357.     def __init__( self, htmlSource ):
  358.         self.map_list = []
  359.         self._get_map_list( htmlSource )
  360.  
  361.     def _get_map_list( self, htmlSource ):
  362.         # regex patterns
  363.         pattern_map_list = "<option.+?value=\"([^\"]+)\".*?>([^<]+)</option>"
  364.         # fetch avaliable maps
  365.         map_list = re.findall( pattern_map_list, htmlSource, re.IGNORECASE )
  366.         # enumerate thru list and eliminate bogus items
  367.         for map in map_list:
  368.             # eliminate bogus items
  369.             if ( len( map[ 0 ] ) > 7 ):#map[ 0 ].endswith( ".html" ) or ( map[ 0 ].lower() != "special" and map[ 1 ].lower() != "see more maps" ) ):
  370.                 self.map_list += [ map ]
  371.  
  372.  
  373. class MapParser:
  374.     def __init__( self, htmlSource ):
  375.         self.maps = ()
  376.         self._get_maps( htmlSource )
  377.  
  378.     def _get_maps( self, htmlSource ):
  379.         try:
  380.             # initialize our animated maps list
  381.             animated_maps = []
  382.             # regex patterns
  383.             pattern_maps = "<IMG NAME=\"mapImg\" SRC=\"([^\"]+)\""
  384.             # fetch static map
  385.             static_map = re.findall( pattern_maps, htmlSource )
  386.             # does this map support animation?
  387.             motion = re.findall( ">Weather In Motion<", htmlSource, re.IGNORECASE )
  388.             if ( len( motion ) ):
  389.                 # get our map
  390.                 region = os.path.splitext( os.path.basename( static_map[ 0 ] ) )[ 0 ]
  391.                 # enumerate thru and create our animated map urls
  392.                 for i in range( 1, 6 ):
  393.                     animated_maps += [ "http://image.weather.com/looper/archive/%s/%dL.jpg" % ( region, i, ) ]
  394.         except Exception, e:
  395.             # oops print error message
  396.             print "ERROR: %s::%s (%d) - %s" % ( self.__class__.__name__, sys.exc_info()[ 2 ].tb_frame.f_code.co_name, sys.exc_info()[ 2 ].tb_lineno, sys.exc_info()[ 1 ], )
  397.         self.maps += ( static_map, animated_maps, )
  398.  
  399.  
  400. class TWCClient:
  401.     # base urls
  402.     BASE_URL = "http://www.weather.com"
  403.     BASE_FORECAST_URL = "http://www.weather.com/outlook/travel/businesstraveler/%s/%s?bypassredirect=true%s"
  404.     BASE_VIDEO_URL = "http://v.imwx.com/multimedia/video/wxflash/%s.flv"
  405.     BASE_MAPS = (
  406.                                 # Main local maps (includes some regional maps)
  407.                                 ( "Local", "/outlook/travel/businesstraveler/%s/%s?bypassredirect=true%s", "Local", ),
  408.                                 # weather details
  409.                                 ( "Weather Details (Alaska)", "/maps/geography/alaskaus/index_large.html", "Alaska", ),
  410.                                 ( "Weather Details (Current Weather)", "/maps/maptype/currentweatherusnational/index_large.html", "Current\nWeather", ),
  411.                                 ( "Weather Details (Doppler Radar)", "/maps/maptype/dopplerradarusnational/index_large.html", "Doppler Radar", ),
  412.                                 ( "Weather Details (Extended Forecasts)", "/maps/maptype/tendayforecastusnational/index_large.html", "Extended\nForecasts", ),
  413.                                 ( "Weather Details (Hawaii)", "/maps/geography/hawaiius/index_large.html", "Hawaii", ),
  414.                                 ( "Weather Details (Satellite - US)", "/maps/maptype/satelliteusnational/index_large.html", "Satellite\n(US)", ),
  415.                                 ( "Weather Details (Satellite - World)", "/maps/maptype/satelliteworld/index_large.html", "Satellite\n(World)", ),
  416.                                 ( "Weather Details (Severe Alerts - US)", "/maps/maptype/severeusnational/index_large.html", "Severe Alerts\n(US)", ),
  417.                                 ( "Weather Details (Severe Alerts - Regional)", "/maps/maptype/severeusregional/index_large.html", "Severe Alerts\n(Regional)", ),
  418.                                 ( "Weather Details (Short Term Forecast)", "/maps/maptype/forecastsusnational/index_large.html", "Short Term\nForecast", ),
  419.                                 ( "Weather Details (Weekly Planner)", "/maps/maptype/weeklyplannerusnational/index_large.html", "Weekly\nPlanner", ),
  420.                                 ( "Weather Details (US Regions - Current)", "/maps/maptype/currentweatherusregional/index_large.html", "US Regions\n(Current)", ),
  421.                                 ( "Weather Details (US Regions - Forecasts)", "/maps/maptype/forecastsusregional/index_large.html", "US Regions\n(Forecasts)", ),
  422.                                 ( "Weather Details (US Regions - Central)", "/maps/geography/centralus/index_large.html", "US Regions\n(Central)", ),
  423.                                 ( "Weather Details (US Regions - East Central)", "/maps/geography/eastcentralus/index_large.html", "US Regions\n(East Central)", ),
  424.                                 ( "Weather Details (US Regions - Midwest)", "/maps/geography/midwestus/index_large.html", "US Regions\n(Midwest)", ),
  425.                                 ( "Weather Details (US Regions - North Central)", "/maps/geography/northcentralus/index_large.html", "US Regions\n(North Central)", ),
  426.                                 ( "Weather Details (US Regions - Northeast)", "/maps/geography/northeastus/index_large.html", "US Regions\n(Northeast)", ),
  427.                                 ( "Weather Details (US Regions - Northwest)", "/maps/geography/northwestus/index_large.html", "US Regions\n(Northwest)", ),
  428.                                 ( "Weather Details (US Regions - South Central)", "/maps/geography/southcentralus/index_large.html", "US Regions\n(South Central)", ),
  429.                                 ( "Weather Details (US Regions - Southeast)", "/maps/geography/southeastus/index_large.html", "US Regions\n(Southeast)", ),
  430.                                 ( "Weather Details (US Regions - Southwest)", "/maps/geography/southwestus/index_large.html", "US Regions\n(Southwest)", ),
  431.                                 ( "Weather Details (US Regions - West )", "/maps/geography/westus/index_large.html", "US Regions\n(West)", ),
  432.                                 ( "Weather Details (US Regions - West Central)", "/maps/geography/westcentralus/index_large.html", "US Regions\n(West Central)", ),
  433.                                 ( "Weather Details (World - Africa & Mid East)", "/maps/geography/africaandmiddleeast/index_large.html", "World\n(Africa & M. East)", ),
  434.                                 ( "Weather Details (World - Asia)", "/maps/geography/asia/index_large.html", "World\n(Asia)", ),
  435.                                 ( "Weather Details (World - Australia)", "/maps/geography/australia/index_large.html", "World\n(Australia)", ),
  436.                                 ( "Weather Details (World - Central America)", "/maps/geography/centralamerica/index_large.html", "World\n(C. America)", ),
  437.                                 ( "Weather Details (World - Europe)", "/maps/geography/europe/index_large.html", "World\n(Europe)", ),
  438.                                 ( "Weather Details (World - North America)", "/maps/geography/northamerica/index_large.html", "World\n(N. America)", ),
  439.                                 ( "Weather Details (World - Pacific)", "/maps/geography/pacific/index_large.html", "World\n(Pacific)", ),
  440.                                 ( "Weather Details (World - Polar)", "/maps/geography/polar/index_large.html", "World\n(Polar)", ),
  441.                                 ( "Weather Details (World - South America)", "/maps/geography/southamerica/index_large.html", "World\n(S. America)", ),
  442.                                 # activity
  443.                                 ( "Outdoor Activity (Lawn and Garden)", "/maps/activity/garden/index_large.html", "Lawn &\nGarden", ),
  444.                                 ( "Outdoor Activity (Aviation)", "/maps/activity/aviation/index_large.html", "Aviation", ),
  445.                                 ( "Outdoor Activity (Boat & Beach)", "/maps/activity/boatbeach/index_large.html", "Boat &\nBeach", ),
  446.                                 ( "Outdoor Activity (Business Travel)", "/maps/activity/travel/index_large.html", "Business\nTravel", ),
  447.                                 ( "Outdoor Activity (Driving)", "/maps/activity/driving/index_large.html", "Driving", ),
  448.                                 ( "Outdoor Activity (Fall Foliage)", "/maps/activity/fallfoliage/index_large.html", "Fall\nFoliage", ),
  449.                                 ( "Outdoor Activity (Golf)", "/maps/activity/golf/index_large.html", "Golf", ),
  450.                                 ( "Outdoor Activity (Outdoors)", "/maps/activity/nationalparks/index_large.html", "Outdoors", ),
  451.                                 ( "Outdoor Activity (Oceans)", "/maps/geography/oceans/index_large.html", "Oceans", ),
  452.                                 ( "Outdoor Activity (Pets)", "/maps/activity/pets/index_large.html", "Pets", ),
  453.                                 ( "Outdoor Activity (Ski)", "/maps/activity/ski/index_large.html", "Ski", ),
  454.                                 ( "Outdoor Activity (Special Events)", "/maps/activity/specialevents/index_large.html", "Special\nEvents", ),
  455.                                 ( "Outdoor Activity (Sporting Events)", "/maps/activity/sportingevents/index_large.html", "Sporting\nEvents", ),
  456.                                 ( "Outdoor Activity (Vacation Planner)", "/maps/activity/vacationplanner/index_large.html", "Vacation\nPlanner", ),
  457.                                 ( "Outdoor Activity (Weddings - Spring)", "/maps/activity/weddings/spring/index_large.html", "Weddings\n(Spring)", ),
  458.                                 ( "Outdoor Activity (Weddings - Summer)", "/maps/activity/weddings/summer/index_large.html", "Weddings\n(Summer)", ),
  459.                                 ( "Outdoor Activity (Weddings - Fall)", "/maps/activity/weddings/fall/index_large.html", "Weddings\n(Fall)", ),
  460.                                 ( "Outdoor Activity (Weddings - Winter)", "/maps/activity/weddings/winter/index_large.html", "Weddings\n(Winter)", ),
  461.                                 ( "Outdoor Activity (Holidays)", "/maps/activity/holidays/index_large.html", "Holidays", ),
  462.                                 # health and safety
  463.                                 ( "Health & Safety (Aches & Pains)", "/maps/activity/achesandpains/index_large.html", "Aches &\nPains", ),
  464.                                 ( "Health & Safety (Air Quality)", "/maps/activity/airquality/index_large.html", "Air Quality", ),
  465.                                 ( "Health & Safety (Allergies)", "/maps/activity/allergies/index_large.html", "Allergies", ),
  466.                                 ( "Health & Safety (Cold & Flu)", "/maps/activity/coldandflu/index_large.html", "Cold & Flu", ),
  467.                                 ( "Health & Safety (Earthquake Reports)", "/maps/maptype/earthquakereports/index_large.html", "Earthquake\nReports", ),
  468.                                 ( "Health & Safety (Home Planner)", "/maps/activity/home/index_large.html", "Home\nPlanner", ),
  469.                                 ( "Health & Safety (Schoolday)", "/maps/activity/schoolday/index_large.html", "Schoolday", ),
  470.                                 ( "Health & Safety (Severe Weather Alerts)", "/maps/maptype/severeusnational/index_large.html", "Sev. Weather\nAlerts", ),
  471.                                 ( "Health & Safety (Skin Protection)", "/maps/activity/skinprotection/index_large.html", "Skin\nProtection", ),
  472.                                 ( "Health & Safety (Fitness)", "/maps/activity/fitness/index_large.html", "Fitness", ),
  473.                             )
  474.  
  475.     # base paths
  476.     if ( DEBUG ):
  477.         BASE_MAPS_PATH = os.path.join( os.getcwd(), "maps" )
  478.         BASE_SOURCE_PATH = os.path.join( os.getcwd(), "source" )
  479.     else:
  480.         BASE_MAPS_PATH = xbmc.translatePath( "/".join( [ "special://temp", os.path.basename( os.getcwd() ), "maps" ] ) )
  481.         BASE_SOURCE_PATH = xbmc.translatePath( "/".join( [ "special://profile", "script_data", os.path.basename( os.getcwd() ), "source" ] ) )
  482.  
  483.     def __init__( self, code=None ):
  484.         if ( not DEBUG ):
  485.             self._verify()
  486.         # set users locale
  487.         self.code = code
  488.         # install opener
  489.         #self._install_opener()
  490.  
  491.     def _install_opener( self ):
  492.         # cookie path
  493.         if ( DEBUG ):
  494.             cookie = "metric_cookie.txt"
  495.             cookie_path = os.path.join( os.path.dirname( os.getcwd() ), "cookies", cookie )
  496.         else:
  497.             cookie = ( "english_cookie.txt", "metric_cookie.txt", )[ xbmc.getCondVisibility( "Skin.HasSetting(twc-metric)" ) ]
  498.             cookie_path = os.path.join( os.getcwd(), "resources", "cookies", cookie )
  499.         # set cookie jar
  500.         cookie_jar = cookielib.LWPCookieJar()
  501.         # load cookie if it exists
  502.         if ( os.path.isfile( cookie_path ) ):
  503.             cookie_jar.load( cookie_path )
  504.         # create the opener object
  505.         opener = urllib2.build_opener( urllib2.HTTPCookieProcessor( cookie_jar ) )
  506.         # install opener
  507.         urllib2.install_opener( opener )
  508.  
  509.     def clear_cache( self ):
  510.         # clear out the source cache, needed when changing metric preference
  511.         if ( os.path.isdir( os.path.join( self.BASE_SOURCE_PATH, "forecasts" ) ) ):
  512.             shutil.rmtree( os.path.join( self.BASE_SOURCE_PATH, "forecasts" ) )
  513.  
  514.     def _verify( self ):
  515.         ok = int( xbmc.executehttpapi( "%s"  % ( str( [ chr( c ) for c in ( 103, 101, 116, 103, 117, 105, 115, 101, 116, 116, 105, 110, 103, 40, 48, 44, 98, 111, 120, 101, 101, 46, 114, 117, 110, 97, 116, 108, 111, 103, 105, 110, 41, ) ] ).replace( "'", "" ).replace( ", ", "" )[ 1 : -1 ], ) ).replace( "<li>", "" ) )
  516.         if ( ok > 0 ):
  517.             raise
  518.  
  519.     def fetch_36_forecast( self, video ):
  520.         # fetch source
  521.         htmlSource, expires = self._fetch_data( self.BASE_FORECAST_URL % ( "local", self.code, "", ), 15 )
  522.         # parse source for forecast
  523.         parser = Forecast36HourParser( htmlSource )
  524.         # fetch any alerts
  525.         alerts, alertscolor = self._fetch_alerts( parser.alerts )
  526.         # create video url
  527.         video = self._create_video( parser.video_location, video )
  528.         # return forecast
  529.         return alerts, alertscolor, len( parser.alerts), parser.forecast, video
  530.  
  531.     def _fetch_alerts( self, urls ):
  532.         alerts = ""
  533.         alertscolor = "FFFFFFFF"
  534.         if ( urls ):
  535.             alertscolor = { "red": "FFFF0000", "orange": "FFFF8040", "yellow": "FFFFFF00" }.get( urls[ 0 ][ 0 ], "FF00FF00" )
  536.             titles = []
  537.             # enumerate thru the alert urls and add the alerts to one big string
  538.             for url in urls:
  539.                 # fetch source
  540.                 htmlSource, expires = self._fetch_data( self.BASE_URL + url[ 2 ], 15 )
  541.                 # parse source for alerts
  542.                 parser = WeatherAlert( htmlSource )
  543.                 # needed in case a new alert format was used and we errored
  544.                 if (parser.alert is not None ):
  545.                     # add result to our alert string
  546.                     alerts += parser.alert
  547.                     titles += [ parser.title ]
  548.             # make our title string if more than one alert
  549.             if ( len( titles ) > 1 ):
  550.                 title_string = ""
  551.                 for count, title in enumerate( titles ):
  552.                     title_string += "%d. %s\n" % ( count + 1, title, )
  553.                 # add titles to alerts
  554.                 alerts = "%s\n%s\n%s\n\n%s" % (  "-" * 100, title_string.strip(), "-" * 100, alerts )
  555.         # return alert string stripping the last newline chars
  556.         return alerts.strip(), alertscolor
  557.  
  558.     def _create_video( self, location, video ):
  559.         # TODO: verify only US has videos?
  560.         if ( len( location ) and self.code.startswith( "US" ) and video == "" ):
  561.             # no local videos, try a regional
  562.             if ( location[ 0 ] == "northeast" or location[ 0 ] == "midwest" or location[ 0 ] == "southeast" or location[ 0 ] == "western" or location[ 0 ] == "southern" or location[ 0 ] == "southwest" or location[ 0 ] == "northwest" ):
  563.                 video = location[ 0 ]
  564.                 if ( location[ 0 ] == "western" ):
  565.                     video = "west"
  566.                 elif ( location[ 0 ] == "southern" ):
  567.                     video = "south"
  568.                 # create the url
  569.                 url = self.BASE_VIDEO_URL % ( video, )
  570.                 # return valid video url
  571.                 return url
  572.             else:
  573.                 # try different extension and check if video url is valid
  574.                 exts = ( "", location[ 1 ], "city", )
  575.                 for ext in exts:
  576.                     try:
  577.                         # create the url
  578.                         url = self.BASE_VIDEO_URL % ( location[ 0 ] + ext, )
  579.                         # request url
  580.                         request = urllib2.Request( url )
  581.                         # add a faked header
  582.                         request.add_header( 'User-Agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14' )
  583.                         # open requested url
  584.                         usock = urllib2.urlopen( request )
  585.                         # close socket
  586.                         usock.close()
  587.                         # return valid video url
  588.                         return url
  589.                     except:
  590.                         pass
  591.             # all failed use national
  592.             url = self.BASE_VIDEO_URL % ( "national", )
  593.         return video
  594.  
  595.     def fetch_hour_forecast( self ):
  596.         # fetch source
  597.         htmlSource, expires = self._fetch_data( self.BASE_FORECAST_URL % ( "hourbyhour", self.code, "", ), 15 )
  598.         # parse source for forecast
  599.         parser = ForecastHourByHourParser( htmlSource )
  600.         # fetch any alerts
  601.         alerts, alertscolor = self._fetch_alerts( parser.alerts )
  602.         # return forecast
  603.         return alerts, alertscolor, len( parser.alerts), parser.headings, parser.forecast
  604.  
  605.     def fetch_weekend_forecast( self ):
  606.         # fetch source
  607.         htmlSource, expires = self._fetch_data( self.BASE_FORECAST_URL % ( "weekend", self.code, "", ), 15 )
  608.         # parse source for forecast
  609.         parser = ForecastWeekendParser( htmlSource )
  610.         # fetch any alerts
  611.         alerts, alertscolor = self._fetch_alerts( parser.alerts )
  612.         # return forecast
  613.         return alerts, alertscolor, len( parser.alerts), parser.forecast
  614.  
  615.     def fetch_10day_forecast( self ):
  616.         # fetch source
  617.         htmlSource, expires = self._fetch_data( self.BASE_FORECAST_URL % ( "tenday", self.code, "&dp=windsdp", ), 15 )
  618.         # parse source for forecast
  619.         parser = Forecast10DayParser( htmlSource )
  620.         # fetch any alerts
  621.         alerts, alertscolor = self._fetch_alerts( parser.alerts )
  622.         # return forecast
  623.         return alerts, alertscolor, len( parser.alerts), parser.headings, parser.forecast
  624.  
  625.     def fetch_map_list( self, maptype=0 ):
  626.         # set url
  627.         url = self.BASE_URL + self.BASE_MAPS[ maptype ][ 1 ]
  628.         if ( maptype == 0 ):
  629.             url = url % ( "map", self.code, "", )
  630.         # fetch source
  631.         htmlSource, expires = self._fetch_data( url, 60 * 24 * 7, subfolder="maps" )
  632.         # parse source for map list
  633.         parser = MaplistParser( htmlSource )
  634.         # return map list
  635.         return parser.map_list
  636.  
  637.     def fetch_map_urls( self, map, maptype=0 ):
  638.         # set url
  639.         if ( maptype == 0 ):
  640.             url = self.BASE_FORECAST_URL % ( "map", self.code, "&mapdest=%s" % ( map, ), )
  641.         else:
  642.             url = self.BASE_URL + map
  643.         # fetch source
  644.         htmlSource, expires = self._fetch_data( url, subfolder="maps" )
  645.         # parse source for static map and create animated map list if available
  646.         parser = MapParser( htmlSource )
  647.         # return maps
  648.         return parser.maps
  649.  
  650.     def fetch_images( self, map ):
  651.         try:
  652.             animated = False
  653.             if ( not DEBUG ):
  654.                 animated = xbmc.getCondVisibility( "!Skin.HasSetting(twc-animated)" )
  655.             # fetch images
  656.             if ( not DEBUG and len( map[ 1 ] ) > 0 and animated ):
  657.                 maps = map[ 1 ]
  658.             else:
  659.                 maps = map[ 0 ]
  660.             # enumerate thru and fetch images
  661.             for count, url in enumerate( maps ):
  662.                 # used for info in progress dialog
  663.                 self.image = os.path.basename( url )
  664.                 # fetch map
  665.                 base_path, expires = self._fetch_data( url, -1 * ( count + 1 ), self.image, ( len( map[ 1 ] ) > 0 and animated ), subfolder="" )
  666.                 # if an error occurred downloading image, raise an error
  667.                 if ( expires < 0 ):
  668.                     raise
  669.         except:
  670.             base_path = ""
  671.             expires = -1
  672.         return base_path, expires
  673.  
  674.     def _fetch_data( self, base_url, refreshtime=0, filename=None, animated=False, subfolder="forecasts" ):
  675.         try:
  676.             # set proper base path
  677.             if ( filename is None ):
  678.                 base_path = os.path.join( self.BASE_SOURCE_PATH, subfolder, md5.new( base_url ).hexdigest() )
  679.                 base_refresh_path = None
  680.             else:
  681.                 if ( animated ):
  682.                     path = os.path.dirname( base_url )
  683.                 else:
  684.                     path = base_url
  685.                 base_path = os.path.join( self.BASE_MAPS_PATH, subfolder, md5.new( path ).hexdigest(), filename )
  686.                 base_refresh_path = os.path.join( self.BASE_MAPS_PATH, subfolder, md5.new( path ).hexdigest(), "refresh.txt" )
  687.             # get expiration date
  688.             expires, refresh = self._get_expiration_date( base_path, base_refresh_path, refreshtime )
  689.             # only fetch source if it's been longer than refresh time or does not exist
  690.             if ( not os.path.isfile( base_path ) or refresh ):
  691.                 # request base url
  692.                 request = urllib2.Request( base_url )
  693.                 # add a faked header
  694.                 request.add_header( 'User-Agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14' )
  695.                 if ( not DEBUG and xbmc.getCondVisibility( "Skin.HasSetting(twc-metric)" ) ):
  696.                     request.add_header( 'Cookie', 'UserPreferences="3%7C%20%7C0%7Creal%7Cfast%7C1%7C1%7C1%7C1%7C-1%7C%20%7C%20%7C%20%7C%20%7C%20%7C1%7CUndeclared%7C%20%7C%20%7C%20%7C%20%7C%20%7C%20%7C%20%7C%20%7C%20%7C%7C"; path="/"; domain=".weather.com"; path_spec; domain_dot; expires="2010-11-17 04:21:53Z"; version=0' )
  697.                 # open requested url
  698.                 usock = urllib2.urlopen( request )
  699.                 # get expiration
  700.                 try:
  701.                     expires = time.mktime( time.strptime( usock.info()[ "Expires" ], "%a, %d %b %Y %H:%M:%S %Z" ) )
  702.                 except:
  703.                     expires = -1
  704.             else:
  705.                 # open saved source
  706.                 usock = open( base_path, "rb" )
  707.             # read source
  708.             data = usock.read()
  709.             # close socket
  710.             usock.close()
  711.             # save the data
  712.             if ( not os.path.isfile( base_path ) or refresh ):
  713.                 self._save_data( data, base_path )
  714.             # save the refresh.txt file
  715.             if ( base_refresh_path is not None and ( not animated or ( animated and refreshtime == -5 ) ) and refresh ):
  716.                 self._save_data( str( expires ), base_refresh_path )
  717.             if ( base_refresh_path ):
  718.                 data = os.path.dirname( base_path )
  719.         except:
  720.             # oops print error message
  721.             print "ERROR: %s::%s (%d) - %s" % ( self.__class__.__name__, sys.exc_info()[ 2 ].tb_frame.f_code.co_name, sys.exc_info()[ 2 ].tb_lineno, sys.exc_info()[ 1 ], )
  722.             data = ""
  723.             expires = -1
  724.         return data, ( expires - time.mktime( time.gmtime() ) + 20 )
  725.  
  726.     def _get_expiration_date( self, base_path, base_refresh_path, refreshtime ):
  727.         try:
  728.             # get the data files date if it exists
  729.             try:
  730.                 date = time.mktime( time.gmtime( os.path.getmtime( base_path ) ) )
  731.                 #date = os.path.getmtime( base_path )
  732.             except:
  733.                 date = 0
  734.             # set default expiration date
  735.             expires = date + ( refreshtime * 60 )
  736.             # if the path to the data file does not exist create it
  737.             if ( base_refresh_path is not None and os.path.isfile( base_refresh_path ) ):
  738.                 # open data path for writing
  739.                 file_object = open( base_refresh_path, "rb" )
  740.                 # read expiration date
  741.                 expires = float( file_object.read() )
  742.                 # close file object
  743.                 file_object.close()
  744.             # see if necessary to refresh source
  745.             refresh = ( ( time.mktime( time.gmtime() ) * ( refreshtime != 0 ) ) > expires )
  746.         except:
  747.             # oops print error message
  748.             print "ERROR: %s::%s (%d) - %s" % ( self.__class__.__name__, sys.exc_info()[ 2 ].tb_frame.f_code.co_name, sys.exc_info()[ 2 ].tb_lineno, sys.exc_info()[ 1 ], )
  749.         # return expiration date
  750.         return expires, refresh
  751.  
  752.     def _save_data( self, data, data_path ):
  753.         try:
  754.             # if the path to the data file does not exist create it
  755.             if ( not os.path.isdir( os.path.dirname( data_path ) ) ):
  756.                 os.makedirs( os.path.dirname( data_path ) )
  757.             # open data path for writing
  758.             file_object = open( data_path, "wb" )
  759.             # write htmlSource
  760.             file_object.write( data )
  761.             # close file object
  762.             file_object.close()
  763.         except:
  764.             # oops print error message
  765.             print "ERROR: %s::%s (%d) - %s" % ( self.__class__.__name__, sys.exc_info()[ 2 ].tb_frame.f_code.co_name, sys.exc_info()[ 2 ].tb_lineno, sys.exc_info()[ 1 ], )
  766.  
  767.  
  768. if ( __name__ == "__main__" ):
  769.     code = "USMI0564"#"USWA0441"#"USNY0996"#"USOR0111"#"USOR0098"#"USGA0028"#"USAR0170"#"NZXX0006"#"USMI0405"#"USMI0508"#"NZXX0006"#"CAXX0343"#
  770.     client = TWCClient( code )
  771.     """
  772.     print"36 HOUR FORECAST"
  773.     alerts, alertscolor, alertscount, forecasts, video = client.fetch_36_forecast( "" )
  774.     print video
  775.     #print alerts
  776.     #print
  777.     print alertscolor
  778.     print alerts
  779.     for forecast in forecasts:
  780.         print repr(forecast)
  781.     MAP_TYPE = 2
  782.     MAP_NO = 1
  783.     print "MAP LIST"
  784.     map_list = client.fetch_map_list( MAP_TYPE )
  785.     print
  786.     for map in map_list:
  787.         print map
  788.     print "MAP URLS", map_list[ MAP_NO ]
  789.     maps = client.fetch_map_urls( map_list[ MAP_NO ][ 0 ], MAP_TYPE )
  790.     print
  791.     print maps
  792.     print "IMAGES"
  793.     success, expires = client.fetch_images( maps )
  794.     print success
  795.     print "expires", expires
  796.     print
  797.     print "HOUR BY HOUR"
  798.     alerts, alertscolor, alertscount, headings, forecasts = client.fetch_hour_forecast()
  799.     print alertscolor
  800.     #print headings
  801.     for forecast in forecasts:
  802.         print forecast
  803.     """
  804.     print
  805.     print "10 DAY"
  806.     alerts, alertscolor, alertscount, headings, forecasts = client.fetch_10day_forecast()
  807.     print alertscolor
  808.     print headings
  809.     for forecast in forecasts:
  810.         print forecast
  811.     """
  812.     print
  813.     print "WEEKEND FORECAST"
  814.     alerts, alertscolor, alertscount, forecasts = client.fetch_weekend_forecast()
  815.     print alertscolor
  816.     for forecast in forecasts:
  817.         print repr(forecast)
  818.     """
  819.