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