generic cleanup:
[enigma2-plugins.git] / weatherplugin / src / plugin.py
1 # -*- coding: utf-8 -*-
2 #
3 #  Weather Plugin E2
4 #
5 #  $Id$
6 #
7 #  Coded by Dr.Best (c) 2009
8 #  Support: www.dreambox-tools.info
9 #
10 #  This program is free software; you can redistribute it and/or
11 #  modify it under the terms of the GNU General Public License
12 #  as published by the Free Software Foundation; either version 2
13 #  of the License, or (at your option) any later version.
14 #
15 #  This program is distributed in the hope that it will be useful,
16 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 #  GNU General Public License for more details.
19 #
20
21 from Plugins.Plugin import PluginDescriptor
22 from Screens.Screen import Screen
23 from Components.ActionMap import ActionMap
24 from Components.Sources.StaticText import StaticText
25 from xml.etree.cElementTree import fromstring as cet_fromstring
26 from twisted.internet import defer
27 from twisted.web.client import getPage, downloadPage
28 from urllib import quote
29 from Components.Pixmap import Pixmap
30 from enigma import ePicLoad
31 from os import path as os_path, mkdir as os_mkdir
32 from Components.AVSwitch import AVSwitch
33 from Components.config import ConfigSubsection, ConfigSubList, ConfigInteger, config
34 from setup import initConfig, WeatherPluginEntriesListConfigScreen
35
36 config.plugins.WeatherPlugin = ConfigSubsection()
37 config.plugins.WeatherPlugin.entriescount =  ConfigInteger(0)
38 config.plugins.WeatherPlugin.Entries = ConfigSubList()
39 initConfig()
40
41 UserAgent = "Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.15) Gecko/2009102815 Ubuntu/9.04 (jaunty) Firefox/3."
42
43 class WeatherIconItem:
44         def __init__(self, url = "", filename = "", index = -1, error = False):
45                 self.url = url
46                 self.filename = filename
47                 self.index = index
48                 self.error = error
49
50 def getXML(url):
51         return getPage(url, agent=UserAgent)
52
53 def download(item):
54         return downloadPage(item.url, file(item.filename, 'wb'), agent=UserAgent)
55
56
57 def main(session,**kwargs):
58         session.open(WeatherPlugin)
59
60 def Plugins(**kwargs):
61         list = [PluginDescriptor(name="Weather Plugin", description=_("Weather Plugin"), where = [PluginDescriptor.WHERE_EXTENSIONSMENU], fnc=main)]
62         return list
63
64
65 class WeatherPlugin(Screen):
66
67         skin = """
68                 <screen name="WeatherPlugin" position="center,center" size="664,170" title="Weather Plugin">
69                         <widget render="Label" source="caption" position="10,20" zPosition="1" size="300,23" font="Regular;22" transparent="1"/>
70                         <widget render="Label" source="currentTemp" position="10,45" zPosition="1" size="300,23" font="Regular;22" transparent="1"/>
71                         <widget render="Label" source="condition" position="10,80" zPosition="1" size="300,20" font="Regular;18" transparent="1"/>
72                         <widget render="Label" source="wind_condition" position="10,105" zPosition="1" size="300,20" font="Regular;18" transparent="1"/>
73                         <widget render="Label" source="humidity" position="10,130" zPosition="1" size="300,20" font="Regular;18" valign="bottom" transparent="1"/>
74                         <widget render="Label" source="weekday1" position="255,30" zPosition="1" size="72,20" halign="center" valign="center" font="Regular;18" transparent="1"/>
75                         <widget name="weekday1_icon" position="255,50" zPosition="1" size="72,72" alphatest="blend"/>
76                         <widget render="Label" source="weekday1_temp" position="241,130" zPosition="1" size="100,20" halign="center" valign="bottom" font="Regular;16" transparent="1"/>
77                         <widget render="Label" source="weekday2" position="358,30" zPosition="1" size="72,20" halign="center" valign="center" font="Regular;18" transparent="1"/>
78                         <widget name="weekday2_icon" position="358,50" zPosition="1" size="72,72" alphatest="blend"/>
79                         <widget render="Label" source="weekday2_temp" position="344,130" zPosition="1" size="100,20" halign="center" valign="bottom" font="Regular;16" transparent="1"/>
80                         <widget render="Label" source="weekday3" position="461,30" zPosition="1" size="72,20" halign="center" valign="center" font="Regular;18" transparent="1"/>
81                         <widget name="weekday3_icon" position="461,50" zPosition="1" size="72,72" alphatest="blend"/>
82                         <widget render="Label" source="weekday3_temp" position="448,130" zPosition="1" size="100,20" halign="center" valign="bottom" font="Regular;16" transparent="1"/>
83                         <widget render="Label" source="weekday4" position="564,30" zPosition="1" size="72,20" halign="center" valign="center" font="Regular;18" transparent="1"/>
84                         <widget name="weekday4_icon" position="564,50" zPosition="1" size="72,72" alphatest="blend"/>
85                         <widget render="Label" source="weekday4_temp" position="550,130" zPosition="1" size="100,20" halign="center" valign="bottom" font="Regular;16" transparent="1"/>
86                         <widget render="Label" source="statustext" position="0,0" zPosition="1" size="664,170" font="Regular;20" halign="center" valign="center" transparent="1"/>
87                 </screen>"""
88         
89         def __init__(self, session):
90                 Screen.__init__(self, session)
91                 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EPGSelectActions"],
92                 {
93                         "back": self.close,
94                         "input_date_time": self.config,
95                         "right": self.nextItem,
96                         "left": self.previousItem
97                 }, -1)
98
99                 self["statustext"] = StaticText()
100                 self["caption"] = StaticText()
101                 self["currentTemp"] = StaticText()
102                 self["condition"] = StaticText()
103                 self["wind_condition"] = StaticText()
104                 self["humidity"] = StaticText()
105
106                 i = 1
107                 while i < 5:
108                         self["weekday%s" % i] = StaticText()
109                         self["weekday%s_icon" %i] = WeatherIcon()
110                         self["weekday%s_temp" % i] = StaticText()
111                         i += 1
112                 del i
113
114                 self.appdir = "/usr/lib/enigma2/python/Plugins/Extensions/WeatherPlugin/icons/" 
115                 if not os_path.exists(self.appdir):
116                         os_mkdir(self.appdir)
117
118                 self.weatherPluginEntryIndex = -1
119                 self.weatherPluginEntryCount = config.plugins.WeatherPlugin.entriescount.value
120                 if self.weatherPluginEntryCount >= 1:
121                         self.weatherPluginEntry = config.plugins.WeatherPlugin.Entries[0]
122                         self.weatherPluginEntryIndex = 1
123                 else:
124                         self.weatherPluginEntry = None
125
126                 self.onLayoutFinish.append(self.startRun)
127
128         def startRun(self):
129                 if self.weatherPluginEntry is not None:
130                         self["statustext"].text = _("Getting weather information...")
131                         url = ("http://www.google.com/ig/api?weather=%s&hl=%s" % (quote(self.weatherPluginEntry.city.value), self.weatherPluginEntry.language.value))
132                         getXML(url).addCallback(self.xmlCallback).addErrback(self.error)
133                 else:
134                         self["statustext"].text = _("No locations defined...\nPress 'Menu' to do that.")
135
136         def nextItem(self):
137                 if self.weatherPluginEntryCount != 0:
138                         if self.weatherPluginEntryIndex < self.weatherPluginEntryCount:
139                                 self.weatherPluginEntryIndex = self.weatherPluginEntryIndex + 1
140                         else:
141                                 self.weatherPluginEntryIndex = 1
142                         self.setItem()
143
144         def previousItem(self):
145                 if self.weatherPluginEntryCount != 0:
146                         if self.weatherPluginEntryIndex >= 2:
147                                 self.weatherPluginEntryIndex = self.weatherPluginEntryIndex - 1
148                         else:
149                                 self.weatherPluginEntryIndex = self.weatherPluginEntryCount
150                         self.setItem()
151
152         def setItem(self):
153                 self.weatherPluginEntry = config.plugins.WeatherPlugin.Entries[self.weatherPluginEntryIndex-1]
154                 self.clearFields()
155                 self.startRun()
156
157         def clearFields(self):
158                 self["caption"].text = ""
159                 self["currentTemp"].text = ""
160                 self["condition"].text = ""
161                 self["wind_condition"].text = ""
162                 self["humidity"].text = ""
163                 i = 1
164                 while i < 5:
165                         self["weekday%s" % i].text = ""
166                         self["weekday%s_icon" %i].hide()
167                         self["weekday%s_temp" % i].text = ""
168                         i += 1
169
170         def errorIconDownload(self, error = None, item = None):
171                 item.error = True
172
173         def finishedIconDownload(self, result, item):
174                 if not item.error:
175                         self.showIcon(item.index,item.filename)
176
177         def showIcon(self,index, filename):
178                 self["weekday%s_icon" % index].updateIcon(filename)
179                 self["weekday%s_icon" % index].show()
180
181         def xmlCallback(self, xmlstring):
182                 self["statustext"].text = ""
183                 metric = 0
184                 index = 0
185                 UnitSystemText = "F"
186                 IconDownloadList = []
187                 root = cet_fromstring(xmlstring)
188                 for childs in root.findall("weather"):
189                         for items in childs:
190                                 if items.tag == "problem_cause":
191                                         self["statustext"].text = items.attrib.get("data").encode("utf-8", 'ignore')
192                                 elif items.tag == "forecast_information":
193                                         for items2 in items:
194                                                 if items2.tag == "city":
195                                                         self["caption"].text = items2.attrib.get("data").encode("utf-8", 'ignore')
196                                                 elif items2.tag == "unit_system":
197                                                         if items2.attrib.get("data").encode("utf-8", 'ignore') == "SI":
198                                                                 metric = 1
199                                                                 UnitSystemText = "C"
200                                 elif items.tag == "current_conditions":
201                                         for items2 in items:
202                                                 if items2.tag == "condition":
203                                                         self["condition"].text = _("Current: %s") % items2.attrib.get("data").encode("utf-8", 'ignore')
204                                                 elif items2.tag == "temp_f" and metric == 0:
205                                                         self["currentTemp"].text =  ("%s F" % items2.attrib.get("data").encode("utf-8", 'ignore')) 
206                                                 elif items2.tag == "temp_c" and metric == 1:
207                                                         self["currentTemp"].text =  ("%s C" % items2.attrib.get("data").encode("utf-8", 'ignore')) 
208                                                 elif items2.tag == "humidity":
209                                                         self["humidity"].text = items2.attrib.get("data").encode("utf-8", 'ignore')
210                                                 elif items2.tag == "wind_condition":
211                                                         self["wind_condition"].text = items2.attrib.get("data").encode("utf-8", 'ignore')
212                                 elif items.tag == "forecast_conditions":
213                                         index = index + 1
214                                         lowTemp = ""
215                                         highTemp = ""
216                                         icon = ""
217                                         for items2 in items:
218                                                 if items2.tag == "day_of_week":
219                                                         self["weekday%s" % index].text = items2.attrib.get("data").encode("utf-8", 'ignore')
220                                                 elif items2.tag == "low":
221                                                         lowTemp = items2.attrib.get("data").encode("utf-8", 'ignore')
222                                                 elif items2.tag == "high":
223                                                         highTemp = items2.attrib.get("data").encode("utf-8", 'ignore')
224                                                         self["weekday%s_temp" % index].text = "%s %s | %s %s" % (highTemp, UnitSystemText, lowTemp, UnitSystemText)
225                                                 elif items2.tag == "icon":
226                                                         url = "http://www.google.com%s" % items2.attrib.get("data").encode("utf-8", 'ignore')
227                                                         parts = url.split("/")
228                                                         filename = self.appdir + parts[-1]
229                                                         if not os_path.exists(filename):
230                                                                 IconDownloadList.append(WeatherIconItem(url = url,filename = filename, index = index))
231                                                         else:
232                                                                 self.showIcon(index,filename)
233                 if len(IconDownloadList) != 0:
234                         ds = defer.DeferredSemaphore(tokens=len(IconDownloadList))
235                         downloads = [ds.run(download,item ).addErrback(self.errorIconDownload, item).addCallback(self.finishedIconDownload,item) for item in IconDownloadList]
236                         finished = defer.DeferredList(downloads).addErrback(self.error)
237
238         def config(self):
239                 self.session.openWithCallback(self.setupFinished, WeatherPluginEntriesListConfigScreen)
240
241         def setupFinished(self, index, entry = None):
242                 self.weatherPluginEntryCount = config.plugins.WeatherPlugin.entriescount.value
243                 if self.weatherPluginEntryCount >= 1:
244                         if entry is not None:
245                                 self.weatherPluginEntry = entry
246                                 self.weatherPluginEntryIndex = index + 1
247                         if self.weatherPluginEntry is None:
248                                 self.weatherPluginEntry = config.plugins.WeatherPlugin.Entries[0]
249                                 self.weatherPluginEntryIndex = 1
250                 else:
251                         self.weatherPluginEntry = None
252                         self.weatherPluginEntryIndex = -1
253
254                 self.clearFields()
255                 self.startRun()
256
257         def error(self, error = None):
258                 if error is not None:
259                         self.clearFields()
260                         self["statustext"].text = str(error.getErrorMessage())
261
262
263 class WeatherIcon(Pixmap):
264         def __init__(self):
265                 Pixmap.__init__(self)
266                 self.IconFileName = ""
267                 self.picload = ePicLoad()
268                 self.picload.PictureData.get().append(self.paintIconPixmapCB)
269
270         def onShow(self):
271                 Pixmap.onShow(self)
272                 sc = AVSwitch().getFramebufferScale()
273                 self.picload.setPara((self.instance.size().width(), self.instance.size().height(), sc[0], sc[1], 0, 0, '#00000000'))
274
275         def paintIconPixmapCB(self, picInfo=None):
276                 ptr = self.picload.getData()
277                 if ptr != None:
278                         self.instance.setPixmap(ptr.__deref__())
279
280         def updateIcon(self, filename):
281                 new_IconFileName = filename
282                 if (self.IconFileName != new_IconFileName):
283                         self.IconFileName = new_IconFileName
284                         self.picload.startDecode(self.IconFileName)
285