drop plugin-local translations (in favor of the global ones in /po)
[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 from xml.etree.cElementTree import fromstring as cet_fromstring
23 from twisted.internet import defer
24 from twisted.web.client import getPage, downloadPage
25 from enigma import eEnv
26 from os import path as os_path, mkdir as os_mkdir, remove as os_remove, listdir as os_listdir
27 from Components.config import config
28 from Tools.Directories import resolveFilename, SCOPE_SKIN
29 from urllib import quote as urllib_quote
30
31 class WeatherIconItem:
32         def __init__(self, url = "", filename = "", index = -1, error = False):
33                 self.url = url
34                 self.filename = filename
35                 self.index = index
36                 self.error = error
37                 
38 class MSNWeatherItem:
39         def __init__(self):
40                 self.temperature = ""
41                 self.skytext = ""
42                 self.humidity = ""
43                 self.winddisplay = ""
44                 self.observationtime = ""
45                 self.observationpoint = ""
46                 self.feelslike = ""
47                 self.skycode = ""
48                 self.date = ""
49                 self.day = ""
50                 self.low = ""
51                 self.high = ""
52                 self.skytextday = ""
53                 self.skycodeday = ""
54                 self.shortday = ""
55                 self.iconFilename = ""
56                 self.code = ""
57                 
58 class MSNWeather:
59
60         ERROR = 0
61         OK = 1
62
63         def __init__(self):
64                 path = "/etc/enigma2/weather_icons/"
65                 extension = self.checkIconExtension(path)
66                 if extension is None:
67                         path = os_path.dirname(resolveFilename(SCOPE_SKIN, config.skin.primary_skin.value)) + "/weather_icons/"
68                         extension = self.checkIconExtension(path)
69                 if extension is None:
70                         path = eEnv.resolve("${libdir}/enigma2/python/Plugins/Extensions/WeatherPlugin/icons/")
71                         extension = ".gif"
72                 self.setIconPath(path)
73                 self.setIconExtension(extension)
74                 self.initialize()
75
76         def checkIconExtension(self, path):
77                 filename = None
78                 extension = None
79                 if os_path.exists(path):
80                         try:
81                                 filename = os_listdir(path)[0]
82                         except:
83                                 filename = None
84                 if filename is not None:
85                         try:
86                                 extension = os_path.splitext(filename)[1].lower()
87                         except: pass
88                 return extension
89                 
90         def initialize(self):
91                 self.city = ""
92                 self.degreetype = ""
93                 self.imagerelativeurl = ""
94                 self.url = ""
95                 self.weatherItems = {}
96                 self.callback = None
97                 self.callbackShowIcon = None
98                 self.callbackAllIconsDownloaded = None
99                 
100         def cancel(self):
101                 self.callback = None
102                 self.callbackShowIcon = None
103                 
104         def setIconPath(self, iconpath):
105                 if not os_path.exists(iconpath):
106                         os_mkdir(iconpath)
107                 self.iconpath = iconpath
108                 
109         def setIconExtension(self, iconextension):
110                 self.iconextension = iconextension
111                 
112         def getWeatherData(self, degreetype, locationcode, city, callback, callbackShowIcon, callbackAllIconsDownloaded = None ):
113                 self.initialize()
114                 language = config.osd.language.value.replace("_","-")
115                 if language == "en-EN": # hack
116                         language = "en-US"
117                 elif language == "no-NO": # hack
118                         language = "nn-NO"
119                 self.city = city
120                 self.callback = callback
121                 self.callbackShowIcon  = callbackShowIcon
122                 self.callbackAllIconsDownloaded = callbackAllIconsDownloaded
123                 url = "http://weather.service.msn.com/data.aspx?src=outlook&weadegreetype=%s&culture=%s&wealocations=%s" % (degreetype, language, urllib_quote(locationcode))
124                 getPage(url).addCallback(self.xmlCallback).addErrback(self.error)
125                 
126         def getDefaultWeatherData(self, callback = None, callbackAllIconsDownloaded = None):
127                 self.initialize()
128                 weatherPluginEntryCount = config.plugins.WeatherPlugin.entrycount.value
129                 if weatherPluginEntryCount >= 1:
130                         weatherPluginEntry = config.plugins.WeatherPlugin.Entry[0]
131                         self.getWeatherData(weatherPluginEntry.degreetype.value, weatherPluginEntry.weatherlocationcode.value, weatherPluginEntry.city.value, callback, None, callbackAllIconsDownloaded)
132                         return 1
133                 else:
134                         return 0
135                 
136         def error(self, error = None):
137                 errormessage = ""
138                 if error is not None:
139                         errormessage = str(error.getErrorMessage())
140                 if self.callback is not None:
141                         self.callback(self.ERROR, errormessage)
142                         
143         
144         def errorIconDownload(self, error = None, item = None):
145                 item.error = True
146                 if os_path.exists(item.filename): # delete 0 kb file
147                         os_remove(item.filename)
148
149         def finishedIconDownload(self, result, item):
150                 if not item.error:
151                         self.showIcon(item.index,item.filename)
152                 
153         def showIcon(self, index, filename):
154                 if self.callbackShowIcon is not None:
155                                 self.callbackShowIcon(index, filename)
156                                 
157         def finishedAllDownloadFiles(self, result):
158                 if self.callbackAllIconsDownloaded is not None:
159                         self.callbackAllIconsDownloaded()
160                 
161         def xmlCallback(self, xmlstring):
162                 IconDownloadList = []
163                 root = cet_fromstring(xmlstring)
164                 index = 0
165                 self.degreetype = "C"
166                 errormessage = ""
167                 for childs in root:
168                         if childs.tag == "weather":
169                                 errormessage = childs.attrib.get("errormessage")
170                                 if errormessage:
171                                         if self.callback is not None:
172                                                 self.callback(self.ERROR, errormessage.encode("utf-8", 'ignore'))
173                                         break
174                                 self.degreetype = childs.attrib.get("degreetype").encode("utf-8", 'ignore')
175                                 self.imagerelativeurl = "%slaw/" % childs.attrib.get("imagerelativeurl").encode("utf-8", 'ignore')
176                                 self.url = childs.attrib.get("url").encode("utf-8", 'ignore')
177                         for items in childs:
178                                 if items.tag == "current":
179                                         currentWeather = MSNWeatherItem()
180                                         currentWeather.temperature = items.attrib.get("temperature").encode("utf-8", 'ignore')
181                                         currentWeather.skytext = items.attrib.get("skytext").encode("utf-8", 'ignore')
182                                         currentWeather.humidity = items.attrib.get("humidity").encode("utf-8", 'ignore')
183                                         currentWeather.winddisplay = items.attrib.get("winddisplay").encode("utf-8", 'ignore')
184                                         currentWeather.observationtime = items.attrib.get("observationtime").encode("utf-8", 'ignore')
185                                         currentWeather.observationpoint = items.attrib.get("observationpoint").encode("utf-8", 'ignore')
186                                         currentWeather.feelslike = items.attrib.get("feelslike").encode("utf-8", 'ignore')
187                                         currentWeather.skycode = "%s%s" % (items.attrib.get("skycode").encode("utf-8", 'ignore'), self.iconextension)
188                                         currentWeather.code = items.attrib.get("skycode").encode("utf-8", 'ignore')
189                                         filename = "%s%s"  % (self.iconpath, currentWeather.skycode)
190                                         currentWeather.iconFilename = filename
191                                         if not os_path.exists(filename):
192                                                 url = "%s%s" % (self.imagerelativeurl, currentWeather.skycode)
193                                                 IconDownloadList.append(WeatherIconItem(url = url,filename = filename, index = -1))
194                                         else:
195                                                 self.showIcon(-1,filename)
196                                         self.weatherItems[str(-1)] = currentWeather
197                                 elif items.tag == "forecast" and index <= 4:
198                                         index +=1
199                                         weather = MSNWeatherItem()
200                                         weather.date = items.attrib.get("date").encode("utf-8", 'ignore')
201                                         weather.day = items.attrib.get("day").encode("utf-8", 'ignore')
202                                         weather.shortday = items.attrib.get("shortday").encode("utf-8", 'ignore')
203                                         weather.low = items.attrib.get("low").encode("utf-8", 'ignore')
204                                         weather.high = items.attrib.get("high").encode("utf-8", 'ignore')
205                                         weather.skytextday = items.attrib.get("skytextday").encode("utf-8", 'ignore')
206                                         weather.skycodeday = "%s%s" % (items.attrib.get("skycodeday").encode("utf-8", 'ignore'), self.iconextension)
207                                         weather.code = items.attrib.get("skycodeday").encode("utf-8", 'ignore')
208                                         filename = "%s%s"  % (self.iconpath, weather.skycodeday)
209                                         weather.iconFilename = filename
210                                         if not os_path.exists(filename):
211                                                 url = "%s%s" % (self.imagerelativeurl, weather.skycodeday)
212                                                 IconDownloadList.append(WeatherIconItem(url = url,filename = filename, index = index))
213                                         else:
214                                                 self.showIcon(index,filename)
215                                         self.weatherItems[str(index)] = weather
216                 
217                 if len(IconDownloadList) != 0:
218                         ds = defer.DeferredSemaphore(tokens=len(IconDownloadList))
219                         downloads = [ds.run(download,item ).addErrback(self.errorIconDownload, item).addCallback(self.finishedIconDownload,item) for item in IconDownloadList]
220                         finished = defer.DeferredList(downloads).addErrback(self.error).addCallback(self.finishedAllDownloadFiles)
221                 else:
222                         self.finishedAllDownloadFiles(None)
223                         
224                 if self.callback is not None:
225                         self.callback(self.OK, None)
226                 
227 def download(item):
228         return downloadPage(item.url, file(item.filename, 'wb'))