From: Rico Schulte Date: Sat, 30 May 2009 12:42:08 +0000 (+0000) Subject: adding support for webcams from http://webcam.travel X-Git-Url: http://code.vuplus.com/gitweb/?p=vuplus_dvbapp-plugin;a=commitdiff_plain;h=06e8e80a7522a192ab0e634e8d64fc497c9f04fc adding support for webcams from webcam.travel needs more work, but popular webcams are shown and you cam search for cams. --- diff --git a/webcamviewer/src/Makefile.am b/webcamviewer/src/Makefile.am index decb564..88e8ca0 100755 --- a/webcamviewer/src/Makefile.am +++ b/webcamviewer/src/Makefile.am @@ -1,5 +1,5 @@ installdir = /usr/lib/enigma2/python/Plugins/Extensions/WebcamViewer -install_PYTHON = __init__.py plugin.py PictureScreen.py WebcamViewConfig.py FTPDownloader.py +install_PYTHON = __init__.py plugin.py PictureScreen.py WebcamViewConfig.py FTPDownloader.py WebcamTravel.py install_DATA = webcam.xml pictureviewer.png webcamviewer.png LICENSE diff --git a/webcamviewer/src/WebcamTravel.py b/webcamviewer/src/WebcamTravel.py new file mode 100644 index 0000000..fb68318 --- /dev/null +++ b/webcamviewer/src/WebcamTravel.py @@ -0,0 +1,366 @@ +from Screens.Screen import Screen +from Components.Sources.List import List +from Components.Button import Button +from Components.Label import Label +from Components.ActionMap import ActionMap +from Screens.InputBox import InputBox +from Components.Input import Input +from Components.MultiContent import MultiContentEntryText, MultiContentEntryPixmapAlphaTest +from Components.Pixmap import Pixmap +from Components.AVSwitch import AVSwitch +from Tools.BoundFunction import boundFunction + +from enigma import eListboxPythonMultiContent, RT_HALIGN_LEFT, RT_HALIGN_RIGHT,ePicLoad,eTimer + +from PictureScreen import PictureScreen + +from twisted.web.client import getPage,downloadPage +#from twisted.internet import reactor + +from xml.etree.cElementTree import fromstring as cElementTree_fromstring + +from os import remove as os_remove +from os.path import exists as os_path_exists +from datetime import datetime + +from urllib import quote as urllib_quote +######################################### + +class TravelWebcamviewer(Screen): + skin = "" + def __init__(self, session, args = 0): + skin = """ + + + + {"templates": + {"default": (77,[ + MultiContentEntryPixmapAlphaTest(pos = (0, 0), size = (100, 75), png = 4), # index 4 is the thumbnail + 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 + 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 + 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 + 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 + 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 + ]), + "status": (77,[ + 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 + 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 + ]) + }, + "fonts": [gFont("Regular", 22),gFont("Regular", 18),gFont("Regular", 26),gFont("Regular", 20)], + "itemHeight": 77 + } + + + # fake entry for dynamic thumbnail resizing, currently there is no other way doing this. + + + + + + + + + + + + + + + """ + self.skin = skin + Screen.__init__(self, session) + self.picloads = {} + self.thumbnails = {} + + self["list"] = List([]) + self["thumbnail"] = Pixmap() + self["thumbnail"].hide() + + self["count"] = Label(_("Cams: ")) + self["page"] = Label(_("Page: ")) + self["currentnumbers"] = Label(_("current: ")) + + + self["key_red"] = Button(_("prev")) + self["key_red"].hide() + self["key_green"] = Button(_("next")) + self["key_green"].hide() + self["key_yellow"] = Button(_("search")) + self["key_blue"] = Button(_("hdkfjhg")) + + self["key_blue"].hide() #not used at the moment + + self["actions"] = ActionMap(["WizardActions", "MenuActions", "DirectionActions", "ShortcutActions"], + { + "ok": self.onOK, + "red": self.onRed, + "green": self.onGreen, + "yellow": self.onYellow, + "back": self.close + }, -1) + + self.timer_default = eTimer() + self.timer_default.timeout.callback.append(self.buildCamList) + + self.timer_status = eTimer() + self.timer_status.timeout.callback.append(self.buildStatusList) + + self.timer_labels = eTimer() + self.timer_labels.timeout.callback.append(self.refreshLabels) + + self.onLayoutFinish.append(self.loadData) + + def onOK(self): + selection = self["list"].getCurrent() + if selection: + print selection + self.session.open(PictureScreen,selection[0].title,selection[0].pic_url) + + def onRed(self): + if self.hasPrevPage(): + self.timer_status.start(1) + WebcamTravelerAPI().list_popular(self.onDataLoaded,_page=self.page-1) + + def onGreen(self): + if self.hasNextPage(): + self.timer_status.start(1) + WebcamTravelerAPI().list_popular(self.onDataLoaded,_page=self.page+1) + + def onYellow(self): + self.session.openWithCallback(self.onSearchkeyEntered,InputBox, title=_("Please enter a searchkey:"), text="Search Webcams", maxSize=False, type=Input.TEXT) + + def onSearchkeyEntered(self,value): + if value is not None: + self.timer_status.start(1) + WebcamTravelerAPI().search(self.onDataLoaded,value) + + def loadData(self): + self.timer_status.start(1) + WebcamTravelerAPI().list_popular(self.onDataLoaded) + + def onDataLoaded(self,list,count=0,page=0,per_page=0): + print "onDataLoaded",list,count,page,per_page + self.count =count + self.page = page + self.per_page = per_page + + self.pixmaps_to_load = [] + self.picloads = {} + self.thumbnails = {} + self.list = list + self.downloadThumbnails() + + def downloadThumbnails(self): + for cam in self.list: + self.pixmaps_to_load.append(cam.webcamid) + downloadPage(cam.thumbnail_url,"/tmp/"+str(cam.webcamid)+"_thumb.jpg").addCallback(self.fetchFinished,cam.webcamid).addErrback(self.fetchFailed,cam.webcamid) + + def fetchFailed(self,string,webcamid): + print "fetchFailed",webcamid,string.getErrorMessage() + self.buildEntryStatus(string.getErrorMessage()) + self.pixmaps_to_load.remove(webcamid) + + def fetchFinished(self,x,webcamid): + print "fetchFinished",x,webcamid + self.pixmaps_to_load.remove(webcamid) + + sc = AVSwitch().getFramebufferScale() + if (os_path_exists("/tmp/"+str(webcamid)+"_thumb.jpg") == True): + self.picloads[webcamid] = ePicLoad() + self.picloads[webcamid].PictureData.get().append(boundFunction(self.finish_decode, webcamid)) + self.picloads[webcamid].setPara((self["thumbnail"].instance.size().width(), self["thumbnail"].instance.size().height(), sc[0], sc[1], False, 1, "#00000000")) + self.picloads[webcamid].startDecode("/tmp/"+str(webcamid)+"_thumb.jpg") + else: + print "[decodePic] Thumbnail file NOT FOUND !!!-->:",thumbnailFile + + def finish_decode(self,webcamid,info): + print "finish_decode - of webcamid", webcamid,info + ptr = self.picloads[webcamid].getData() + if ptr != None: + self.thumbnails[webcamid] = ptr + print "removing file" + os_remove("/tmp/"+str(webcamid)+"_thumb.jpg") + del self.picloads[webcamid] + self.timer_default.start(1) + + + + def buildStatusList(self): + self.timer_status.stop() + print "buildStatusList" + statuslist = [] + statuslist.append(self.buildEntryStatus("loading data")) + + self["list"].style = "status" + self["list"].disable_callbacks = True + self["list"].list = statuslist + self["list"].disable_callbacks = False + self["list"].setIndex(0) + self["list"].setList(statuslist) + self["list"].updateList(statuslist) + + + def buildCamList(self): + if len(self.picloads) != 0: + return + self.timer_default.stop() + print "buildCamList" + statuslist = [] + for cam in self.list: + x= self.buildEntryCam(cam) + statuslist.append(x) + + self["list"].style = "default" + self["list"].disable_callbacks = True + self["list"].list = statuslist + self["list"].disable_callbacks = False + self["list"].setIndex(0) + self["list"].setList(statuslist) + self["list"].updateList(statuslist) + self.timer_labels.start(1) + + def refreshLabels(self): + self.timer_labels.stop() + if self.hasNextPage(): + self["key_green"].show() + else: + self["key_green"].hide() + + if self.hasPrevPage(): + self["key_red"].show() + else: + self["key_red"].hide() + self["count"].setText(_("Cams: ")+str(self.count)) + self["page"].setText(_("Page: ")+str(self.page)+"/"+str(self.count/self.per_page)) + self["currentnumbers"].setText(_("current: ")+str(((self.page-1)*self.per_page)+1)+"-"+str(((self.page-1)*self.per_page)+len(self.list))) + + def buildEntryCam(self, cam): + 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 )) + + def buildEntryStatus(self, text): + return (("loading ...", "please wait just a moment","cccccccccccc","last update","1111111111111", _("Last updated: "), _("Views: "), _("Duration: ") , _("Ratings: ") )) + + def hasNextPage(self): + if (self.per_page*(self.page+1)>self.count): + return False + else: + return True + + def hasPrevPage(self): + if (self.page>1): + return True + else: + return False + + +######################################### + + + +######################################### +# API ################################### +######################################### +######################################### +######################################### + +class WebcamTravelerAPI: + APIKEY="e1019c6811f593a7cca1cf4f536da4c7" + URL_HOST = "api.webcams.travel" + URL_FORMAT = "rest" + + def get(self,method,callback,errorback,**kwargs): + url = "http://"+self.URL_HOST+"/"+self.URL_FORMAT+"?method="+method+"&devid="+self.APIKEY + for key in kwargs: + print key,kwargs[key] + url +="&"+str(key)+"="+str(kwargs[key]) + print url + cb = getPage(url).addCallback(callback) + if errorback!=None: + cb.addErrback(errorback) + else: + cb.addErrback(self.loadingFailed) + + def loadingFailed(self,reason): + print "loadingFailed",reason + + def list_popular(self,callback,_page=1,_per_page=30): + """ wct.webcams.list_popular + Get the popular webcams. + + devid (required) + Your developer ID. If you do not have one, please signup for a developer ID. + per_page (optional) + Number of webcams to return per page. If this argument is omitted, it defaults to 10. The maximum allowed value is 50. + page (optional) + The page of results to return. If this argument is omitted, it defaults to 1. + """ + cb = lambda raw: self.list_popularCB(raw,callback) + self.get("wct.webcams.list_popular",cb,None,page=_page,per_page=_per_page) + + def list_popularCB(self,raw,callback): + dom = cElementTree_fromstring(raw) + list, _count, _page, _per_page = self.parseWebcam(dom) + callback(list,count=_count,page=_page,per_page=_per_page) + + def parseWebcam(self,dom): + cams= dom.findall("webcams") + _count = int(cams[0].findtext("count", 0)) + _page = int(cams[0].findtext("page", 0)) + _per_page = int(cams[0].findtext("per_page", 0)) + list = [] + for cam in cams[0].findall("webcam"): + ca = Cam(cam) + list.append(ca) + return list,_count, _page, _per_page + + def search(self,callback,searchkey,_page=1,_per_page=30): + """wct.search.webcams + + Search the webcams by the given query. + + + Arguments + + devid (required) + Your developer ID. If you do not have one, please signup for a developer ID. + query (required) + The query to search for. + per_page (optional) + Number of comments to return per page. If this argument is omitted, it defaults to 10. The maximum allowed value is 50. + page (optional) + The page of results to return. If this argument is omitted, it defaults to 1. + """ + cb = lambda raw: self.searchCB(raw,callback) + self.get("wct.search.webcams",cb,None,query=urllib_quote(searchkey),page=_page,per_page=_per_page) + + def searchCB(self,raw,callback): + dom = cElementTree_fromstring(raw) + list, _count, _page, _per_page = self.parseWebcam(dom) + callback(list,count=_count,page=_page,per_page=_per_page) + + +class Cam: + def __init__(self,element): + self.title = element.findtext("title", 0).encode('utf-8',"ignore") + self.webcamid = int(element.findtext("webcamid", 0)) + self.pic_url = "http://images.webcams.travel/webcam/"+str(self.webcamid)+".jpg" + #self.icon_url = element.findtext("icon_url", 0) + self.thumbnail_url = element.findtext("thumbnail_url", 0) + self.view_count = element.findtext("view_count", 0) + self.user = element.findtext("user", 0) + self.userid = element.findtext("userid", 0) + self.rating_avg = element.findtext("rating_avg", 0) + self.rating_count = element.findtext("rating_count", 0) + self.city = element.findtext("city", 0) + self.country = element.findtext("country", 0) + self.continent = element.findtext("continent", 0) + self.latitude = element.findtext("latitude", 0) + self.longitude = element.findtext("longitude", 0) + + datex = datetime.fromtimestamp(int(element.findtext("last_update", 0))) + self.last_update = datex.strftime("%d.%m.%Y %H:%M:%S") + + + + diff --git a/webcamviewer/src/plugin.py b/webcamviewer/src/plugin.py index 9c221b5..5a62faf 100755 --- a/webcamviewer/src/plugin.py +++ b/webcamviewer/src/plugin.py @@ -28,6 +28,7 @@ import xml.dom.minidom ### my from WebcamViewConfig import WebcamViewerMenu from PictureScreen import PictureScreen +from WebcamTravel import TravelWebcamviewer ### myname = "Webcam/Picture Viewer" myversion = "1.1" @@ -47,7 +48,8 @@ SLIDESHOWMODE_REPEAT = 1 originalservice = None mysession = None -def main1(session, **kwargs): + +def startPictureviewer(session, **kwargs): global originalservice, mysession mysession = session originalservice = session.nav.getCurrentlyPlayingServiceReference() @@ -55,7 +57,7 @@ def main1(session, **kwargs): session.nav.stopService() session.openWithCallback(mainCB, PictureViewer) -def main2(session, **kwargs): +def startWebcamviewer(session, **kwargs): global originalservice, mysession mysession = session originalservice = session.nav.getCurrentlyPlayingServiceReference() @@ -79,6 +81,9 @@ def main2(session, **kwargs): MessageBox.TYPE_WARNING ) + + + def mainCB(): global originalservice, mysession if config.plugins.pictureviewer.stopserviceonstart.value: @@ -90,20 +95,45 @@ def Plugins(path, **kwargs): name="PictureViewer", description="browse your local pictures", where = PluginDescriptor.WHERE_PLUGINMENU, - fnc = main1, + fnc = startPictureviewer, icon="pictureviewer.png" ), PluginDescriptor( name="WebcamViewer", description="view webcams around the world", where = PluginDescriptor.WHERE_PLUGINMENU, - fnc = main2, + fnc = startWebcamviewer, icon="webcamviewer.png" ) ] return p ################### +class ViewerSelectScreen(Screen): + skin = "" + def __init__(self, session, args = 0): + skin = """ + + """ + self.skin = skin + Screen.__init__(self, session) + self.slideshowfiles = [] + self.slideshowfiles.append((_("WebcamViewer"),STARTWEBCAMVIEWER)) + self.slideshowfiles.append((_("online webcam.travel"),STARTWEBCAMTRAVEL)) + self["list"] = MenuList(self.slideshowfiles) + self["actions"] = ActionMap(["WizardActions", "MenuActions", "DirectionActions", "ShortcutActions"], + { + "ok": self.go, + "back": self.close + }, -1) + + def go(self): + selection = self["list"].getCurrent() + if selection: + self.close(self.session,selection[1]) + + +################### class Slideshow: filelist = [] currentslideshowitem = 0 @@ -433,7 +463,9 @@ class WebcamViewer(Screen): menuitemtitle = self["menu"].l.getCurrentSelection()[0] type = selected[0] data = selected[1] - if type.startswith("cam"): + if menuitemtitle.startswith("webcam.travel"): + self.session.openWithCallback(self.cb, TravelWebcamviewer) + elif type.startswith("cam"): self.session.open(PictureScreen, menuitemtitle, data) else: self.hide() @@ -446,6 +478,8 @@ class WebcamViewer(Screen): xloader = XMLloader() self.menutitle = xloader.getScreenXMLTitle(self.xmlnode) data =[] + if self.menutitle =="Mainmenu": + data.append((_("webcam.travel"), "webcam.travel")) for node in self.xmlnode.childNodes: if node.nodeType != xml.dom.minidom.Element.nodeType or node.tagName != 'menu': continue