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,
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:
135 self.timer_status.start(1)
136 WebcamTravelerAPI().search(self.onDataLoaded,value)
139 self.timer_status.start(1)
140 WebcamTravelerAPI().list_popular(self.onDataLoaded)
142 def onDataLoaded(self,list,count=0,page=0,per_page=0):
143 print "onDataLoaded",list,count,page,per_page
146 self.per_page = per_page
148 self.pixmaps_to_load = []
152 self.downloadThumbnails()
154 def downloadThumbnails(self):
155 for cam in self.list:
156 self.pixmaps_to_load.append(cam.webcamid)
157 downloadPage(cam.thumbnail_url,"/tmp/"+str(cam.webcamid)+"_thumb.jpg").addCallback(self.fetchFinished,cam.webcamid).addErrback(self.fetchFailed,cam.webcamid)
159 def fetchFailed(self,string,webcamid):
160 print "fetchFailed",webcamid,string.getErrorMessage()
161 self.buildEntryStatus(string.getErrorMessage())
162 self.pixmaps_to_load.remove(webcamid)
164 def fetchFinished(self,x,webcamid):
165 print "fetchFinished",x,webcamid
166 self.pixmaps_to_load.remove(webcamid)
168 sc = AVSwitch().getFramebufferScale()
169 if (os_path_exists("/tmp/"+str(webcamid)+"_thumb.jpg") == True):
170 self.picloads[webcamid] = ePicLoad()
171 self.picloads[webcamid].PictureData.get().append(boundFunction(self.finish_decode, webcamid))
172 self.picloads[webcamid].setPara((self["thumbnail"].instance.size().width(), self["thumbnail"].instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
173 self.picloads[webcamid].startDecode("/tmp/"+str(webcamid)+"_thumb.jpg")
175 print "[decodePic] Thumbnail file NOT FOUND !!!-->:",thumbnailFile
177 def finish_decode(self,webcamid,info):
178 print "finish_decode - of webcamid", webcamid,info
179 ptr = self.picloads[webcamid].getData()
181 self.thumbnails[webcamid] = ptr
182 print "removing file"
183 os_remove("/tmp/"+str(webcamid)+"_thumb.jpg")
184 del self.picloads[webcamid]
185 self.timer_default.start(1)
189 def buildStatusList(self):
190 self.timer_status.stop()
191 print "buildStatusList"
193 statuslist.append(self.buildEntryStatus("loading data"))
195 self["list"].style = "status"
196 self["list"].disable_callbacks = True
197 self["list"].list = statuslist
198 self["list"].disable_callbacks = False
199 self["list"].setIndex(0)
200 self["list"].setList(statuslist)
201 self["list"].updateList(statuslist)
204 def buildCamList(self):
205 if len(self.picloads) != 0:
207 self.timer_default.stop()
210 for cam in self.list:
211 x= self.buildEntryCam(cam)
214 self["list"].style = "default"
215 self["list"].disable_callbacks = True
216 self["list"].list = statuslist
217 self["list"].disable_callbacks = False
218 self["list"].setIndex(0)
219 self["list"].setList(statuslist)
220 self["list"].updateList(statuslist)
221 self.timer_labels.start(1)
223 def refreshLabels(self):
224 self.timer_labels.stop()
225 if self.hasNextPage():
226 self["key_green"].show()
228 self["key_green"].hide()
230 if self.hasPrevPage():
231 self["key_red"].show()
233 self["key_red"].hide()
234 self["count"].setText(_("Cams: ")+str(self.count))
235 self["page"].setText(_("Page: ")+str(self.page)+"/"+str(self.count/self.per_page))
236 self["currentnumbers"].setText(_("current: ")+str(((self.page-1)*self.per_page)+1)+"-"+str(((self.page-1)*self.per_page)+len(self.list)))
238 def buildEntryCam(self, cam):
239 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 ))
241 def buildEntryStatus(self, text):
242 return (("loading ...", "please wait just a moment","cccccccccccc","last update","1111111111111", _("Last updated: "), _("Views: "), _("Duration: ") , _("Ratings: ") ))
244 def hasNextPage(self):
245 if (self.per_page*(self.page+1)>self.count):
250 def hasPrevPage(self):
257 #########################################
261 #########################################
262 # API ###################################
263 #########################################
264 #########################################
265 #########################################
267 class WebcamTravelerAPI:
268 APIKEY="e1019c6811f593a7cca1cf4f536da4c7"
269 URL_HOST = "api.webcams.travel"
272 def get(self,method,callback,errorback,**kwargs):
273 url = "http://"+self.URL_HOST+"/"+self.URL_FORMAT+"?method="+method+"&devid="+self.APIKEY
275 print key,kwargs[key]
276 url +="&"+str(key)+"="+str(kwargs[key])
278 cb = getPage(url).addCallback(callback)
280 cb.addErrback(errorback)
282 cb.addErrback(self.loadingFailed)
284 def loadingFailed(self,reason):
285 print "loadingFailed",reason
287 def list_popular(self,callback,_page=1,_per_page=30):
288 """ wct.webcams.list_popular
289 Get the popular webcams.
292 Your developer ID. If you do not have one, please signup for a developer ID.
294 Number of webcams to return per page. If this argument is omitted, it defaults to 10. The maximum allowed value is 50.
296 The page of results to return. If this argument is omitted, it defaults to 1.
298 cb = lambda raw: self.list_popularCB(raw,callback)
299 self.get("wct.webcams.list_popular",cb,None,page=_page,per_page=_per_page)
301 def list_popularCB(self,raw,callback):
302 dom = cElementTree_fromstring(raw)
303 list, _count, _page, _per_page = self.parseWebcam(dom)
304 callback(list,count=_count,page=_page,per_page=_per_page)
306 def parseWebcam(self,dom):
307 cams= dom.findall("webcams")
308 _count = int(cams[0].findtext("count", 0))
309 _page = int(cams[0].findtext("page", 0))
310 _per_page = int(cams[0].findtext("per_page", 0))
312 for cam in cams[0].findall("webcam"):
315 return list,_count, _page, _per_page
317 def search(self,callback,searchkey,_page=1,_per_page=30):
318 """wct.search.webcams
320 Search the webcams by the given query.
326 Your developer ID. If you do not have one, please signup for a developer ID.
328 The query to search for.
330 Number of comments to return per page. If this argument is omitted, it defaults to 10. The maximum allowed value is 50.
332 The page of results to return. If this argument is omitted, it defaults to 1.
334 cb = lambda raw: self.searchCB(raw,callback)
335 self.get("wct.search.webcams",cb,None,query=urllib_quote(searchkey),page=_page,per_page=_per_page)
337 def searchCB(self,raw,callback):
338 dom = cElementTree_fromstring(raw)
339 list, _count, _page, _per_page = self.parseWebcam(dom)
340 callback(list,count=_count,page=_page,per_page=_per_page)
344 def __init__(self,element):
345 self.title = element.findtext("title", 0).encode('utf-8',"ignore")
346 self.webcamid = int(element.findtext("webcamid", 0))
347 self.pic_url = "http://images.webcams.travel/webcam/"+str(self.webcamid)+".jpg"
348 #self.icon_url = element.findtext("icon_url", 0)
349 self.thumbnail_url = element.findtext("thumbnail_url", 0)
350 self.view_count = element.findtext("view_count", 0)
351 self.user = element.findtext("user", 0)
352 self.userid = element.findtext("userid", 0)
353 self.rating_avg = element.findtext("rating_avg", 0)
354 self.rating_count = element.findtext("rating_count", 0)
355 self.city = element.findtext("city", 0)
356 self.country = element.findtext("country", 0)
357 self.continent = element.findtext("continent", 0)
358 self.latitude = element.findtext("latitude", 0)
359 self.longitude = element.findtext("longitude", 0)
361 datex = datetime.fromtimestamp(int(element.findtext("last_update", 0)))
362 self.last_update = datex.strftime("%d.%m.%Y %H:%M:%S")