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
13 from enigma import eListboxPythonMultiContent, RT_HALIGN_LEFT, RT_HALIGN_RIGHT,ePicLoad,eTimer
15 from PictureScreen import PictureScreen
17 from twisted.web.client import getPage,downloadPage
18 #from twisted.internet import reactor
20 from xml.etree.cElementTree import fromstring as cElementTree_fromstring
22 from os import remove as os_remove
23 from os.path import exists as os_path_exists
24 from datetime import datetime
26 from urllib import quote as urllib_quote
27 #########################################
29 class TravelWebcamviewer(Screen):
31 def __init__(self, session, args = 0):
32 skin = """<screen position="93,70" size="550,450" title="Webcams provided by webcams.travel">
34 <widget source="list" render="Listbox" position="0,0" size="550,350" zPosition="1" scrollbarMode="showOnDemand" transparent="1" >
35 <convert type="TemplatedMultiContent">
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
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
50 "fonts": [gFont("Regular", 22),gFont("Regular", 18),gFont("Regular", 26),gFont("Regular", 20)],
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.
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" />
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" />
72 Screen.__init__(self, session)
76 self["list"] = List([])
77 self["thumbnail"] = Pixmap()
78 self["thumbnail"].hide()
80 self["count"] = Label(_("Cams: "))
81 self["page"] = Label(_("Page: "))
82 self["currentnumbers"] = Label(_("current: "))
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"))
92 self["key_blue"].hide() #not used at the moment
94 self["actions"] = ActionMap(["WizardActions", "MenuActions", "DirectionActions", "ShortcutActions"],
98 "green": self.onGreen,
99 "yellow": self.onYellow,
102 self.finish_loading = True
103 self.timer_default = eTimer()
104 self.timer_default.timeout.callback.append(self.buildCamList)
106 self.timer_status = eTimer()
107 self.timer_status.timeout.callback.append(self.buildStatusList)
109 self.timer_labels = eTimer()
110 self.timer_labels.timeout.callback.append(self.refreshLabels)
112 self.onLayoutFinish.append(self.loadData)
115 selection = self["list"].getCurrent()
118 self.session.open(PictureScreen,selection[0].title,selection[0].pic_url)
121 if self.hasPrevPage():
122 self.timer_status.start(1)
123 WebcamTravelerAPI().list_popular(self.onDataLoaded,_page=self.page-1)
126 if self.hasNextPage():
127 self.timer_status.start(1)
128 WebcamTravelerAPI().list_popular(self.onDataLoaded,_page=self.page+1)
131 self.session.openWithCallback(self.onSearchkeyEntered,InputBox, title=_("Please enter a searchkey:"), text="Search Webcams", maxSize=False, type=Input.TEXT)
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
140 if self.finish_loading != False:
141 self.timer_status.start(1)
142 WebcamTravelerAPI().list_popular(self.onDataLoaded)
143 self.finish_loading = False
145 def onDataLoaded(self,list,count=0,page=0,per_page=0):
146 print "onDataLoaded",list,count,page,per_page
149 self.per_page = per_page
151 self.pixmaps_to_load = []
155 self.downloadThumbnails()
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)
162 def fetchFailed(self,string,webcamid):
163 print "fetchFailed",webcamid,string.getErrorMessage()
164 self.buildEntryStatus(string.getErrorMessage())
165 self.pixmaps_to_load.remove(webcamid)
167 def fetchFinished(self,x,webcamid):
168 print "fetchFinished",x,webcamid
169 self.pixmaps_to_load.remove(webcamid)
171 sc = AVSwitch().getFramebufferScale()
172 if (os_path_exists("/tmp/"+str(webcamid)+"_thumb.jpg") == True):
173 self.picloads[webcamid] = ePicLoad()
174 self.picloads[webcamid].PictureData.get().append(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")
178 print "[decodePic] Thumbnail file NOT FOUND !!!-->:",thumbnailFile
180 def finish_decode(self,webcamid,info):
181 print "finish_decode - of webcamid", webcamid,info
182 ptr = self.picloads[webcamid].getData()
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)
192 def buildStatusList(self):
193 self.timer_status.stop()
194 print "buildStatusList"
196 statuslist.append(self.buildEntryStatus("loading data"))
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)
207 def buildCamList(self):
208 if len(self.picloads) != 0:
210 self.timer_default.stop()
213 for cam in self.list:
215 x= self.buildEntryCam(cam)
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)
229 def refreshLabels(self):
230 self.timer_labels.stop()
231 if self.hasNextPage():
232 self["key_green"].show()
234 self["key_green"].hide()
236 if self.hasPrevPage():
237 self["key_red"].show()
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)))
244 self.finish_loading = True
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 ))
249 def buildEntryStatus(self, text):
250 return (("loading ...", "please wait just a moment","cccccccccccc","last update","1111111111111", _("Last updated: "), _("Views: "), _("Duration: ") , _("Ratings: ") ))
252 def hasNextPage(self):
253 if (self.per_page*(self.page+1)>self.count):
258 def hasPrevPage(self):
265 #########################################
269 #########################################
270 # API ###################################
271 #########################################
272 #########################################
273 #########################################
275 class WebcamTravelerAPI:
276 APIKEY="e1019c6811f593a7cca1cf4f536da4c7"
277 URL_HOST = "api.webcams.travel"
280 def get(self,method,callback,errorback,**kwargs):
281 url = "http://"+self.URL_HOST+"/"+self.URL_FORMAT+"?method="+method+"&devid="+self.APIKEY
283 print key,kwargs[key]
284 url +="&"+str(key)+"="+str(kwargs[key])
286 cb = getPage(url).addCallback(callback)
288 cb.addErrback(errorback)
290 cb.addErrback(self.loadingFailed)
292 def loadingFailed(self,reason):
293 print "loadingFailed",reason
295 def list_popular(self,callback,_page=1,_per_page=30):
296 """ wct.webcams.list_popular
297 Get the popular webcams.
300 Your developer ID. If you do not have one, please signup for a developer ID.
302 Number of webcams to return per page. If this argument is omitted, it defaults to 10. The maximum allowed value is 50.
304 The page of results to return. If this argument is omitted, it defaults to 1.
306 cb = lambda raw: self.list_popularCB(raw,callback)
307 self.get("wct.webcams.list_popular",cb,None,page=_page,per_page=_per_page)
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)
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))
320 for cam in cams[0].findall("webcam"):
323 return list,_count, _page, _per_page
325 def search(self,callback,searchkey,_page=1,_per_page=30):
326 """wct.search.webcams
328 Search the webcams by the given query.
334 Your developer ID. If you do not have one, please signup for a developer ID.
336 The query to search for.
338 Number of comments to return per page. If this argument is omitted, it defaults to 10. The maximum allowed value is 50.
340 The page of results to return. If this argument is omitted, it defaults to 1.
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)
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)
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)
369 datex = datetime.fromtimestamp(int(element.findtext("last_update", 0)))
370 self.last_update = datex.strftime("%d.%m.%Y %H:%M:%S")