Advertisement
Guest User

default.py

a guest
May 29th, 2013
689
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 25.72 KB | None | 0 0
  1. # * This Program is free software; you can redistribute it and/or modify
  2. # * it under the terms of the GNU General Public License as published by
  3. # * the Free Software Foundation; either version 2, or (at your option)
  4. # * any later version.
  5. # *
  6. # * This Program is distributed in the hope that it will be useful,
  7. # * but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. # * GNU General Public License for more details.
  10. # *
  11. # * You should have received a copy of the GNU General Public License
  12. # * along with XBMC; see the file COPYING. If not, write to
  13. # * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  14. # * http://www.gnu.org/copyleft/gpl.html
  15. # *
  16.  
  17. import os, sys, urllib, urllib2, socket
  18. import xbmc, xbmcvfs, xbmcgui, xbmcaddon
  19. import CommonFunctions
  20. import re
  21. import ftplib
  22. import shutil
  23. import time
  24. import datetime
  25. # Minimal code to import bossanova808 common code
  26. ADDON = xbmcaddon.Addon()
  27. CWD = ADDON.getAddonInfo('path')
  28. RESOURCES_PATH = xbmc.translatePath( os.path.join( CWD, 'resources' ))
  29. LIB_PATH = xbmc.translatePath(os.path.join( RESOURCES_PATH, "lib" ))
  30. sys.path.append( LIB_PATH )
  31. from b808common import *
  32.  
  33. #import the tables that map conditions to icon number and short days to long days
  34. from utilities import *
  35.  
  36. #parseDOM setup
  37. common = CommonFunctions
  38. common.plugin = ADDONNAME + "-" + VERSION
  39. dbg = False # Set to false if you don't want debugging
  40. dbglevel = 3
  41.  
  42. #Handy Strings
  43. WEATHER_WINDOW = xbmcgui.Window(12600)
  44. WEATHERZONE_URL = 'http://www.weatherzone.com.au'
  45. FTPSTUB = "ftp://anonymous:someone%40somewhere.com@ftp.bom.gov.au//anon/gen/radar_transparencies/"
  46. HTTPSTUB = "http://www.bom.gov.au/products/radar_transparencies/"
  47. RADAR_BACKGROUNDS_PATH = ""
  48. LOOP_IMAGES_PATH = ""
  49.  
  50.  
  51.  
  52. ################################################################################
  53. # blank out all the window properties
  54.  
  55. def clearProperties():
  56. log("Clearing Properties")
  57. try:
  58. setProperty(WEATHER_WINDOW, 'Weather.IsFetched')
  59. setProperty(WEATHER_WINDOW, 'Radar')
  60. setProperty(WEATHER_WINDOW, 'Video.1')
  61.  
  62. #now set all the XBMC current weather properties
  63. setProperty(WEATHER_WINDOW, 'Current.Condition')
  64. setProperty(WEATHER_WINDOW, 'Current.ConditionLong')
  65. setProperty(WEATHER_WINDOW, 'Current.Temperature')
  66. setProperty(WEATHER_WINDOW, 'Current.Wind')
  67. setProperty(WEATHER_WINDOW, 'Current.WindDirection')
  68. setProperty(WEATHER_WINDOW, 'Current.Humidity')
  69. setProperty(WEATHER_WINDOW, 'Current.FeelsLike')
  70. setProperty(WEATHER_WINDOW, 'Current.DewPoint')
  71. setProperty(WEATHER_WINDOW, 'Current.UVIndex')
  72. setProperty(WEATHER_WINDOW, 'Current.OutlookIcon')
  73. setProperty(WEATHER_WINDOW, 'Current.FanartCode')
  74.  
  75. #and all the properties for the forecast
  76. for count in range(0,7):
  77. setProperty(WEATHER_WINDOW, 'Day%i.Title' % count)
  78. setProperty(WEATHER_WINDOW, 'Day%i.HighTemp' % count)
  79. setProperty(WEATHER_WINDOW, 'Day%i.LowTemp' % count)
  80. setProperty(WEATHER_WINDOW, 'Day%i.Outlook' % count)
  81. setProperty(WEATHER_WINDOW, 'Day%i.OutlookIcon' % count)
  82. setProperty(WEATHER_WINDOW, 'Day%i.FanartCode' % count)
  83. setProperty(WEATHER_WINDOW, 'Daily.%i.ShortDate' % count)
  84. except Exception as inst:
  85. log("********** OzWeather Couldn't clear all the properties, sorry!!", inst)
  86.  
  87.  
  88. ################################################################################
  89. # set the location and radar code properties
  90.  
  91. def refresh_locations():
  92.  
  93. log("Refreshing locations from settings")
  94. location_set1 = ADDON.getSetting('Location1')
  95. location_set2 = ADDON.getSetting('Location2')
  96. location_set3 = ADDON.getSetting('Location3')
  97. locations = 0
  98. if location_set1 != '':
  99. locations += 1
  100. setProperty(WEATHER_WINDOW, 'Location1', location_set1)
  101. else:
  102. setProperty(WEATHER_WINDOW, 'Location1', '')
  103. if location_set2 != '':
  104. locations += 1
  105. setProperty(WEATHER_WINDOW, 'Location2', location_set2)
  106. else:
  107. setProperty(WEATHER_WINDOW, 'Location2', '')
  108. if location_set3 != '':
  109. locations += 1
  110. setProperty(WEATHER_WINDOW, 'Location3', location_set3)
  111. else:
  112. setProperty(WEATHER_WINDOW, 'Location3', '')
  113.  
  114. setProperty(WEATHER_WINDOW, 'Locations', str(locations))
  115.  
  116. log("Refreshing radar locations from settings")
  117. radar_set1 = ADDON.getSetting('Radar1')
  118. radar_set2 = ADDON.getSetting('Radar2')
  119. radar_set3 = ADDON.getSetting('Radar3')
  120. radars = 0
  121. if radar_set1 != '':
  122. radars += 1
  123. setProperty(WEATHER_WINDOW, 'Radar1', radar_set1)
  124. else:
  125. setProperty(WEATHER_WINDOW, 'Radar1', '')
  126. if radar_set2 != '':
  127. radars += 1
  128. setProperty(WEATHER_WINDOW, 'Radar2', radar_set2)
  129. else:
  130. setProperty(WEATHER_WINDOW, 'Radar2', '')
  131. if radar_set3 != '':
  132. radars += 1
  133. setProperty(WEATHER_WINDOW, 'Radar3', radar_set3)
  134. else:
  135. setProperty(WEATHER_WINDOW, 'Radar3', '')
  136.  
  137. setProperty(WEATHER_WINDOW, 'Radars', str(locations))
  138.  
  139.  
  140. ################################################################################
  141. # The main forecast retrieval function
  142. # Does either a basic forecast or a more extended forecast with radar etc.
  143. # if the appropriate setting is set
  144.  
  145. def forecast(url, radarCode):
  146. log("Called forecast()")
  147.  
  148. #pull in the paths
  149. global RADAR_BACKGROUNDS_PATH, LOOP_IMAGES_PATH
  150.  
  151. #make sure updates look neat
  152. clearProperties()
  153.  
  154. #check if we're doing jsut a basic data update or data and images
  155. extendedFeatures = ADDON.getSetting('ExtendedFeaturesToggle')
  156. log("Getting weather from " + url + ", Extended features = " + str(extendedFeatures))
  157.  
  158. #ok now we want to build the radar images first, looks neater
  159. if extendedFeatures == "true":
  160. log("Extended feature powers -> activate!")
  161.  
  162. #strings to store the paths we will use
  163. RADAR_BACKGROUNDS_PATH = xbmc.translatePath("special://profile/addon_data/weather.ozweather/radarbackgrounds/" + radarCode + "/");
  164. LOOP_IMAGES_PATH = xbmc.translatePath("special://profile/addon_data/weather.ozweather/currentloop/" + radarCode + "/");
  165.  
  166. log("Build radar images")
  167. buildImages(radarCode)
  168. radar = ""
  169. radar = ADDON.getSetting('Radar%s' % sys.argv[1])
  170. setProperty(WEATHER_WINDOW, 'Radar', radar)
  171.  
  172. #and now get and set all the temperatures etc.
  173. log("Get the forecast data from weatherzone.com.au: " + url)
  174. try:
  175. data = common.fetchPage({"link":url})
  176. except Exception as inst:
  177. log("Error, couldn't retrieve weather page from WeatherZone - error: ", inst)
  178. if data != '':
  179. propertiesPDOM(data["content"], extendedFeatures)
  180. else:
  181. log("Weatherzone returned empty data??!")
  182.  
  183. ################################################################################
  184. # Downloads a radar background given a BOM radar code like IDR023 & filename
  185. # Converts the image from indexed colour to RGBA colour
  186.  
  187. def downloadBackground(radarCode, fileName):
  188. global RADAR_BACKGROUNDS_PATH, LOOP_IMAGES_PATH
  189.  
  190. outFileName = fileName
  191.  
  192. #the legend file doesn't have the radar code int he filename
  193. if fileName == "IDR.legend.0.png":
  194. outFileName = "legend.png"
  195. else:
  196. #append the radar code
  197. fileName = radarCode + "." + fileName
  198.  
  199. #are the backgrounds stale?
  200. if xbmcvfs.exists( RADAR_BACKGROUNDS_PATH + outFileName ):
  201. fileCreation = os.path.getmtime( RADAR_BACKGROUNDS_PATH + outFileName)
  202. now = time.time()
  203. weekAgo = now - 7*60*60*24 # Number of seconds in a week
  204. #log ("filec " + str(fileCreation) + " dayAgo " + str(dayAgo))
  205. if fileCreation < weekAgo:
  206. log("Background older than one week - let's refresh - " + outFileName)
  207. os.remove(RADAR_BACKGROUNDS_PATH + outFileName)
  208.  
  209. #download the backgrounds only if we don't have them yet
  210. if not xbmcvfs.exists( RADAR_BACKGROUNDS_PATH + outFileName ):
  211.  
  212. log("Downloading missing background image...." + outFileName)
  213.  
  214. #import PIL only if we need it so the add on can be run for data only
  215. #on platforms without PIL
  216. log("Importing PIL as extra features are activated.")
  217. from PIL import Image
  218. #ok get ready to retrieve some images
  219. image = urllib.URLopener()
  220.  
  221. #the legend image showing the rain scale
  222. try:
  223. imageFileIndexed = RADAR_BACKGROUNDS_PATH + "idx." + fileName
  224. imageFileRGB = RADAR_BACKGROUNDS_PATH + outFileName
  225. try:
  226. image.retrieve(FTPSTUB + fileName, imageFileIndexed )
  227. except:
  228. log("ftp failed, let's try http instead...")
  229. try:
  230. image.retrieve(HTTPSTUB + fileName, imageFileIndexed )
  231. except:
  232. log("http failed too.. sad face :( ")
  233. #jump to the outer exception
  234. raise
  235. #got here, we must have an image
  236. log("Downloaded background texture...now converting from indexed to RGB - " + fileName)
  237. im = Image.open( imageFileIndexed )
  238. rgbimg = im.convert('RGBA')
  239. rgbimg.save(imageFileRGB, "PNG")
  240. os.remove(imageFileIndexed)
  241. except Exception as inst:
  242. log("Error, couldn't retrieve " + fileName + " - error: ", inst)
  243. #ok try and get it via http instead?
  244. #try REALLY hard to get at least the background image
  245. try:
  246. #ok so something is wrong with image conversion - probably a PIL issue, so let's just get a minimal BG image
  247. if "background.png" in fileName:
  248. if not '00004' in fileName:
  249. image.retrieve(FTPSTUB + fileName, imageFileRGB )
  250. else:
  251. #national radar loop uses a different BG for some reason...
  252. image.retrieve(FTPSTUB + 'IDE00035.background.png', imageFileRGB )
  253. except Exception as inst2:
  254. log("No, really, -> Error, couldn't retrieve " + fileName + " - error: ", inst2)
  255.  
  256.  
  257. def prepareBackgrounds(radarCode):
  258.  
  259. log("Called prepareBackgrounds()")
  260.  
  261. downloadBackground(radarCode, "IDR.legend.0.png")
  262. downloadBackground(radarCode, "background.png")
  263. downloadBackground(radarCode, "locations.png")
  264. downloadBackground(radarCode, "range.png")
  265. downloadBackground(radarCode, "topography.png")
  266. downloadBackground(radarCode, "catchments.png")
  267.  
  268.  
  269. ################################################################################
  270. # Builds the radar images given a BOM radar code like IDR023
  271. # the background images are permanently cached (user can manually delete if
  272. # they need to)
  273. # the radar images are downloaded with each update (~60kb each time)
  274.  
  275. def buildImages(radarCode):
  276.  
  277. log("Called buildImages with radarCode: " + radarCode)
  278.  
  279. #remove the temporary files - we only want fresh radar files
  280. #this results in maybe ~60k used per update.
  281. if xbmcvfs.exists( LOOP_IMAGES_PATH ):
  282. log("Removing previous radar files")
  283. shutil.rmtree( LOOP_IMAGES_PATH , ignore_errors=True)
  284.  
  285. #we need make the directories to store stuff if they don't exist
  286. if not xbmcvfs.exists( RADAR_BACKGROUNDS_PATH ):
  287. os.makedirs( RADAR_BACKGROUNDS_PATH )
  288. if not xbmcvfs.exists( LOOP_IMAGES_PATH ):
  289. os.makedirs( LOOP_IMAGES_PATH )
  290.  
  291. log("Prepare the backgrounds if necessary...")
  292. prepareBackgrounds(radarCode)
  293.  
  294. #Ok so we have the backgrounds...now it is time get the loop
  295. #first we retrieve a list of the available files via ftp
  296. #ok get ready to retrieve some images
  297.  
  298. log("Download the radar loop")
  299. image = urllib.URLopener()
  300. files = []
  301.  
  302. log("Log in to BOM FTP")
  303. ftp = ftplib.FTP("ftp.bom.gov.au")
  304. ftp.login("anonymous", "anonymous@anonymous.org")
  305. ftp.cwd("/anon/gen/radar/")
  306.  
  307. log("Get files list")
  308. #connected, so let's get the list
  309. try:
  310. files = ftp.nlst()
  311. except ftplib.error_perm, resp:
  312. if str(resp) == "550 No files found":
  313. log("No files in BOM ftp directory!")
  314. else:
  315. log("Something wrong in the ftp bit of radar images")
  316.  
  317. log("Download the files...")
  318. #ok now we need just the matching radar files...
  319. loopPicNames = []
  320. for f in files:
  321. if radarCode in f:
  322. loopPicNames.append(f)
  323.  
  324. #download the actual images, might as well get the longest loop they have
  325. for f in loopPicNames:
  326. #ignore the composite gif...
  327. if f[-3:] == "png":
  328. imageToRetrieve = "ftp://anonymous:someone%40somewhere.com@ftp.bom.gov.au//anon/gen/radar/" + f
  329. log("Retrieving radar image: " + imageToRetrieve)
  330. try:
  331. image.retrieve(imageToRetrieve, LOOP_IMAGES_PATH + "/" + f )
  332. except Exception as inst:
  333. log("Failed to retrieve radar image: " + imageToRetrieve + ", oh well never mind!", inst )
  334.  
  335.  
  336. ################################################################################
  337. # this is the main scraper function that uses parseDOM to scrape the
  338. # data from the weatherzone site.
  339.  
  340. def propertiesPDOM(page, extendedFeatures):
  341.  
  342. log("Use PDOM to pull weather forecast data")
  343. ####CURRENT DATA
  344. try:
  345. #pull data from the current observations table
  346. ret = common.parseDOM(page, "div", attrs = { "class": "details_lhs" })
  347. observations = common.parseDOM(ret, "td", attrs = { "class": "hilite bg_yellow" })
  348. #Observations now looks like - ['18.3&deg;C', '4.7&deg;C', '18.3&deg;C', '41%', 'SSW 38km/h', '48km/h', '1015.7hPa', '-', '0.0mm / -']
  349. log("Observations Retrieved: " + str(observations))
  350. temperature = observations[0].strip( '&deg;C' )
  351. log(" TEMP " + str(temperature))
  352. dewPoint = observations[1].strip( '&deg;C' )
  353. feelsLike = observations[2].strip( '&deg;C')
  354. humidity = observations[3].strip( '%')
  355. windTemp = observations[4].partition(' ');
  356. windDirection = windTemp[0]
  357. windSpeed = windTemp[2].strip( 'km/h')
  358. #there's no UV so we get that from the forecast, see below
  359. except Exception as inst:
  360. log("********** OzWeather Couldn't Parse Data, sorry!!", inst)
  361. setProperty(WEATHER_WINDOW, 'Current.Condition', "Error w. Current Data!")
  362. setProperty(WEATHER_WINDOW, 'Current.ConditionLong', "Error - Couldn't retrieve current weather data from WeatherZone - this is usually just a temporary problem with their server and with any luck they'll fix it soon!")
  363. setProperty(WEATHER_WINDOW, "Weather.IsFetched", "false")
  364. ####END CURRENT DATA
  365.  
  366. ####FORECAST DATA
  367. try:
  368. #pull the basic data from the forecast table
  369. ret = common.parseDOM(page, "div", attrs = { "class": "boxed_blue_nopad" })
  370. #create lists of each of the maxes, mins, and descriptions
  371. #Get the days UV in text form like 'Extreme' and number '11'
  372. UVchunk = common.parseDOM(ret, "td", attrs = { "style": "text-align: center;" })
  373. UVtext = common.parseDOM(UVchunk, "span")
  374. UVnumber = common.parseDOM(UVchunk, "span", ret = "title")
  375. UV = UVtext[0] + ' (' + UVnumber[0] + ')'
  376. #get the 7 day max min forecasts
  377. maxMin = common.parseDOM(ret, "td")
  378. #for count, element in enumerate(maxMin):
  379. # print "********" , count , "^^^" , str(element)
  380. maxList = stripList(maxMin[7:14],'&deg;C');
  381. minList = stripList(maxMin[14:21],'&deg;C');
  382. #and the short forecasts
  383. shortDesc = common.parseDOM(ret, "td", attrs = { "class": "bg_yellow" })
  384. shortDesc = common.parseDOM(ret, "span", attrs = { "style": "font-size: 0.9em;" })
  385. shortDesc = shortDesc[0:7]
  386.  
  387. log(" shortDesc is " + str(shortDesc))
  388.  
  389. for count, desc in enumerate(shortDesc):
  390. shortDesc[count] = shortDesc[count].title().replace( '-<br />','')
  391. shortDesc[count] = shortDesc[count].title().replace( '-<Br />','')
  392. shortDesc[count] = shortDesc[count].title().replace( 'ThunderStorms','Thunderstorms')
  393. shortDesc[count] = shortDesc[count].title().replace( 'windy','Windy')
  394.  
  395. #log the collected data, helpful for finding errors
  396. log("Collected data: shortDesc [" + str(shortDesc) + "] maxList [" + str(maxList) +"] minList [" + str(minList) + "]")
  397.  
  398. #and the names of the days
  399. days = common.parseDOM(ret, "span", attrs = { "style": "font-size: larger;" })
  400. days = common.parseDOM(ret, "span", attrs = { "class": "bold" })
  401. days = days[0:7]
  402. for count, day in enumerate(days):
  403. days[count] = DAYS[day]
  404.  
  405. #get the longer current forecast for the day
  406. # or just use the short one if this is disabled in settings
  407. if extendedFeatures == "true":
  408. longDayCast = common.parseDOM(page, "div", attrs = { "class": "top_left" })
  409. longDayCast = common.parseDOM(longDayCast, "p" )
  410. longDayCast = common.stripTags(longDayCast[0])
  411. longDayCast = longDayCast.replace( '\t','')
  412. longDayCast = longDayCast.replace( '\r',' ')
  413. longDayCast = longDayCast.replace( '&amp;','&')
  414. longDayCast = longDayCast[:-1]
  415. else:
  416. longDayCast = shortDesc[0]
  417.  
  418. #if for some reason the codes change return a neat 'na' response
  419. try:
  420. weathercode = WEATHER_CODES[shortDesc[0]]
  421. except:
  422. weathercode = 'na'
  423.  
  424. except Exception as inst:
  425. log("********** OzWeather Couldn't Parse Data, sorry!!", inst)
  426. setProperty(WEATHER_WINDOW, 'Current.Condition', "Error w. Current Data!")
  427. setProperty(WEATHER_WINDOW, 'Current.ConditionLong', "Error - Couldn't retrieve forecast weather data from WeatherZone - this is usually just a temporary problem with their server and with any luck they'll fix it soon!")
  428. setProperty(WEATHER_WINDOW, "Weather.IsFetched", "false")
  429. #END FORECAST DATA
  430.  
  431. #ABC VIDEO URL
  432. try:
  433. log("Trying to get ABC weather video URL")
  434. abcURL = "http://www.abc.net.au/news/abcnews24/weather-in-90-seconds/"
  435. req = urllib2.Request(abcURL)
  436. response = urllib2.urlopen(req)
  437. htmlSource = str(response.read())
  438. pattern_video = "http://mpegmedia.abc.net.au/news/weather/video/(.+?)video3.flv"
  439. video = re.findall( pattern_video, htmlSource )
  440. try:
  441. url = "http://mpegmedia.abc.net.au/news/weather/video/" + video[0] + "video3.flv"
  442. setProperty(WEATHER_WINDOW, 'Video.1',url)
  443. except Exception as inst:
  444. log("Couldn't get ABC video URL from page", inst)
  445.  
  446. except Exception as inst:
  447. log("********** Couldn't get ABC video page", inst)
  448. #END ABC VIDEO URL
  449.  
  450. # set all the XBMC window properties.
  451. # wrap it in a try: in case something goes wrong, it's better than crashing out...
  452.  
  453. #SET PROPERTIES
  454. try:
  455. #now set all the XBMC current weather properties
  456. setProperty(WEATHER_WINDOW, 'Current.Condition' , shortDesc[0])
  457. setProperty(WEATHER_WINDOW, 'Current.ConditionLong' , longDayCast)
  458. setProperty(WEATHER_WINDOW, 'Current.Temperature' , temperature)
  459. setProperty(WEATHER_WINDOW, 'Current.Wind' , windSpeed)
  460. setProperty(WEATHER_WINDOW, 'Current.WindDirection' , windDirection)
  461. setProperty(WEATHER_WINDOW, 'Current.Humidity' , humidity)
  462. setProperty(WEATHER_WINDOW, 'Current.FeelsLike' , feelsLike)
  463. setProperty(WEATHER_WINDOW, 'Current.DewPoint' , dewPoint)
  464. setProperty(WEATHER_WINDOW, 'Current.UVIndex' , UV)
  465. setProperty(WEATHER_WINDOW, 'Current.OutlookIcon' , '%s.png' % weathercode)
  466. setProperty(WEATHER_WINDOW, 'Current.FanartCode' , weathercode)
  467.  
  468. #and all the properties for the forecast
  469. for count, desc in enumerate(shortDesc):
  470. try:
  471. weathercode = WEATHER_CODES[shortDesc[count]]
  472. except:
  473. weathercode = 'na'
  474.  
  475. day = days[count]
  476. tdate = datetime.date.today() #establishes current date
  477. futureDate = tdate + datetime.timedelta(days=count) #establishs the future dates one at a time
  478. newdatetuple = time.strptime(str(futureDate),'%Y-%m-%d')#creates a time tuple of that future date
  479. goodshortDate = time.strftime('%d %b %a', newdatetuple) #sets the format of the time tuple, taken from this table http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior
  480. setProperty(WEATHER_WINDOW, 'Daily.%i.ShortDate' % count, str(goodshortDate))
  481. setProperty(WEATHER_WINDOW, 'Day%i.Title' % count, day)
  482. setProperty(WEATHER_WINDOW, 'Day%i.HighTemp' % count, maxList[count])
  483. setProperty(WEATHER_WINDOW, 'Day%i.LowTemp' % count, minList[count])
  484. setProperty(WEATHER_WINDOW, 'Day%i.Outlook' % count, desc)
  485. setProperty(WEATHER_WINDOW, 'Day%i.OutlookIcon' % count, '%s.png' % weathercode)
  486. setProperty(WEATHER_WINDOW, 'Day%i.FanartCode' % count, weathercode)
  487.  
  488. except Exception as inst:
  489. log("********** OzWeather Couldn't set all the properties, sorry!!", inst)
  490.  
  491. #Ok, if we got here we're done
  492. setProperty(WEATHER_WINDOW, "Weather.IsFetched", "true")
  493.  
  494. #END SET PROPERTIES
  495.  
  496.  
  497. ##############################################
  498. ### NOW ACTUALLTY RUN THIS PUPPY - this is main() in the old language...
  499.  
  500. footprints()
  501.  
  502. socket.setdefaulttimeout(100)
  503.  
  504. #the being called from the settings section where the user enters their postcodes
  505. if sys.argv[1].startswith('Location'):
  506. keyboard = xbmc.Keyboard('', LANGUAGE(30195), False)
  507. keyboard.doModal()
  508. if (keyboard.isConfirmed() and keyboard.getText() != ''):
  509. text = keyboard.getText()
  510.  
  511. log("Doing locations search for " + text)
  512. #need to submit the postcode to the weatherzone search
  513. searchURL = WEATHERZONE_URL + '/search/'
  514. user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
  515. host = 'www.weatherzone.com.au'
  516. headers = { 'User-Agent' : user_agent, 'Host' : host }
  517. values = {'q' : text, 't' : '3' }
  518. data = urllib.urlencode(values)
  519. req = urllib2.Request(searchURL, data, headers)
  520. response = urllib2.urlopen(req)
  521. resultPage = str(response.read())
  522. #was there only one match? If so it returns the page for that match so we need to check the URL
  523. responseurl = response.geturl()
  524. log("Response page url: " + responseurl)
  525. if not responseurl.endswith('weatherzone.com.au/search/'):
  526. #we were redirected to an actual result page
  527. locationName = common.parseDOM(resultPage, "h1", attrs = { "class": "unenclosed" })
  528. locationName = locationName[0].split('Weather')
  529. locations = [locationName[0] + ', ' + text]
  530. locationids = [responseurl]
  531. log("Single result " + str(locations) + " URL " + str(locationids))
  532. else:
  533. #we got back a page to choose a more specific location
  534. try:
  535. locations=[]
  536. locationids=[]
  537. middle = common.parseDOM(resultPage, "div", attrs = { "id": "structure_middle" })
  538. skimmed = common.parseDOM(middle, "ul", attrs = { "class": "typ2" })
  539. #ok now get two lists - one of the friendly names
  540. #and a matchin one of the URLs to store
  541. locations = common.parseDOM(skimmed[0], "a")
  542. templocs = common.parseDOM(skimmed[0], "a", ret="href")
  543. #build the full urls
  544. locationids = []
  545. for count, loc in enumerate(templocs):
  546. locationids.append(WEATHERZONE_URL + '/' + loc)
  547. #if we did not get enough data back there are no locations with this postcode
  548. if len(locations)<=1:
  549. log("No locations found with this postcode")
  550. locations = []
  551. locationids = []
  552. log("Multiple result " + str(locations) + " URLs " + str(locationids))
  553. except:
  554. log("Error - middle: " + str(middle) + " skimmed " + str(skimmed))
  555.  
  556.  
  557. #now get them to choose an actual location
  558. dialog = xbmcgui.Dialog()
  559. if locations != []:
  560. selected = dialog.select(xbmc.getLocalizedString(396), locations)
  561. if selected != -1:
  562. ADDON.setSetting(sys.argv[1], locations[selected])
  563. ADDON.setSetting(sys.argv[1] + 'id', locationids[selected])
  564. else:
  565. dialog.ok(ADDONNAME, xbmc.getLocalizedString(284))
  566.  
  567.  
  568. #script is being called in general use, not from the settings page
  569. #get the currently selected location and grab it's forecast
  570. else:
  571.  
  572. #retrieve the currently set location & radar
  573. location = ""
  574. location = ADDON.getSetting('Location%sid' % sys.argv[1])
  575. radar = ""
  576. radar = ADDON.getSetting('Radar%s' % sys.argv[1])
  577. #now get a forecast
  578. forecast(location, radar)
  579.  
  580. #refresh the locations and set the weather provider property
  581. refresh_locations()
  582. setProperty(WEATHER_WINDOW, 'WeatherProvider', 'BOM Australia via WeatherZone')
  583. setProperty(WEATHER_WINDOW, 'WeatherVersion', ADDONNAME + "-" + VERSION)
  584.  
  585. #and close out...
  586. footprints(startup=False)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement