add Webcam/Pictureviewer
authorRico Schulte <ricoschulte@users.schwerkraft.elitedvb.net>
Sun, 9 Sep 2007 10:41:05 +0000 (10:41 +0000)
committerRico Schulte <ricoschulte@users.schwerkraft.elitedvb.net>
Sun, 9 Sep 2007 10:41:05 +0000 (10:41 +0000)
initial version

webcamviewer/CONTROL/control [new file with mode: 0755]
webcamviewer/Makefile.am [new file with mode: 0755]
webcamviewer/src/Makefile.am [new file with mode: 0755]
webcamviewer/src/PictureScreen.py [new file with mode: 0755]
webcamviewer/src/WebcamViewConfig.py [new file with mode: 0755]
webcamviewer/src/__init__.py [new file with mode: 0755]
webcamviewer/src/plugin.py [new file with mode: 0755]
webcamviewer/src/webcam.xml [new file with mode: 0755]

diff --git a/webcamviewer/CONTROL/control b/webcamviewer/CONTROL/control
new file mode 100755 (executable)
index 0000000..4fcf9b8
--- /dev/null
@@ -0,0 +1,10 @@
+Package: enigma2-plugin-extensions-webcamviewer
+Version: 1.1
+Description: view Pictures and Webcams on your TV Screen
+Architecture: mipsel
+Section: extra
+Priority: optional
+Maintainer: 3c5x9 <3c5x9@gmx.net>
+Homepage: n/a
+Depends: enigma2(>1.0cvs20070908), twisted-web 
+Source: http://enigma2-plugins.schwerkraft.elitedvb.net/
diff --git a/webcamviewer/Makefile.am b/webcamviewer/Makefile.am
new file mode 100755 (executable)
index 0000000..af437a6
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = src
diff --git a/webcamviewer/src/Makefile.am b/webcamviewer/src/Makefile.am
new file mode 100755 (executable)
index 0000000..e3aeae9
--- /dev/null
@@ -0,0 +1,5 @@
+installdir = /usr/lib/enigma2/python/Plugins/Extensions/WebcamViewer
+
+install_PYTHON = __init__.py plugin.py PictureScreen.py WebcamViewConfig.py
+
+install_DATA = webcam.xml
diff --git a/webcamviewer/src/PictureScreen.py b/webcamviewer/src/PictureScreen.py
new file mode 100755 (executable)
index 0000000..caaa484
--- /dev/null
@@ -0,0 +1,95 @@
+from enigma import loadPic
+from enigma import eTimer
+
+from Screens.Screen import Screen
+from Components.AVSwitch import AVSwitch
+from Components.config import config
+from Components.Pixmap import Pixmap
+from Components.ActionMap import ActionMap
+from twisted.web.client import downloadPage
+
+class PictureScreen(Screen):
+    skin = ""
+    prozessing =False # if fetching or converting is active
+    autoreload =False
+    def __init__(self, session,title,filename, slideshowcallback = None,args=0):
+        self.session=session
+        self.slideshowcallback=slideshowcallback
+        self.screentitle = title
+        self.skin = """
+        <screen position="0,0" size="720,576" title="%s" flags=\"wfNoBorder\">
+             <widget name="pixmap" position="0,0" size="720,576" backgroundColor=\"black\"/>
+        </screen>""" % (filename)
+        Screen.__init__(self, session)
+        self.filename = filename
+        self["pixmap"] = Pixmap()
+        
+        self["actions"] = ActionMap(["WizardActions", "DirectionActions","ChannelSelectBaseActions","ShortcutActions"], 
+            {
+             "ok": self.do,
+             "back": self.exit,
+             "green":self.AutoReloaderSwitch,
+             }, -1)
+        
+        self.onLayoutFinish.append(self.do)
+        
+    def AutoReloaderSwitch(self):
+        if self.filename.startswith("http") or self.filename.startswith("ftp"):            
+            if self.autoreload is False:
+                self.autoreload = True
+                self.do()
+            else:
+                self.autoreload = False
+            
+    def do(self): 
+        if self.prozessing:
+            pass       
+        elif self.filename.startswith("http") or self.filename.startswith("ftp"):            
+            self.fetchFile(self.filename)
+        else:
+            self.sourcefile = self.filename
+            self.setPicture(self.filename)
+
+    def exit(self):
+        self.cleanUP()
+        self.close()
+
+    def cleanUP(self):
+        try:
+            if os.path.exists("/tmp/loadedfile"):
+                os.remove("/tmp/loadedfile")
+        except:## OSerror??
+            pass
+    
+    def fetchFile(self,url):
+        self.prozessing =True        
+        self.setTitle("loading File")
+        print "fetching URL ",url
+        self.sourcefile = "/tmp/loadedfile"
+        downloadPage(url,self.sourcefile).addCallback(self.fetchFinished).addErrback(self.fetchFailed)
+            
+        
+    def fetchFailed(self,string):
+        print "fetch failed",string
+        self.setTitle( "fetch failed: "+string)
+        
+    def fetchFinished(self,string):
+        print "fetching finished "
+        self.setPicture(self.sourcefile)   
+              
+    def setPicture(self,string):
+        self.setTitle(self.filename.split("/")[-1])        
+        pixmap = loadPic(string,720,576, AVSwitch().getAspectRatioSetting()/2,1, 0,1)
+        if pixmap is not None:
+            self["pixmap"].instance.setPixmap(pixmap)
+        self.prozessing =False
+        
+        if self.autoreload is True:
+                self.cleanUP()
+                self.do()
+        elif self.slideshowcallback is not None:
+                self.closetimer = eTimer()
+                self.closetimer.timeout.get().append(self.slideshowcallback)
+                print "waiting ",config.plugins.pictureviewer.slideshowtime.value," seconds for next picture"
+                self.closetimer.start(int(config.plugins.pictureviewer.slideshowtime.value))
+        
diff --git a/webcamviewer/src/WebcamViewConfig.py b/webcamviewer/src/WebcamViewConfig.py
new file mode 100755 (executable)
index 0000000..48b7c31
--- /dev/null
@@ -0,0 +1,43 @@
+from Screens.Screen import Screen
+from Components.ConfigList import ConfigListScreen
+from Components.Label import Label
+from Components.config import config, getConfigListEntry
+from Components.ActionMap import ActionMap
+
+
+class WebcamViewerMenu(ConfigListScreen,Screen):
+    skin = """
+        <screen position="100,100" size="550,400" title="Setup" >
+        <widget name="config" position="0,0" size="550,360" scrollbarMode="showOnDemand" />
+        <widget name="buttonred" position="10,360" size="100,40" backgroundColor="red" valign="center" halign="center" zPosition="2"  foregroundColor="white" font="Regular;18"/> 
+        <widget name="buttongreen" position="120,360" size="100,40" backgroundColor="green" valign="center" halign="center" zPosition="2"  foregroundColor="white" font="Regular;18"/> 
+        </screen>"""
+    def __init__(self, session, args = 0):
+        self.session = session
+        Screen.__init__(self, session)
+        self.list = []
+        self.list.append(getConfigListEntry(_("Slideshow Time"), config.plugins.pictureviewer.slideshowtime))
+        self.list.append(getConfigListEntry(_("Slideshow Mode"), config.plugins.pictureviewer.slideshowmode))
+        ConfigListScreen.__init__(self, self.list)
+        self["buttonred"] = Label(_("cancel"))
+        self["buttongreen"] = Label(_("ok"))
+        self["setupActions"] = ActionMap(["SetupActions"],
+        {
+            "green": self.save,
+            "red": self.cancel,
+            "save": self.save,
+            "cancel": self.cancel,
+            "ok": self.save,
+        }, -2)
+
+    def save(self):
+        print "saving"
+        for x in self["config"].list:
+            x[1].save()
+        self.close(True,self.session)
+
+    def cancel(self):
+        print "cancel"
+        for x in self["config"].list:
+            x[1].cancel()
+        self.close(False,self.session)
diff --git a/webcamviewer/src/__init__.py b/webcamviewer/src/__init__.py
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/webcamviewer/src/plugin.py b/webcamviewer/src/plugin.py
new file mode 100755 (executable)
index 0000000..609739c
--- /dev/null
@@ -0,0 +1,519 @@
+from enigma import eListbox\r
+from enigma import eListboxPythonMultiContent\r
+from enigma import loadPic\r
+from enigma import loadPNG\r
+from enigma import gFont\r
+### Picturelist\r
+from Components.HTMLComponent import HTMLComponent\r
+from Components.GUIComponent import GUIComponent\r
+from Screens.Screen import Screen\r
+from Screens.MessageBox import MessageBox\r
+from Screens.InputBox import InputBox\r
+from Screens.ChoiceBox import ChoiceBox\r
+from Components.ActionMap import ActionMap, NumberActionMap\r
+from Components.ScrollLabel import ScrollLabel\r
+from Components.Label import Label\r
+from Components.MenuList import MenuList\r
+from Components.FileList import EXTENSIONS\r
+## configmenu\r
+from Components.config import config, ConfigSubsection,ConfigSelection,ConfigText,getConfigListEntry\r
+from Components.ConfigList import ConfigListScreen\r
+####\r
+from Components.Input import Input\r
+from Components.Pixmap import Pixmap\r
+from Plugins.Plugin import PluginDescriptor\r
+### System\r
+import os\r
+import re\r
+## XML\r
+from pyexpat import ExpatError\r
+import xml.dom.minidom\r
+from Tools.XMLTools import mergeText, elementsWithTag\r
+\r
+### my\r
+from WebcamViewConfig import WebcamViewerMenu\r
+from PictureScreen import PictureScreen\r
+###\r
+myname = "Webcam/Picture Viewer"    \r
+myversion = "1.1"\r
+\r
+\r
+\r
+config.plugins.pictureviewer = ConfigSubsection()\r
+config.plugins.pictureviewer.slideshowtime = ConfigSelection(default="5000", choices = [("5000", _("5 Sekunden")), ("10000", _("10 Sekunden")), ("20000", _("20 Sekunden")), ("60000", _("1 Minute"))])\r
+config.plugins.pictureviewer.slideshowmode = ConfigSelection(default="0", choices = [("0", _("normal")), ("1", _("endlos"))])\r
+#not editable configs\r
+config.plugins.pictureviewer.slideshowext = ConfigText(default=".3ssl")\r
+config.plugins.pictureviewer.matchingPattern = ConfigText(default="(?i)^.*\.(jpeg|jpg|jpe|png|bmp|gif)")\r
+config.plugins.pictureviewer.slideshowdir = ConfigText(default="/media/hdd/slideshows/")\r
+config.plugins.pictureviewer.rootdir = ConfigText(default="/media/")\r
+SLIDESHOWMODE_NORMAL = 0\r
+SLIDESHOWMODE_REPEAT = 1\r
+\r
+    \r
+def main1(session,**kwargs):\r
+    session.open(PictureViewer)\r
+\r
+def main2(session,**kwargs):\r
+    xmlfile = "/usr/lib/enigma2/python/Plugins/Extensions/WebcamViewer/webcam.xml"\r
+    if os.path.isfile(xmlfile):\r
+        try:\r
+            xmlnode = xml.dom.minidom.parse( open(xmlfile) )\r
+            session.open(WebcamViewer,xmlnode.childNodes[1])\r
+        except ExpatError,e:\r
+            session.open(MessageBox,_("Loading config file failed!\n\n%s"%e), MessageBox.TYPE_WARNING)\r
+    else:\r
+        session.open(MessageBox,_("Loading config file failed!\n\nconfigfile not found!"), MessageBox.TYPE_WARNING)\r
+        \r
+    \r
+def Plugins(path,**kwargs):\r
+    p = [\r
+             PluginDescriptor(\r
+                              name="PictureViewer", \r
+                              description="browse your local pictures", \r
+                              where = PluginDescriptor.WHERE_PLUGINMENU,\r
+                              fnc = main1\r
+                              )\r
+        ,\r
+            PluginDescriptor(\r
+                             name="WebcamViewer", \r
+                             description="view webcams around the world", \r
+                             where = PluginDescriptor.WHERE_PLUGINMENU,\r
+                             fnc = main2\r
+                             )\r
+         ]\r
+    return p \r
+\r
+\r
+        \r
+\r
+###################\r
+class Slideshow:\r
+    filelist=[]\r
+    currentslideshowitem =0\r
+    wbviewer = False\r
+    def __init__(self,session,callback):\r
+        self.session = session\r
+        self.callback = callback\r
+    def setfiles(self,filelist):\r
+        self.filelist = filelist \r
+\r
+    def start(self):\r
+        if len(self.filelist)>0:            \r
+            self.currentslideshowitem = -1\r
+            self.nextSlideshowItem()\r
+            \r
+    def nextSlideshowItem(self):\r
+        if self.currentslideshowitem is not (len(self.filelist)-1):\r
+            self.currentslideshowitem = self.currentslideshowitem+1\r
+            filetoshow = self.filelist[self.currentslideshowitem][1]\r
+            if self.wbviewer is False:\r
+                self.wbviewer = self.session.openWithCallback(self.cb,PictureScreen,filetoshow.split("/")[-1],filetoshow,slideshowcallback=self.nextSlideshowItem)              \r
+            else:\r
+                self.wbviewer.filename = filetoshow\r
+                self.wbviewer.do()    \r
+        elif self.currentslideshowitem is (len(self.filelist)-1) and int(config.plugins.pictureviewer.slideshowmode.value) is SLIDESHOWMODE_REPEAT:\r
+            print "["+myname+"] restarting slideshow"\r
+            self.start()\r
+        else:\r
+            print "["+myname+"] slideshow finished"\r
+            self.wbviewer.exit()\r
+            self.cb()\r
+    def cb(self):\r
+        self.callback()\r
+###################\r
+class PictureViewer(Screen):\r
+    skin = ""\r
+    filelist = []\r
+    currList = "slideshowlist"\r
+    wbviewer = False\r
+    loadedslideshowlistlistname = False\r
+    def __init__(self, session, args = 0):\r
+        self.session = session\r
+        s =   "<screen position=\"93,70\" size=\"550,450\" title=\"%s\">\n" %config.plugins.pictureviewer.rootdir.value\r
+        s = s+"<widget name=\"menu\" position=\"1,1\" size=\"275,400\"  scrollbarMode=\"showOnDemand\" />\n"\r
+        s = s+"<widget name=\"pixmap\" position=\"550,450\" size=\"275,200\" backgroundColor=\"red\"/>\n" \r
+        s = s+"<widget name=\"slist\" position=\"275,200\" size=\"275,200\"  scrollbarMode=\"showOnDemand\"/>\n" \r
+        s = s+"<widget name=\"buttonred\" position=\"6,405\" size=\"130,40\" backgroundColor=\"red\" valign=\"center\" halign=\"center\" zPosition=\"2\"  foregroundColor=\"white\" font=\"Regular;18\"/>\n" \r
+        s = s+"<widget name=\"buttongreen\" position=\"142,405\" size=\"130,40\" backgroundColor=\"green\" valign=\"center\" halign=\"center\" zPosition=\"2\"  foregroundColor=\"white\" font=\"Regular;18\"/>\n" \r
+        s = s+"<widget name=\"buttonyellow\" position=\"278,405\" size=\"130,40\" backgroundColor=\"yellow\" valign=\"center\" halign=\"center\" zPosition=\"2\"  foregroundColor=\"white\" font=\"Regular;18\"/>\n" \r
+        s = s+"<widget name=\"buttonblue\" position=\"414,405\" size=\"130,40\" backgroundColor=\"blue\" valign=\"center\" halign=\"center\" zPosition=\"2\"  foregroundColor=\"white\" font=\"Regular;18\"/>\n" \r
+        self.skin = s+"</screen>"\r
+        Screen.__init__(self, session)\r
+        self.filelist = PictureList(config.plugins.pictureviewer.rootdir.value, matchingPattern = config.plugins.pictureviewer.matchingPattern.value)\r
+        self["menu"] = self.filelist\r
+        self.preview = Pixmap()\r
+        self["pixmap"] = self.preview\r
+        self.slideshowfiles = []\r
+        self.slideshowlist =MenuList(self.slideshowfiles)\r
+        self["slist"] = self.slideshowlist\r
+        self["buttonred"] = Label("")\r
+        self["buttongreen"] = Label("")\r
+        self["buttonyellow"] = Label("")\r
+        self["buttonblue"] = Label("")\r
+        self["actions"] = ActionMap(["WizardActions","MenuActions", "DirectionActions","ShortcutActions"], \r
+            {\r
+             "ok": self.go,\r
+             "back": self.close,\r
+             "menu": self.openMenu,\r
+             "up": self.up,\r
+             "down": self.down,\r
+             "left": self.leftUp,\r
+             "right": self.rightUp,\r
+             "red": self.KeyRed,\r
+             "green": self.KeyGreen,\r
+             "yellow": self.KeyYellow,\r
+             "blue": self.switchList,\r
+             }, -1)\r
+        self.onLayoutFinish.append(self.switchList)\r
+        self.onLayoutFinish.append(self.updateInfoPanel)\r
+    def KeyGreen(self):\r
+        if self.currList is "filelist" :\r
+            ## adding all files in current dir to slideshowlist\r
+            dirname = self["menu"].getCurrentDir()\r
+            if os.path.isdir(dirname):\r
+                s = os.listdir(dirname)\r
+                s.sort()\r
+                for file in s:\r
+                    if re.compile(config.plugins.pictureviewer.matchingPattern.value).search(dirname+file):\r
+                        self.slideshowfiles.append((_(file),dirname+file))\r
+                self["slist"].l.setList(self.slideshowfiles)\r
+                    \r
+        else:\r
+            #loading list\r
+            list = []\r
+            try:\r
+                for file in os.listdir(config.plugins.pictureviewer.slideshowdir.value):\r
+                    if file.endswith(config.plugins.pictureviewer.slideshowext.value):\r
+                        list.append((_(file.split("/")[-1]),file))\r
+                self.session.openWithCallback(self.fileToLoadFilelistEntered,ChoiceBox,_("select List to load"),list)\r
+            except IOError,e:\r
+                print "["+myname+"] IOError:",e\r
+            except OSError,e:\r
+                print "["+myname+"] OSError:",e\r
+               \r
+    def KeyRed(self):\r
+        if self.currList is "filelist" :\r
+            #do slideshow\r
+            self.hide()\r
+            x = Slideshow(self.session,self.show)\r
+            x.setfiles(self.slideshowfiles)\r
+            x.start()\r
+        else:\r
+            # save filelist\r
+            if self.loadedslideshowlistlistname is False:\r
+                newname = "slideshowlist"\r
+            else:\r
+                newname = self.loadedslideshowlistlistname\r
+            self.session.openWithCallback(self.fileToSaveFilelistEntered,InputBox, title=_("Enter filename to save the List:"), text=newname, maxSize=False, type=Input.TEXT)\r
+\r
+    def fileToLoadFilelistEntered(self,fileselection):\r
+        if fileselection is not None: \r
+               try:\r
+                   filename = fileselection[1]\r
+                   fp = open(config.plugins.pictureviewer.slideshowdir.value+filename)\r
+                   list = []\r
+                   for x in fp.readlines():\r
+                       file = x.replace("\n","")\r
+                       if x.startswith("#"):\r
+                           pass\r
+                       elif os.path.exists(file) is not True:\r
+                           print "["+myname+"] loaded file from filelist isnt avaible! ignoreing ->",file\r
+                       else:\r
+                           list.append((_(file.split("/")[-1]),file))\r
+                   self.slideshowfiles =list\r
+                   self["slist"].l.setList(self.slideshowfiles)\r
+                   self.loadedslideshowlistlistname = filename.replace(config.plugins.pictureviewer.slideshowext.value,"")\r
+               except IOError,e:\r
+                   print "["+myname+"] error:",e\r
+               \r
+    def fileToSaveFilelistEntered(self,filename):\r
+        if filename is not None:    \r
+            print "["+myname+"] saving list to ",config.plugins.pictureviewer.slideshowdir.value+filename+config.plugins.pictureviewer.slideshowext.value\r
+            try:\r
+                if os.path.exists(config.plugins.pictureviewer.slideshowdir.value) is not True:\r
+                    print "+"*10,os.path.basename(filename)\r
+                    os.mkdir(config.plugins.pictureviewer.slideshowdir.value)\r
+                fp = open(config.plugins.pictureviewer.slideshowdir.value+filename+config.plugins.pictureviewer.slideshowext.value,"w")\r
+                fp.write("# this is a slideshow file for "+myname+" made by V"+myversion+"\n")\r
+                fp.write("# you can make your own... each line with full path of the imagefile\n")\r
+                fp.write("# by importing this file,we will ignoring a file if is doesnt exist\n")\r
+                for x in self.slideshowfiles:\r
+                    fp.write(x[1]+"\n")\r
+                fp.close()\r
+            except IOError,e:\r
+                print "["+myname+"] error:",e\r
+    def KeyYellow(self):\r
+        if self.currList is "filelist" :\r
+            # add picture to list\r
+            fullfile = self["menu"].getSelection()[0]\r
+            if os.path.isfile(fullfile):\r
+                self.slideshowfiles.append((_(fullfile.split("/")[-1]),fullfile))\r
+                self["slist"].l.setList(self.slideshowfiles)\r
+        else:\r
+            # deleting an Picture\r
+            if len(self.slideshowfiles) >=1:\r
+                indexinlist = self["slist"].l.getCurrentSelectionIndex()\r
+                self.slideshowfiles.pop(indexinlist)\r
+                self["slist"].l.setList(self.slideshowfiles)\r
+\r
+    def switchList(self):\r
+        if self.currList is "filelist" :\r
+            # Slideshow activieren\r
+            self.filelist.selectionEnabled(0)\r
+            self.slideshowlist.selectionEnabled(1)\r
+            self["buttonred"].setText("speichern")\r
+            self["buttongreen"].setText("laden")\r
+            self["buttonyellow"].setText("loeschen")        \r
+            self["buttonblue"].setText("Dateien")\r
+            self.currList = "slideshowlist"\r
+        else:\r
+            # filelist activieren\r
+            self.filelist.selectionEnabled(1)\r
+            self.slideshowlist.selectionEnabled(0)\r
+            self["buttonred"].setText("starte Slideshow")\r
+            self["buttongreen"].setText("alle hinzufuegen")\r
+            self["buttonyellow"].setText("hinzufuegen")        \r
+            self["buttonblue"].setText("Slideshow bearbeiten")\r
+            self.currList = "filelist"\r
+                \r
+    def go(self):\r
+        if self.currList is "filelist" :\r
+            selection = self["menu"].getSelection()\r
+            if self.filelist.canDescent():\r
+                self.setTitle(selection[0])\r
+                self.filelist.descent()\r
+            else:\r
+                if selection[1] == True: # isDir\r
+                    pass\r
+                else:\r
+                    print "["+myname+"] file selected ",selection[0]\r
+                    if os.path.isfile(selection[0]):\r
+                        self.session.open(PictureScreen,selection[0].split("/")[-1],selection[0])\r
+                    else:\r
+                        print "["+myname+"] file not found " + selection[0]+""\r
+        else:\r
+            self.updateInfoPanel()\r
+    def up(self):\r
+         if self.currList is "filelist" :\r
+             self.filelist.up()\r
+             self.updateInfoPanel()\r
+         else:\r
+             self.slideshowlist.up()\r
+    def leftUp(self):\r
+         if self.currList is "filelist" :\r
+             self.filelist.pageUp()         \r
+             self.updateInfoPanel()\r
+         else:\r
+             self.slideshowlist.pageUp()\r
+    def rightUp(self):\r
+        if self.currList is "filelist" :\r
+             self.filelist.pageDown()\r
+             self.updateInfoPanel()\r
+        else:\r
+             self.slideshowlist.pageDown()\r
+    def down(self):\r
+         if self.currList is "filelist" :\r
+             self.filelist.down()\r
+             self.updateInfoPanel()\r
+         else:\r
+             self.slideshowlist.down()\r
+             \r
+    def updateInfoPanel(self):\r
+        if self.currList is "filelist" :\r
+            selectedfile = self["menu"].getSelection()[0]\r
+        else:\r
+            selectedfile = self["slist"].l.getCurrentSelection()[1]\r
+        pixmap = loadPic(selectedfile, 275,200, 1,1, 0,1)\r
+        if pixmap is not None:\r
+            self["pixmap"].instance.setPixmap(pixmap.__deref__())\r
+            self["pixmap"].move(275,0)\r
+        else:\r
+            pass\r
+                \r
+    def output(self,str):\r
+        print "+"*10,str  \r
+    def openMenu(self):\r
+        self.session.open(WebcamViewerMenu)\r
+###################\r
+class WebcamViewer(Screen):\r
+    skin = ""\r
+    filelist = []\r
+    def __init__(self, session,xmlnode, args = 0):\r
+        self.xmlnode = xmlnode\r
+        screen_x = 736\r
+        screen_y = 576\r
+        size_x = 350\r
+        size_y = 250\r
+        pos_x = (screen_x/2)-(size_x/2)\r
+        pos_y = (screen_y/2)-(size_y/2)\r
+        self.session = session\r
+        self.skin = """\r
+        <screen position="%i,%i" size="%i,%i" title="%s">\r
+            <widget name="menu" position="1,1" size="%i,%i"  scrollbarMode="showOnDemand"/>\r
+        </screen>""" % (pos_x,pos_y,size_x,size_y,myname,size_x,size_y) \r
+        Screen.__init__(self, session)\r
+        self.filelist = MenuList(self.getMenuData())\r
+        self["menu"] = self.filelist\r
+        self["actions"] = ActionMap(["WizardActions", "DirectionActions"], \r
+            {\r
+             "ok": self.go,\r
+             "back": self.close,\r
+             }, -1)\r
+        self.onLayoutFinish.append(self.settingTitle)\r
+        \r
+    def settingTitle(self):\r
+        self.setTitle(myname+": "+self.menutitle)\r
+        \r
+    def go(self):\r
+        selected = self["menu"].l.getCurrentSelection()[1]\r
+        menuitemtitle = self["menu"].l.getCurrentSelection()[0]\r
+        type = selected[0]\r
+        data = selected[1]\r
+        if type.startswith("cam"):\r
+            self.session.open(PictureScreen,menuitemtitle,data)\r
+        else:\r
+            self.hide()\r
+            self.session.openWithCallback(self.cb,WebcamViewer,data)\r
+\r
+    def cb(self):\r
+        self.show() \r
+               \r
+    def getMenuData(self):\r
+        xloader = XMLloader()\r
+        self.menutitle = xloader.getScreenXMLTitle(self.xmlnode)\r
+        data =[]        \r
+        for node in  elementsWithTag(self.xmlnode._get_childNodes(), 'menu'):\r
+            nodex={}\r
+            nodex['name'] =  xloader.get_txt( node, "name", "no name" )\r
+            data.append((_("*"+nodex['name']),["node",node]))\r
+        \r
+        for node2 in elementsWithTag(self.xmlnode._get_childNodes(), 'cam'):\r
+            nodex={}\r
+            nodex['name'] =  xloader.get_txt( node2, "name", "no name" )\r
+            nodex['url'] =  xloader.get_txt( node2, "url", "no url" )\r
+            data.append((_(nodex['name']),["cam",nodex['url']]))\r
+        return data\r
+###################\r
+\r
+##################\r
+class PictureList(MenuList, HTMLComponent, GUIComponent):\r
+    def __init__(self, directory, matchingPattern = None):\r
+        GUIComponent.__init__(self)\r
+        self.l = eListboxPythonMultiContent()\r
+        self.showDirectories = True\r
+        self.showFiles = True\r
+        self.isTop = False\r
+        self.matchingPattern = matchingPattern\r
+        self.changeDir(directory)\r
+        self.l.setFont(0, gFont("Regular", 18))\r
+        self.currentDir = directory\r
+    \r
+    def getCurrentDir(self):\r
+        return self.currentDir\r
+    \r
+    def getSelection(self):\r
+        return self.l.getCurrentSelection()[0]\r
+    \r
+    def getFileList(self):\r
+        return self.list\r
+    \r
+    def changeDir(self, directory):\r
+        self.currentDir = directory\r
+        self.list = []\r
+        \r
+        directories = []\r
+        files = []\r
+        files = os.listdir(directory)\r
+        files.sort()\r
+        tmpfiles = files[:]\r
+        for x in tmpfiles:\r
+            if os.path.isdir(directory +"/"+ x):\r
+                directories.append(x)\r
+                files.remove(x)\r
+        directories.sort()\r
+        files.sort()\r
+        if directory != "/" and self.showDirectories and not self.isTop:\r
+            self.list.append(self.getPictureEntryComponent("..",'/'.join(directory.split('/')[:-2]) + '/',True))\r
+\r
+        if self.showDirectories:\r
+            for x in directories:\r
+                name = (directory+x).split('/')[-1]\r
+                self.list.append(self.getPictureEntryComponent(name,'/'.join(directory.split('/')[:-1]) + '/'+x+'/',True))\r
+\r
+        if self.showFiles:\r
+            for x in files:\r
+                path = directory + x\r
+                name = x\r
+                if self.matchingPattern is not None:\r
+                    if re.compile(self.matchingPattern).search(path):\r
+                        self.list.append(self.getPictureEntryComponent(name,path ,False))\r
+                else:\r
+                    pass \r
+                \r
+        self.l.setList(self.list)\r
+        \r
+    def canDescent(self):\r
+        return self.getSelection()[1]\r
+    \r
+    def descent(self):\r
+        self.changeDir(self.getSelection()[0])\r
+        \r
+    def getFilename(self):\r
+        return self.getSelection()[0].getPath()\r
+\r
+    def getServiceRef(self):\r
+        return self.getSelection()[0]\r
+\r
+    GUI_WIDGET = eListbox\r
+\r
+    def postWidgetCreate(self, instance):\r
+        instance.setContent(self.l)\r
+        instance.setItemHeight(23)\r
+    \r
+    def getPictureEntryComponent(self,name, absolute, isDir):\r
+        """ name={angezeigter Name}, absolute={vollstaendiger Pfad}, isDir={True,False} """\r
+        res = [ (absolute, isDir) ]\r
+        res.append((eListboxPythonMultiContent.TYPE_TEXT, 35, 1, 200, 20, 0, 0, name))\r
+        if isDir:\r
+            png = loadPNG("/usr/share/enigma2/extensions/directory.png")\r
+        else: \r
+            extension = name.split('.')\r
+            extension = extension[-1].lower()\r
+            if EXTENSIONS.has_key(extension):\r
+                png = loadPNG("/usr/share/enigma2/extensions/" + EXTENSIONS[extension] + ".png")\r
+            else:\r
+                png = None\r
+        if png is not None:\r
+            res.append((eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, 10, 2, 20, 20, png))\r
+        return res\r
+\r
+\r
+##################\r
+class XMLloader:\r
+    DEFAULT_NAMESPACES = (\r
+          None, # RSS 0.91, 0.92, 0.93, 0.94, 2.0\r
+          'http://purl.org/rss/1.0/', # RSS 1.0\r
+          'http://my.netscape.com/rdf/simple/0.9/' # RSS 0.90\r
+        )\r
+    DUBLIN_CORE = ('http://purl.org/dc/elements/1.1/',)\r
+    def getElementsByTagName( self, node, tagName, possibleNamespaces=DEFAULT_NAMESPACES ):\r
+        for namespace in possibleNamespaces:\r
+            children = node.getElementsByTagNameNS(namespace, tagName)\r
+            if len(children): return children\r
+        return []\r
+\r
+    def node_data( self, node, tagName, possibleNamespaces=DEFAULT_NAMESPACES):\r
+        children = self.getElementsByTagName(node, tagName, possibleNamespaces)\r
+        node = len(children) and children[0] or None\r
+        return node and "".join([child.data.encode("utf-8") for child in node.childNodes]) or None\r
+\r
+    def get_txt( self, node, tagName, default_txt="" ):\r
+        """\r
+        Liefert den Inhalt >tagName< des >node< zurueck, ist dieser nicht\r
+        vorhanden, wird >default_txt< zurueck gegeben.\r
+        """\r
+        return self.node_data( node, tagName ) or self.node_data( node, tagName, self.DUBLIN_CORE ) or default_txt\r
+\r
+    def getScreenXMLTitle( self,node ):\r
+        return self.get_txt( node, "name", "no title" )\r
diff --git a/webcamviewer/src/webcam.xml b/webcamviewer/src/webcam.xml
new file mode 100755 (executable)
index 0000000..ea12595
--- /dev/null
@@ -0,0 +1,295 @@
+<?xml version="1.0"  encoding="UTF-8" ?>
+<!-- I you have webcams that should be listed here, send an email to 3c5x9(at)gmx.net -->
+<xml>
+       <name>Mainmenu</name>
+       <menu>
+               <name>Webcam</name>
+               <menu>
+                       <name>Amerika</name>
+                       <menu>
+                               <name>USA Westkueste</name>
+                               <cam>
+                                       <name>Santa Monica Pier</name>
+                                       <url>http://www.westland.net/photo/file02.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>Venice Beach</name>
+                                       <url>http://www.westland.net/photo/file01.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>Pacific Palisades Bay</name>
+                                       <url>http://www.westland.net/photo/file01.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>Pacific Coast HWY</name>
+                                       <url>http://www.livinginthepalisades.com/photo/coastcam1.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>Auto Webcam - Live von unterwegs in L.A.</name>
+                                       <url>http://www.laavenue.com/la/la.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>sf Lawrence Hall of Science</name>
+                                       <url>http://sv.berkeley.edu/view/images/current_view.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>Mount St. Helens - VolcanoCam</name>
+                                       <url>http://www.fs.fed.us/gpnf/volcanocams/msh/images/mshvolcanocam.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>Seattle King 5 TV - From Queen Anne</name>
+                                       <url>http://www.king5.com/live/weather_images/external/queenanne_lg.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>Grand Canyon</name>
+                                       <url>http://www2.nature.nps.gov/air/WebCams/parks/grcacam/grca.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>Point Reyes National Seashore</name>
+                                       <url>http://www2.nature.nps.gov/air/webcams/parks/porecam/pore.jpg</url>
+                               </cam>
+                       </menu>
+                       <menu>
+                               <name>New York</name>
+                               <cam>
+                                       <name>Broadway</name>
+                                       <url>http://images.earthcam.com/ec_metros/ourcams/charleyo.jpg</url>    
+                               </cam>
+                               <cam>
+                                       <name>Ground zero</name>
+                                       <url>http://images.earthcam.com/ec_metros/ourcams/millenium.jpg</url>   
+                               </cam>
+                               <cam>
+                                       <name>46th Street and Broadway</name>
+                                       <url>http://209.178.198.74/ec_metros/ourcams/fridays.jpg</url>  
+                               </cam>              
+                               <cam>
+                                       <name>Emipre State Building</name>
+                                       <url>http://www.nyvibe.net/nyvibescam/view.jpg</url>    
+                               </cam>
+                       </menu>
+                       <menu>
+                               <name>Las Vegas</name>
+                               <cam>
+                                       <name>MGM</name>
+                                       <url>http://images.earthcam.com/ec_metros/ourcams/mgm.jpg</url> 
+                               </cam>
+                               <cam>
+                                       <name>Wedding Chapel</name>
+                                       <url>http://images.earthcam.com/ec_metros/ourcams/wedding.jpg</url>     
+                               </cam>
+                               <cam>
+                                       <name>Paris Hotel</name>
+                                       <url>http://images.earthcam.com/ec_metros/ourcams/paris.jpg</url>       
+                               </cam>              
+                               <cam>
+                                       <name>Hard Rock Hotel</name>
+                                       <url>http://images.earthcam.com/ec_metros/ourcams/cafe.jpg</url>        
+                               </cam>
+                       </menu>
+                       <menu>
+                               <name>Rio de Janeiro</name>
+                               <cam>
+                                       <name>Lapa</name>
+                                       <url>http://transito.rio.rj.gov.br/imagens1/41.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>Av. Rio Branco / Av. Presidente Vargas</name>
+                                       <url>http://transito.rio.rj.gov.br/imagens1/2.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>Aterro do Flamengo</name>
+                                       <url>http://transito.rio.rj.gov.br/imagens1/5.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>Flamengo / Botafogo</name>
+                                       <url>http://transito.rio.rj.gov.br/imagens1/20.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>Copacabana - Avenida Atlantica</name>
+                                       <url>http://transito.rio.rj.gov.br/imagens1/26.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>Av. Nossa Senhora de Copacabana</name>
+                                       <url>http://transito.rio.rj.gov.br/imagens1/24.jpg</url>
+                               </cam>
+                       </menu>
+                       <cam>
+                               <name>Vancouver, English Bay</name>
+                               <url>http://www.katkam.ca/p.asp?what=currentjpg</url>   
+                       </cam>
+                       <cam>
+                               <name>Torronto</name>
+                               <url>http://www.traveloffice.ca/webcam/capture1.jpg</url>       
+                       </cam>
+                       <cam>
+                               <name>Argentinien, Mar del Plata</name>
+                               <url>http://www.mardelplatawebcam.com.ar/img/webcam_colon_y_costa.jpg</url>     
+                       </cam>
+
+               </menu>
+               <menu>
+                       <name>Europa</name>
+                       <cam>
+                               <name>London, Trafalgar Square</name>
+                               <url>http://images.earthcam.com/ec_metros/ourcams/trafalgarsq.jpg</url> 
+                       </cam>
+                       <cam>
+                               <name>London, Big Ben</name>
+                               <url>http://images.earthcam.com/ec_metros/ourcams/big_ben.jpg</url>     
+                       </cam>
+                       <cam>
+                               <name>London, Covent Garden</name>
+                               <url>http://images.earthcam.com/ec_metros/ourcams/ltm.jpg</url> 
+                       </cam>
+                       <cam>
+                               <name>Spanien, Costa Brava</name>
+                               <url>http://www.costabrava.cc/calella_live_webcam.jpg</url>     
+                       </cam>
+                       <cam>
+                               <name>Paris</name>
+                               <url>http://www.abcparislive.com/eiffel2.jpg</url>      
+                       </cam>
+                       <cam>
+                               <name>Madrid</name>
+                               <url>http://www.multimadrid.com/plaza.jpg</url> 
+                       </cam>
+                       <cam>
+                               <name>Dublin</name>
+                               <url>http://www.ireland.com/includes/webcam/liveview.jpg</url>  
+                       </cam>
+                       <cam>
+                               <name>Griechenland, Naxos</name>
+                               <url>http://www.flisvos-sportclub.com/images/webcam.jpg</url>   
+                       </cam>
+                       <cam>
+                               <name>Griechenland, Mykonos</name>
+                               <url>http://www.travel-to-mykonos.com/webcam/1/mykonos.jpg</url>        
+                       </cam>
+               </menu>
+               <menu>
+                       <name>Deutschland</name>
+                       <menu>
+                               <name>Hamburg</name>
+                               <cam>
+                                       <name>Hamburg A7 Elbtunnel</name>
+                                       <url>http://www.ikk-hamburg.de/seiten/webcam/bild.php?bild=gross</url>  
+                               </cam>    
+                               <cam>
+                                       <name>Hamburg Landungsbruecken</name>
+                                       <url>http://www.dwd.de/scripts/getimg.php?src=/wundk/wkam1-10148.jpg</url>      
+                               </cam>
+                               <cam>
+                                       <name>Hamburg Hafen</name>
+                                       <url>http://www.hafen-hamburg.de/webcam/camstill.jpg</url>      
+                               </cam>                                  
+                       </menu>
+                       <menu>
+                               <name>Dresden</name>
+                               <cam>
+                                       <name>Frauenkirche</name>
+                                       <url>http://www3.mdr.de/webcams/frauen.jpg?t=12679</url>
+                               </cam>
+                               <cam>
+                                       <name>Blick auf Altstadtpanorama, Synagoge und Frauenkirche</name>
+                                       <url>http://www3.mdr.de/webcams/altstadt.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>Zwinger</name>
+                                       <url>http://www.softed.de/Webcam/webcam/hugesize.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>Fernsehturm</name>
+                                       <url>http://www.eb-world.de/FernsehturmCam/pics/Fernsehturm.jpg</url>
+                               </cam>                  
+                               <cam>
+                                       <name>Seidnitz</name>
+                                       <url>http://www.webcam.maxg.ath.cx/capture1.jpg</url>
+                               </cam>
+                               <cam>
+                                       <name>Blick zur Frauenkirche</name>
+                                       <url>http://dataware.de/~combase/fkdrv/images/campics/image.jpg</url>
+                               </cam>
+                       </menu>
+                       <cam>
+                               <name>Eutin</name>
+                               <url>http://www.stadtwerke-eutin.de/webcam/images/wasserturm.jpg</url>
+                       </cam>
+                       <cam>
+                               <name>Offenbach/Frankfurt</name>
+                               <url>http://www.dwd.de/scripts/getimg.php?src=/wundk/wkam1-10640.jpg</url>      
+                       </cam>
+                       <cam>
+                               <name>St. Peter Ording</name>
+                               <url>http://www.dwd.de/scripts/getimg.php?src=/wundk/wkam1-10028.jpg</url>      
+                       </cam>
+                       <cam>
+                               <name>Rostock-Warnemuende Seestrasse</name>
+                               <url>http://www.dwd.de/scripts/getimg.php?src=/wundk/wkam1-10170.jpg</url>      
+                       </cam>
+                       <cam>
+                               <name>Kahler Asten - Wetterstation</name>
+                               <url>http://www.dwd.de/scripts/getimg.php?src=/wundk/wkam1-10427.jpg</url>      
+                       </cam>
+                       <cam>
+                               <name>Braunlage</name>
+                               <url>http://www.dwd.de/scripts/getimg.php?src=/wundk/wkam1-10452.jpg</url>      
+                       </cam>
+                       <cam>
+                               <name>Hannover</name>
+                               <url>http://www.langelaube2.de/webcam/webcam.jpg</url>  
+                       </cam>
+                       <cam>
+                               <name>Koeln</name>
+                               <url>http://www.wdr.de/themen/global/webcams/domcam/domcam_live.jpg</url>       
+                       </cam>
+                       <cam>
+                               <name>Frankfurt</name>
+                               <url>http://www.frankfurt.de/sis/frankfurtbilder/cams/pia/images/webcam_pia.jpg</url>   
+                       </cam>
+                       <cam>
+                               <name>Berlin</name>
+                               <url>http://www.dhm.de/webcams/pics/cam1_large.jpg</url>        
+                       </cam>
+                       <cam>
+                               <name>Berlin2</name>
+                               <url>http://www.dwd.de/scripts/getimg.php?src=/wundk/wkam1-10384.jpg</url>      
+                       </cam>
+                       <cam>
+                               <name>Berlin, Museumsinsel</name>
+                               <url>http://www.ipb.de/webcam/cam/cam.jpg</url> 
+                       </cam>
+                       <cam>
+                               <name>Leipzig</name>
+                               <url>http://www.na-klarmann.de/cam.JPG</url>    
+                       </cam>
+               </menu>
+               <cam>
+                       <name>Antarkits,South Georgia</name>
+                       <url>http://www.sgisland.org/webcam/webcam.jpg</url>    
+               </cam>
+               <cam>
+                       <name>Neuseeland, Hammer Springs</name>
+                       <url>http://www.hanmer.co.nz/hanmer.jpg</url>   
+               </cam>
+       </menu>
+       <menu>
+               <name>Wetter</name>
+               <cam>
+                       <name>Deutschlandwetter</name>
+                       <url>http://www.dwd.de/scripts/getimg.php?src=/wundk/Wetter.jpg</url>   
+               </cam>    
+               <cam>
+                       <name>Satellitenbild Wolken Deutschland</name>
+                       <url>http://www.dwd.de/scripts/getimg.php?src=/hobbymet/mvvs1200.jpg</url>      
+               </cam>    
+               <cam>
+                       <name>Satellitenbild Wolken Welt</name>
+                       <url>http://www.dwd.de/scripts/getimg.php?src=/hobbymet/wvds1200.jpg</url>      
+               </cam>    
+               <cam>
+                       <name>Wasser Temperaturen</name>
+                       <url>http://www.dwd.de/scripts/getimg.php?src=/wundk/00-awg_sst.png</url>       
+               </cam>
+       </menu>
+</xml>
\ No newline at end of file