[WeatherPlugin] small fix for skincomponents
[enigma2-plugins.git] / weatherplugin / src / MSNWeather.py
1 # -*- coding: utf-8 -*-
2 #
3 # WeatherPlugin E2
4 #
5 # Coded by Dr.Best (c) 2012-2013
6 # Support: www.dreambox-tools.info
7 # E-Mail: dr.best@dreambox-tools.info
8 #
9 # This plugin is open source but it is NOT free software.
10 #
11 # This plugin may only be distributed to and executed on hardware which
12 # is licensed by Dream Multimedia GmbH.
13 # In other words:
14 # It's NOT allowed to distribute any parts of this plugin or its source code in ANY way
15 # to hardware which is NOT licensed by Dream Multimedia GmbH.
16 # It's NOT allowed to execute this plugin and its source code or even parts of it in ANY way
17 # on hardware which is NOT licensed by Dream Multimedia GmbH.
18 #
19 # If you want to use or modify the code or parts of it,
20 # you have to keep MY license and inform me about the modifications by mail.
21 #
22
23 # for localized messages
24 from . import _
25
26 from xml.etree.cElementTree import fromstring as cet_fromstring
27 from twisted.internet import defer
28 from twisted.web.client import getPage, downloadPage
29 from enigma import eEnv
30 from os import path as os_path, mkdir as os_mkdir, remove as os_remove, listdir as os_listdir
31 from Components.config import config
32 from Tools.Directories import resolveFilename, SCOPE_SKIN
33 from urllib import quote as urllib_quote
34
35 class WeatherIconItem:
36         def __init__(self, url = "", filename = "", index = -1, error = False):
37                 self.url = url
38                 self.filename = filename
39                 self.index = index
40                 self.error = error
41                 
42 class MSNWeatherItem:
43         def __init__(self):
44                 self.temperature = ""
45                 self.skytext = ""
46                 self.humidity = ""
47                 self.winddisplay = ""
48                 self.observationtime = ""
49                 self.observationpoint = ""
50                 self.feelslike = ""
51                 self.skycode = ""
52                 self.date = ""
53                 self.day = ""
54                 self.low = ""
55                 self.high = ""
56                 self.skytextday = ""
57                 self.skycodeday = ""
58                 self.shortday = ""
59                 self.iconFilename = ""
60                 self.code = ""
61                 
62 class MSNWeather:
63
64         ERROR = 0
65         OK = 1
66
67         def __init__(self):
68                 path = "/etc/enigma2/weather_icons/"
69                 extension = self.checkIconExtension(path)
70                 if extension is None:
71                         path = os_path.dirname(resolveFilename(SCOPE_SKIN, config.skin.primary_skin.value)) + "/weather_icons/"
72                         extension = self.checkIconExtension(path)
73                 if extension is None:
74                         path = eEnv.resolve("${libdir}/enigma2/python/Plugins/Extensions/WeatherPlugin/icons/")
75                         extension = ".gif"
76                 self.setIconPath(path)
77                 self.setIconExtension(extension)
78                 self.initialize()
79
80         def checkIconExtension(self, path):
81                 filename = None
82                 extension = None
83                 if os_path.exists(path):
84                         try:
85                                 filename = os_listdir(path)[0]
86                         except:
87                                 filename = None
88                 if filename is not None:
89                         try:
90                                 extension = os_path.splitext(filename)[1].lower()
91                         except: pass
92                 return extension
93                 
94         def initialize(self):
95                 self.city = ""
96                 self.degreetype = ""
97                 self.imagerelativeurl = ""
98                 self.url = ""
99                 self.weatherItems = {}
100                 self.callback = None
101                 self.callbackShowIcon = None
102                 self.callbackAllIconsDownloaded = None
103                 
104         def cancel(self):
105                 self.callback = None
106                 self.callbackShowIcon = None
107                 
108         def setIconPath(self, iconpath):
109                 if not os_path.exists(iconpath):
110                         os_mkdir(iconpath)
111                 self.iconpath = iconpath
112                 
113         def setIconExtension(self, iconextension):
114                 self.iconextension = iconextension
115                 
116         def getWeatherData(self, degreetype, locationcode, city, callback, callbackShowIcon, callbackAllIconsDownloaded = None ):
117                 self.initialize()
118                 language = config.osd.language.value.replace("_","-")
119                 if language == "en-EN": # hack
120                         language = "en-US"
121                 elif language == "no-NO": # hack
122                         language = "nn-NO"
123                 self.city = city
124                 self.callback = callback
125                 self.callbackShowIcon  = callbackShowIcon
126                 self.callbackAllIconsDownloaded = callbackAllIconsDownloaded
127                 url = "http://weather.service.msn.com/data.aspx?src=outlook&weadegreetype=%s&culture=%s&wealocations=%s" % (degreetype, language, urllib_quote(locationcode))
128                 getPage(url).addCallback(self.xmlCallback).addErrback(self.error)
129                 
130         def getDefaultWeatherData(self, callback = None, callbackAllIconsDownloaded = None):
131                 self.initialize()
132                 weatherPluginEntryCount = config.plugins.WeatherPlugin.entrycount.value
133                 if weatherPluginEntryCount >= 1:
134                         weatherPluginEntry = config.plugins.WeatherPlugin.Entry[0]
135                         self.getWeatherData(weatherPluginEntry.degreetype.value, weatherPluginEntry.weatherlocationcode.value, weatherPluginEntry.city.value, callback, None, callbackAllIconsDownloaded)
136                         return 1
137                 else:
138                         return 0
139                 
140         def error(self, error = None):
141                 errormessage = ""
142                 if error is not None:
143                         errormessage = str(error.getErrorMessage())
144                 if self.callback is not None:
145                         self.callback(self.ERROR, errormessage)
146                         
147         
148         def errorIconDownload(self, error = None, item = None):
149                 item.error = True
150                 if os_path.exists(item.filename): # delete 0 kb file
151                         os_remove(item.filename)
152
153         def finishedIconDownload(self, result, item):
154                 if not item.error:
155                         self.showIcon(item.index,item.filename)
156                 
157         def showIcon(self, index, filename):
158                 if self.callbackShowIcon is not None:
159                                 self.callbackShowIcon(index, filename)
160                                 
161         def finishedAllDownloadFiles(self, result):
162                 if self.callbackAllIconsDownloaded is not None:
163                         self.callbackAllIconsDownloaded()
164                 
165         def xmlCallback(self, xmlstring):
166                 IconDownloadList = []
167                 root = cet_fromstring(xmlstring)
168                 index = 0
169                 self.degreetype = "C"
170                 errormessage = ""
171                 for childs in root:
172                         if childs.tag == "weather":
173                                 errormessage = childs.attrib.get("errormessage")
174                                 if errormessage:
175                                         if self.callback is not None:
176                                                 self.callback(self.ERROR, errormessage.encode("utf-8", 'ignore'))
177                                         break
178                                 self.degreetype = childs.attrib.get("degreetype").encode("utf-8", 'ignore')
179                                 self.imagerelativeurl = "%slaw/" % childs.attrib.get("imagerelativeurl").encode("utf-8", 'ignore')
180                                 self.url = childs.attrib.get("url").encode("utf-8", 'ignore')
181                         for items in childs:
182                                 if items.tag == "current":
183                                         currentWeather = MSNWeatherItem()
184                                         currentWeather.temperature = items.attrib.get("temperature").encode("utf-8", 'ignore')
185                                         currentWeather.skytext = items.attrib.get("skytext").encode("utf-8", 'ignore')
186                                         currentWeather.humidity = items.attrib.get("humidity").encode("utf-8", 'ignore')
187                                         currentWeather.winddisplay = items.attrib.get("winddisplay").encode("utf-8", 'ignore')
188                                         currentWeather.observationtime = items.attrib.get("observationtime").encode("utf-8", 'ignore')
189                                         currentWeather.observationpoint = items.attrib.get("observationpoint").encode("utf-8", 'ignore')
190                                         currentWeather.feelslike = items.attrib.get("feelslike").encode("utf-8", 'ignore')
191                                         currentWeather.skycode = "%s%s" % (items.attrib.get("skycode").encode("utf-8", 'ignore'), self.iconextension)
192                                         currentWeather.code = items.attrib.get("skycode").encode("utf-8", 'ignore')
193                                         filename = "%s%s"  % (self.iconpath, currentWeather.skycode)
194                                         currentWeather.iconFilename = filename
195                                         if not os_path.exists(filename):
196                                                 url = "%s%s" % (self.imagerelativeurl, currentWeather.skycode)
197                                                 IconDownloadList.append(WeatherIconItem(url = url,filename = filename, index = -1))
198                                         else:
199                                                 self.showIcon(-1,filename)
200                                         self.weatherItems[str(-1)] = currentWeather
201                                 elif items.tag == "forecast" and index <= 4:
202                                         index +=1
203                                         weather = MSNWeatherItem()
204                                         weather.date = items.attrib.get("date").encode("utf-8", 'ignore')
205                                         weather.day = items.attrib.get("day").encode("utf-8", 'ignore')
206                                         weather.shortday = items.attrib.get("shortday").encode("utf-8", 'ignore')
207                                         weather.low = items.attrib.get("low").encode("utf-8", 'ignore')
208                                         weather.high = items.attrib.get("high").encode("utf-8", 'ignore')
209                                         weather.skytextday = items.attrib.get("skytextday").encode("utf-8", 'ignore')
210                                         weather.skycodeday = "%s%s" % (items.attrib.get("skycodeday").encode("utf-8", 'ignore'), self.iconextension)
211                                         weather.code = items.attrib.get("skycodeday").encode("utf-8", 'ignore')
212                                         filename = "%s%s"  % (self.iconpath, weather.skycodeday)
213                                         weather.iconFilename = filename
214                                         if not os_path.exists(filename):
215                                                 url = "%s%s" % (self.imagerelativeurl, weather.skycodeday)
216                                                 IconDownloadList.append(WeatherIconItem(url = url,filename = filename, index = index))
217                                         else:
218                                                 self.showIcon(index,filename)
219                                         self.weatherItems[str(index)] = weather
220                 
221                 if len(IconDownloadList) != 0:
222                         ds = defer.DeferredSemaphore(tokens=len(IconDownloadList))
223                         downloads = [ds.run(download,item ).addErrback(self.errorIconDownload, item).addCallback(self.finishedIconDownload,item) for item in IconDownloadList]
224                         finished = defer.DeferredList(downloads).addErrback(self.error).addCallback(self.finishedAllDownloadFiles)
225                 else:
226                         self.finishedAllDownloadFiles(None)
227                         
228                 if self.callback is not None:
229                         self.callback(self.OK, None)
230                 
231 def download(item):
232         return downloadPage(item.url, file(item.filename, 'wb'))