Merge remote-tracking branch 'origin/master' into master
[enigma2-plugins.git] / webcamviewer / src / WebcamTravel.py
1 from Screens.Screen import Screen
2 from Components.Sources.List import List
3 from Components.Button import Button
4 from Components.Label import Label
5 from Components.ActionMap import ActionMap
6 from Screens.InputBox import InputBox
7 from Components.Input import Input
8 from Components.MultiContent import MultiContentEntryText, MultiContentEntryPixmapAlphaTest
9 from Components.Pixmap import Pixmap
10 from Components.AVSwitch import AVSwitch
11 from Tools.BoundFunction import boundFunction
12
13 from enigma import eListboxPythonMultiContent, RT_HALIGN_LEFT, RT_HALIGN_RIGHT,ePicLoad,eTimer
14
15 from PictureScreen import PictureScreen
16
17 from twisted.web.client import getPage,downloadPage
18 #from twisted.internet import reactor
19
20 from xml.etree.cElementTree import fromstring as cElementTree_fromstring
21
22 from os import remove as os_remove
23 from os.path import exists as os_path_exists
24 from datetime import datetime
25
26 from urllib import quote as urllib_quote
27 #########################################
28
29 class TravelWebcamviewer(Screen):
30         skin = ""
31         def __init__(self, session, args = 0):
32                 skin =  """<screen position="93,70" size="550,450" title="Webcams provided by webcams.travel">
33
34                         <widget source="list" render="Listbox" position="0,0" size="550,350" zPosition="1" scrollbarMode="showOnDemand" transparent="1"  >
35                                 <convert type="TemplatedMultiContent">
36                                 {"templates":
37                                         {"default": (77,[
38                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 0), size = (100, 75), png = 4), # index 4 is the thumbnail
39                                                         MultiContentEntryText(pos = (100, 1), size = (500, 22), font=0, flags = RT_HALIGN_LEFT | RT_VALIGN_TOP| RT_WRAP, text = 1), # index 1 is the Title
40                                                         MultiContentEntryText(pos = (100, 24), size = (300, 18), font=1, flags = RT_HALIGN_LEFT | RT_VALIGN_TOP| RT_WRAP, text = 5), # index 5 is the Published Date
41                                                         MultiContentEntryText(pos = (100, 43), size = (300, 18), font=1, flags = RT_HALIGN_LEFT | RT_VALIGN_TOP| RT_WRAP, text = 6), # index 6 is the Views Count
42                                                         MultiContentEntryText(pos = (400, 24), size = (200, 18), font=1, flags = RT_HALIGN_LEFT | RT_VALIGN_TOP| RT_WRAP, text = 7), # index 7 is the duration
43                                                         MultiContentEntryText(pos = (400, 43), size = (200, 18), font=1, flags = RT_HALIGN_LEFT | RT_VALIGN_TOP| RT_WRAP, text = 8), # index 8 is the ratingcount
44                                                 ]),
45                                         "status": (77,[
46                                                         MultiContentEntryText(pos = (10, 1), size = (500, 28), font=2, flags = RT_HALIGN_LEFT | RT_VALIGN_TOP| RT_WRAP, text = 0), # index 0 is the name
47                                                         MultiContentEntryText(pos = (10, 22), size = (500, 46), font=3, flags = RT_HALIGN_LEFT | RT_VALIGN_TOP| RT_WRAP, text = 1), # index 2 is the description
48                                                 ])
49                                         },
50                                         "fonts": [gFont("Regular", 22),gFont("Regular", 18),gFont("Regular", 26),gFont("Regular", 20)],
51                                         "itemHeight": 77
52                                 }
53                                 </convert>
54                         </widget>
55                         <widget name="thumbnail" position="0,0" size="100,75" alphatest="on"/> # fake entry for dynamic thumbnail resizing, currently there is no other way doing this.
56
57                         <widget name="count" position="5,360" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
58                         <widget name="page" position="150,360" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
59                         <widget name="currentnumbers" position="295,360" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
60
61                         <ePixmap position="5,410" zPosition="0" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
62                         <ePixmap position="150,410" zPosition="1" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
63                         <ePixmap position="295,410" zPosition="2" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
64                         <!-- #not used now# ePixmap position="445,410" zPosition="3" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" //-->
65                         <widget name="key_red" position="5,410" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
66                         <widget name="key_green" position="150,410" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
67                         <widget name="key_yellow" position="295,410" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
68                         <widget name="key_blue" position="445,410" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
69
70                 </screen>"""
71                 self.skin = skin
72                 Screen.__init__(self, session)
73                 self.picloads = {}
74                 self.thumbnails = {}
75
76                 self["list"] = List([])
77                 self["thumbnail"] = Pixmap()
78                 self["thumbnail"].hide()
79
80                 self["count"] = Label(_("Cams: "))
81                 self["page"] = Label(_("Page: "))
82                 self["currentnumbers"] = Label(_("current: "))
83
84
85                 self["key_red"] = Button(_("prev"))
86                 self["key_red"].hide()
87                 self["key_green"] = Button(_("next"))
88                 self["key_green"].hide()
89                 self["key_yellow"] = Button(_("search"))
90                 self["key_blue"] = Button(_("hdkfjhg"))
91
92                 self["key_blue"].hide() #not used at the moment
93
94                 self["actions"] = ActionMap(["WizardActions", "MenuActions", "DirectionActions", "ShortcutActions"],
95                         {
96                          "ok": self.onOK,
97                          "red": self.onRed,
98                          "green": self.onGreen,
99                          "yellow": self.onYellow,
100                          "back": self.close
101                          }, -1)
102                 self.finish_loading = True
103                 self.timer_default = eTimer()
104                 self.timer_default_conn = self.timer_default.timeout.connect(self.buildCamList)
105
106                 self.timer_status = eTimer()
107                 self.timer_status_conn = self.timer_status.timeout.connect(self.buildStatusList)
108
109                 self.timer_labels = eTimer()
110                 self.timer_labels_conn = self.timer_labels.timeout.connect(self.refreshLabels)
111
112                 self.onLayoutFinish.append(self.loadData)
113
114         def onOK(self):
115                 selection = self["list"].getCurrent()
116                 if selection:
117                         print selection
118                         self.session.open(PictureScreen,selection[0].title,selection[0].pic_url)
119
120         def onRed(self):
121                 if self.hasPrevPage():
122                         self.timer_status.start(1)
123                         WebcamTravelerAPI().list_popular(self.onDataLoaded,_page=self.page-1)
124
125         def onGreen(self):
126                 if self.hasNextPage():
127                         self.timer_status.start(1)
128                         WebcamTravelerAPI().list_popular(self.onDataLoaded,_page=self.page+1)
129
130         def onYellow(self):
131                 self.session.openWithCallback(self.onSearchkeyEntered,InputBox, title=_("Please enter a searchkey:"), text="Search Webcams", maxSize=False, type=Input.TEXT)
132
133         def onSearchkeyEntered(self,value):
134                 if value is not None and self.finish_loading != False:
135                         self.timer_status.start(1)
136                         WebcamTravelerAPI().search(self.onDataLoaded,value)
137                         self.finish_loading = False
138
139         def loadData(self):
140                 if self.finish_loading != False:
141                         self.timer_status.start(1)
142                         WebcamTravelerAPI().list_popular(self.onDataLoaded)
143                         self.finish_loading = False
144
145         def onDataLoaded(self,list,count=0,page=0,per_page=0):
146                 print "onDataLoaded",list,count,page,per_page
147                 self.count =count
148                 self.page = page
149                 self.per_page = per_page
150
151                 self.pixmaps_to_load = []
152                 self.picloads = {}
153                 self.thumbnails = {}
154                 self.list = list
155                 self.downloadThumbnails()
156
157         def downloadThumbnails(self):
158                 for cam in self.list:
159                         self.pixmaps_to_load.append(cam.webcamid)
160                         downloadPage(cam.thumbnail_url,"/tmp/"+str(cam.webcamid)+"_thumb.jpg").addCallback(self.fetchFinished,cam.webcamid).addErrback(self.fetchFailed,cam.webcamid)
161
162         def fetchFailed(self,string,webcamid):
163                 print "fetchFailed",webcamid,string.getErrorMessage()
164                 self.buildEntryStatus(string.getErrorMessage())
165                 self.pixmaps_to_load.remove(webcamid)
166
167         def fetchFinished(self,x,webcamid):
168                 print "fetchFinished",x,webcamid
169                 self.pixmaps_to_load.remove(webcamid)
170
171                 sc = AVSwitch().getFramebufferScale()
172                 if (os_path_exists("/tmp/"+str(webcamid)+"_thumb.jpg") == True):
173                         self.picloads[webcamid] = ePicLoad()
174                         self.picloads[webcamid].conn = self.picloads[webcamid].PictureData.connect(boundFunction(self.finish_decode, webcamid))
175                         self.picloads[webcamid].setPara((self["thumbnail"].instance.size().width(), self["thumbnail"].instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
176                         self.picloads[webcamid].startDecode("/tmp/"+str(webcamid)+"_thumb.jpg")
177                 else:
178                         print "[decodePic] Thumbnail file NOT FOUND !!!-->:",thumbnailFile
179
180         def finish_decode(self,webcamid,info):
181                 print "finish_decode - of webcamid", webcamid,info
182                 ptr = self.picloads[webcamid].getData()
183                 if ptr != None:
184                         self.thumbnails[webcamid] = ptr
185                         print "removing file"
186                         os_remove("/tmp/"+str(webcamid)+"_thumb.jpg")
187                         del self.picloads[webcamid]
188                         self.timer_default.start(1)
189
190
191
192         def buildStatusList(self):
193                 self.timer_status.stop()
194                 print "buildStatusList"
195                 statuslist = []
196                 statuslist.append(self.buildEntryStatus("loading data"))
197
198                 self["list"].style = "status"
199                 self["list"].disable_callbacks = True
200                 self["list"].list = statuslist
201                 self["list"].disable_callbacks = False
202                 self["list"].setIndex(0)
203                 self["list"].setList(statuslist)
204                 self["list"].updateList(statuslist)
205
206
207         def buildCamList(self):
208                 if len(self.picloads) != 0:
209                         return
210                 self.timer_default.stop()
211                 print "buildCamList"
212                 statuslist = []
213                 for cam in self.list:
214                         try:
215                                 x= self.buildEntryCam(cam)
216                                 statuslist.append(x)
217                         except KeyError:
218                                 pass
219
220                 self["list"].style = "default"
221                 self["list"].disable_callbacks = True
222                 self["list"].list = statuslist
223                 self["list"].disable_callbacks = False
224                 self["list"].setIndex(0)
225                 self["list"].setList(statuslist)
226                 self["list"].updateList(statuslist)
227                 self.timer_labels.start(1)
228
229         def refreshLabels(self):
230                 self.timer_labels.stop()
231                 if self.hasNextPage():
232                         self["key_green"].show()
233                 else:
234                         self["key_green"].hide()
235
236                 if self.hasPrevPage():
237                         self["key_red"].show()
238                 else:
239                         self["key_red"].hide()
240                 self["count"].setText(_("Cams: ")+str(self.count))
241                 self["page"].setText(_("Page: ")+str(self.page)+"/"+str(self.count/self.per_page))
242                 self["currentnumbers"].setText(_("current: ")+str(((self.page-1)*self.per_page)+1)+"-"+str(((self.page-1)*self.per_page)+len(self.list)))
243
244                 self.finish_loading = True
245
246         def buildEntryCam(self, cam):
247                 return ((cam, cam.title, cam.webcamid,"last update",self.thumbnails[cam.webcamid], _("Last updated: ")+cam.last_update, _("Views: ")+cam.view_count, _("User: ")+cam.user, _("Ratings: ")+cam.rating_avg ))
248
249         def buildEntryStatus(self, text):
250                 return (("loading ...", "please wait just a moment","cccccccccccc","last update","1111111111111", _("Last updated: "), _("Views: "), _("Duration: ") , _("Ratings: ") ))
251
252         def hasNextPage(self):
253                 if (self.per_page*(self.page+1)>self.count):
254                         return False
255                 else:
256                         return True
257
258         def hasPrevPage(self):
259                 if (self.page>1):
260                         return True
261                 else:
262                         return False
263
264
265 #########################################
266
267
268
269 #########################################
270 # API ###################################
271 #########################################
272 #########################################
273 #########################################
274
275 class WebcamTravelerAPI:
276         APIKEY="e1019c6811f593a7cca1cf4f536da4c7"
277         URL_HOST = "api.webcams.travel"
278         URL_FORMAT = "rest"
279
280         def get(self,method,callback,errorback,**kwargs):
281                 url = "http://"+self.URL_HOST+"/"+self.URL_FORMAT+"?method="+method+"&devid="+self.APIKEY
282                 for key in kwargs:
283                         print key,kwargs[key]
284                         url +="&"+str(key)+"="+str(kwargs[key])
285                 print url
286                 cb = getPage(url).addCallback(callback)
287                 if errorback!=None:
288                         cb.addErrback(errorback)
289                 else:
290                         cb.addErrback(self.loadingFailed)
291
292         def loadingFailed(self,reason):
293                 print "loadingFailed",reason
294
295         def list_popular(self,callback,_page=1,_per_page=30):
296                 """     wct.webcams.list_popular
297                         Get the popular webcams.
298
299                         devid (required)
300                                 Your developer ID. If you do not have one, please signup for a developer ID.
301                         per_page (optional)
302                                 Number of webcams to return per page. If this argument is omitted, it defaults to 10. The maximum allowed value is 50.
303                         page (optional)
304                                 The page of results to return. If this argument is omitted, it defaults to 1.
305                 """
306                 cb = lambda raw: self.list_popularCB(raw,callback)
307                 self.get("wct.webcams.list_popular",cb,None,page=_page,per_page=_per_page)
308
309         def list_popularCB(self,raw,callback):
310                 dom = cElementTree_fromstring(raw)
311                 list, _count, _page, _per_page = self.parseWebcam(dom)
312                 callback(list,count=_count,page=_page,per_page=_per_page)
313
314         def parseWebcam(self,dom):
315                 cams= dom.findall("webcams")
316                 _count = int(cams[0].findtext("count", 0))
317                 _page = int(cams[0].findtext("page", 0))
318                 _per_page = int(cams[0].findtext("per_page", 0))
319                 list = []
320                 for cam in cams[0].findall("webcam"):
321                         ca = Cam(cam)
322                         list.append(ca)
323                 return list,_count, _page, _per_page
324
325         def search(self,callback,searchkey,_page=1,_per_page=30):
326                 """wct.search.webcams
327
328                         Search the webcams by the given query.
329
330
331                         Arguments
332
333                         devid (required)
334                         Your developer ID. If you do not have one, please signup for a developer ID.
335                         query (required)
336                         The query to search for.
337                         per_page (optional)
338                         Number of comments to return per page. If this argument is omitted, it defaults to 10. The maximum allowed value is 50.
339                         page (optional)
340                         The page of results to return. If this argument is omitted, it defaults to 1.
341                 """
342                 cb = lambda raw: self.searchCB(raw,callback)
343                 self.get("wct.search.webcams",cb,None,query=urllib_quote(searchkey),page=_page,per_page=_per_page)
344
345         def searchCB(self,raw,callback):
346                 dom = cElementTree_fromstring(raw)
347                 list, _count, _page, _per_page = self.parseWebcam(dom)
348                 callback(list,count=_count,page=_page,per_page=_per_page)
349
350
351 class Cam:
352         def __init__(self,element):
353                 self.title = element.findtext("title", 0).encode('utf-8',"ignore")
354                 self.webcamid = int(element.findtext("webcamid", 0))
355                 self.pic_url = "http://images.webcams.travel/webcam/"+str(self.webcamid)+".jpg"
356                 #self.icon_url = element.findtext("icon_url", 0)
357                 self.thumbnail_url = element.findtext("thumbnail_url", 0)
358                 self.view_count = element.findtext("view_count", 0)
359                 self.user = element.findtext("user", 0)
360                 self.userid = element.findtext("userid", 0)
361                 self.rating_avg = element.findtext("rating_avg", 0)
362                 self.rating_count = element.findtext("rating_count", 0)
363                 self.city = element.findtext("city", 0)
364                 self.country = element.findtext("country", 0)
365                 self.continent = element.findtext("continent", 0)
366                 self.latitude = element.findtext("latitude", 0)
367                 self.longitude = element.findtext("longitude", 0)
368
369                 datex = datetime.fromtimestamp(int(element.findtext("last_update", 0)))
370                 self.last_update = datex.strftime("%d.%m.%Y %H:%M:%S")
371
372
373
374