1 from enigma import eListbox
2 from enigma import eListboxPythonMultiContent
3 from enigma import ePicLoad
4 from enigma import loadPNG
5 from enigma import gFont
7 from Screens.Screen import Screen
8 from Screens.MessageBox import MessageBox
9 from Screens.InputBox import InputBox
10 from Screens.ChoiceBox import ChoiceBox
11 from Components.ActionMap import ActionMap
12 from Components.Label import Label
13 from Components.MenuList import MenuList
14 from Components.FileList import EXTENSIONS
15 from Components.AVSwitch import AVSwitch
17 from Components.config import config, ConfigSubsection,ConfigSelection,ConfigText,ConfigYesNo
19 from Components.Input import Input
20 from Components.Pixmap import Pixmap
21 from Plugins.Plugin import PluginDescriptor
24 from re import compile
26 from pyexpat import ExpatError
27 import xml.dom.minidom
30 from WebcamViewConfig import WebcamViewerMenu
31 from PictureScreen import PictureScreen
32 from WebcamTravel import TravelWebcamviewer
34 myname = "Webcam/Picture Viewer"
37 config.plugins.pictureviewer = ConfigSubsection()
38 config.plugins.pictureviewer.slideshowtime = ConfigSelection(default="5000", choices = [("5000", _("5 Seconds")), ("10000", _("10 Seconds")), ("20000", _("20 Seconds")), ("60000", _("1 Minute"))])
39 config.plugins.pictureviewer.slideshowmode = ConfigSelection(default="0", choices = [("0", _("normal")), ("1", _("endless"))])
41 config.plugins.pictureviewer.slideshowext = ConfigText(default=".3ssl")
42 config.plugins.pictureviewer.matchingPattern = ConfigText(default="(?i)^.*\.(jpeg|jpg|jpe|png|bmp|gif)")
43 config.plugins.pictureviewer.slideshowdir = ConfigText(default="/media/hdd/slideshows/")
44 config.plugins.pictureviewer.rootdir = ConfigText(default="/media/")
45 config.plugins.pictureviewer.stopserviceonstart = ConfigYesNo(default = False)
46 SLIDESHOWMODE_NORMAL = 0
47 SLIDESHOWMODE_REPEAT = 1
49 originalservice = None
53 def startPictureviewer(session, **kwargs):
54 global originalservice, mysession
56 originalservice = session.nav.getCurrentlyPlayingServiceReference()
57 if config.plugins.pictureviewer.stopserviceonstart.value:
58 session.nav.stopService()
59 session.openWithCallback(mainCB, PictureViewer)
61 def startWebcamviewer(session, **kwargs):
62 global originalservice, mysession
64 originalservice = session.nav.getCurrentlyPlayingServiceReference()
65 if config.plugins.pictureviewer.stopserviceonstart.value:
66 session.nav.stopService()
67 xmlfile = "/usr/lib/enigma2/python/Plugins/Extensions/WebcamViewer/webcam.xml"
68 if os.path.isfile(xmlfile):
70 xmlnode = xml.dom.minidom.parse(open(xmlfile))
71 session.openWithCallback(mainCB, WebcamViewer, xmlnode.childNodes[1])
75 _("Loading config file failed!\n\n%s") % e,
76 MessageBox.TYPE_WARNING
81 _("Loading config file failed!\n\nconfigfile not found!"),
82 MessageBox.TYPE_WARNING
89 global originalservice, mysession
90 if config.plugins.pictureviewer.stopserviceonstart.value:
91 mysession.nav.playService(originalservice)
93 def Plugins(path, **kwargs):
97 description="browse your local pictures",
98 where = PluginDescriptor.WHERE_PLUGINMENU,
99 fnc = startPictureviewer,
100 icon="pictureviewer.png"
104 description="view webcams around the world",
105 where = PluginDescriptor.WHERE_PLUGINMENU,
106 fnc = startWebcamviewer,
107 icon="webcamviewer.png"
113 class ViewerSelectScreen(Screen):
115 def __init__(self, session, args = 0):
116 skin = """<screen position="93,70" size="550,450">
117 <widget name="list" position="0,0" size="550,450" />
120 Screen.__init__(self, session)
121 self.slideshowfiles = []
122 self.slideshowfiles.append((_("WebcamViewer"),STARTWEBCAMVIEWER))
123 self.slideshowfiles.append((_("online webcam.travel"),STARTWEBCAMTRAVEL))
124 self["list"] = MenuList(self.slideshowfiles)
125 self["actions"] = ActionMap(["WizardActions", "MenuActions", "DirectionActions", "ShortcutActions"],
132 selection = self["list"].getCurrent()
134 self.close(self.session,selection[1])
140 currentslideshowitem = 0
143 def __init__(self, session, callback):
144 self.session = session
145 self.callback = callback
147 def setfiles(self, filelist):
148 self.filelist = filelist
151 if len(self.filelist) > 0:
152 self.currentslideshowitem = -1
153 self.nextSlideshowItem()
155 def nextSlideshowItem(self, prev = False):
156 currentslideshowitem = self.currentslideshowitem
158 currentslideshowitem -= 2
159 if currentslideshowitem < 0:
160 currentslideshowitem = -1
161 if currentslideshowitem is not (len(self.filelist) - 1):
162 currentslideshowitem += 1
163 filetoshow = self.filelist[currentslideshowitem][1]
164 if not self.wbviewer:
165 self.wbviewer = self.session.openWithCallback(
168 filetoshow.split("/")[-1],
170 slideshowcallback = self.nextSlideshowItem
173 self.wbviewer.filename = filetoshow
175 self.currentslideshowitem = currentslideshowitem
176 elif int(config.plugins.pictureviewer.slideshowmode.value) is SLIDESHOWMODE_REPEAT:
177 print "["+myname+"] restarting slideshow"
180 print "["+myname+"] slideshow finished"
187 class PictureViewer(Screen):
190 currList = "slideshowlist"
192 loadedslideshowlistlistname = False
194 def __init__(self, session, args = 0):
195 skin = """<screen position="93,70" size="550,450" title="%s">
196 <widget name="menu" position="1,1" size="275,400" scrollbarMode="showOnDemand" />
197 <widget name="pixmap" position="275,1" size="275,200" backgroundColor="red" />
198 <widget name="slist" position="275,200" size="275,200" scrollbarMode="showOnDemand" />
199 <widget name="buttonred" position="6,405" size="130,40" backgroundColor="red" valign="center" halign="center" zPosition="2" foregroundColor="white" font="Regular;18" />
200 <widget name="buttongreen" position="142,405" size="130,40" backgroundColor="green" valign="center" halign="center" zPosition="2" foregroundColor="white" font="Regular;18" />
201 <widget name="buttonyellow" position="278,405" size="130,40" backgroundColor="yellow" valign="center" halign="center" zPosition="2" foregroundColor="white" font="Regular;18" />
202 <widget name="buttonblue" position="414,405" size="130,40" backgroundColor="blue" valign="center" halign="center" zPosition="2" foregroundColor="white" font="Regular;18" />
203 </screen>""" % config.plugins.pictureviewer.rootdir.value
205 Screen.__init__(self, session)
207 self.filelist = PictureList(config.plugins.pictureviewer.rootdir.value, matchingPattern = config.plugins.pictureviewer.matchingPattern.value)
208 self["menu"] = self.filelist
210 self.preview = Pixmap()
211 self["pixmap"] = self.preview
213 self.slideshowfiles = []
214 self.slideshowlist =MenuList(self.slideshowfiles)
215 self["slist"] = self.slideshowlist
217 self["buttonred"] = Label("")
218 self["buttongreen"] = Label("")
219 self["buttonyellow"] = Label("")
220 self["buttonblue"] = Label("")
222 self["actions"] = ActionMap(["WizardActions", "MenuActions", "DirectionActions", "ShortcutActions"],
226 "menu": self.openMenu,
230 "right": self.rightUp,
232 "green": self.KeyGreen,
233 "yellow": self.KeyYellow,
234 "blue": self.switchList,
237 self.onLayoutFinish.append(self.switchList)
238 self.onLayoutFinish.append(self.updateInfoPanel)
241 if self.currList is "filelist":
242 # adding all files in current dir to slideshowlist
243 dirname = self["menu"].getCurrentDir()
244 if os.path.isdir(dirname):
245 s = os.listdir(dirname)
248 if compile(config.plugins.pictureviewer.matchingPattern.value).search(dirname + file):
249 self.slideshowfiles.append((_(file),dirname + file))
250 self["slist"].l.setList(self.slideshowfiles)
255 for file in os.listdir(config.plugins.pictureviewer.slideshowdir.value):
256 if file.endswith(config.plugins.pictureviewer.slideshowext.value):
257 list.append((_(file.split("/")[-1]),file))
258 self.session.openWithCallback(
259 self.fileToLoadFilelistEntered,
261 _("select List to load"),
265 print "["+myname+"] IOError:",e
267 print "["+myname+"] OSError:",e
270 if self.currList is "filelist" :
273 x = Slideshow(self.session, self.show)
274 x.setfiles(self.slideshowfiles)
278 if not self.loadedslideshowlistlistname:
279 newname = "slideshowlist"
281 newname = self.loadedslideshowlistlistname
282 self.session.openWithCallback(
283 self.fileToSaveFilelistEntered,
285 title = _("Enter filename to save the List:"),
291 def fileToLoadFilelistEntered(self, fileselection):
292 if fileselection is not None:
294 filename = fileselection[1]
295 fp = open(config.plugins.pictureviewer.slideshowdir.value + filename)
297 for x in fp.readlines():
298 file = x.replace("\n","")
299 if x.startswith("#"):
301 elif not os.path.exists(file):
302 print "["+myname+"] loaded file from filelist isnt avaible! ignoreing ->", file
304 list.append((_(file.split("/")[-1]), file))
305 self.slideshowfiles = list
306 self["slist"].l.setList(self.slideshowfiles)
307 self.loadedslideshowlistlistname = filename.replace(config.plugins.pictureviewer.slideshowext.value, "")
309 print "["+myname+"] error:", e
311 def fileToSaveFilelistEntered(self, filename):
312 if filename is not None:
313 print "["+myname+"] saving list to ", config.plugins.pictureviewer.slideshowdir.value+filename + config.plugins.pictureviewer.slideshowext.value
315 if not os.path.exists(config.plugins.pictureviewer.slideshowdir.value):
316 print "+" * 10, os.path.basename(filename)
317 os.mkdir(config.plugins.pictureviewer.slideshowdir.value)
318 fp = open(config.plugins.pictureviewer.slideshowdir.value + filename+config.plugins.pictureviewer.slideshowext.value, "w")
319 fp.write("# this is a slideshow file for "+myname+" made by V"+myversion+"\n")
320 fp.write("# you can make your own... each line with full path of the imagefile\n")
321 fp.write("# by importing this file,we will ignoring a file if is doesnt exist\n")
322 for x in self.slideshowfiles:
323 fp.write(x[1] + "\n")
326 print "["+myname+"] error:", e
329 if self.currList is "filelist":
330 # add picture to list
331 fullfile = self["menu"].getSelection()[0]
332 if os.path.isfile(fullfile):
333 self.slideshowfiles.append((_(fullfile.split("/")[-1]), fullfile))
334 self["slist"].l.setList(self.slideshowfiles)
336 # deleting an Picture
337 if len(self.slideshowfiles) >= 1:
338 indexinlist = self["slist"].l.getCurrentSelectionIndex()
339 self.slideshowfiles.pop(indexinlist)
340 self["slist"].l.setList(self.slideshowfiles)
342 def switchList(self):
343 if self.currList is "filelist" :
344 # Slideshow activieren
345 self.filelist.selectionEnabled(0)
346 self.slideshowlist.selectionEnabled(1)
347 self["buttonred"].setText("speichern")
348 self["buttongreen"].setText("laden")
349 self["buttonyellow"].setText("loeschen")
350 self["buttonblue"].setText("Dateien")
351 self.currList = "slideshowlist"
353 # filelist activieren
354 self.filelist.selectionEnabled(1)
355 self.slideshowlist.selectionEnabled(0)
356 self["buttonred"].setText("starte Slideshow")
357 self["buttongreen"].setText("alle hinzufuegen")
358 self["buttonyellow"].setText("hinzufuegen")
359 self["buttonblue"].setText("Slideshow bearbeiten")
360 self.currList = "filelist"
363 if self.currList is "filelist" :
364 selection = self["menu"].getSelection()
365 if self.filelist.canDescent():
366 self.setTitle(selection[0])
367 self.filelist.descent()
369 if selection[1] == True: # isDir
372 print "["+myname+"] file selected ", selection[0]
373 if os.path.isfile(selection[0]):
374 self.session.open(PictureScreen,selection[0].split("/")[-1], selection[0])
376 print "["+myname+"] file not found ", selection[0]
378 self.updateInfoPanel()
381 if self.currList is "filelist":
383 self.updateInfoPanel()
385 self.slideshowlist.up()
388 if self.currList is "filelist":
389 self.filelist.pageUp()
390 self.updateInfoPanel()
392 self.slideshowlist.pageUp()
395 if self.currList is "filelist":
396 self.filelist.pageDown()
397 self.updateInfoPanel()
399 self.slideshowlist.pageDown()
402 if self.currList is "filelist":
404 self.updateInfoPanel()
406 self.slideshowlist.down()
408 def updateInfoPanel(self):
409 if self.currList is "filelist":
410 selectedfile = self["menu"].getSelection()[0]
412 selectedfile = self["slist"].l.getCurrentSelection()[1]
413 sc=AVSwitch().getFramebufferScale()
414 self.picload = ePicLoad()
415 self.picload.PictureData.get().append(self.updateInfoPanelCB)
416 self.picload.setPara((self["pixmap"].instance.size().width(), self["pixmap"].instance.size().height(), sc[0], sc[1], False, 1, "#FF000000"))
417 self.picload.startDecode(selectedfile)
420 def updateInfoPanelCB(self, picInfo = None):
421 ptr = self.picload.getData()
423 self["pixmap"].instance.setPixmap(ptr.__deref__())
427 def output(self,str):
431 self.session.open(WebcamViewerMenu)
433 class WebcamViewer(Screen):
436 def __init__(self, session,xmlnode, args = 0):
437 self.xmlnode = xmlnode
442 pos_x = (screen_x/2)-(size_x/2)
443 pos_y = (screen_y/2)-(size_y/2)
445 <screen position="%i,%i" size="%i,%i" title="%s">
446 <widget name="menu" position="1,1" size="%i,%i" scrollbarMode="showOnDemand"/>
447 </screen>""" % (pos_x,pos_y,size_x,size_y,myname,size_x,size_y)
449 Screen.__init__(self, session)
451 self.filelist = MenuList(self.getMenuData())
452 self["menu"] = self.filelist
453 self["actions"] = ActionMap(["WizardActions", "DirectionActions"],
458 self.onLayoutFinish.append(self.settingTitle)
460 def settingTitle(self):
461 self.setTitle(myname + ": " + self.menutitle)
464 selected = self["menu"].l.getCurrentSelection()[1]
465 menuitemtitle = self["menu"].l.getCurrentSelection()[0]
468 if menuitemtitle.startswith("webcam.travel"):
469 self.session.openWithCallback(self.cb, TravelWebcamviewer)
470 elif type.startswith("cam"):
471 self.session.open(PictureScreen, menuitemtitle, data)
474 self.session.openWithCallback(self.cb, WebcamViewer, data)
479 def getMenuData(self):
480 xloader = XMLloader()
481 self.menutitle = xloader.getScreenXMLTitle(self.xmlnode)
483 if self.menutitle =="Mainmenu":
484 data.append((_("webcam.travel"), "webcam.travel"))
485 for node in self.xmlnode.childNodes:
486 if node.nodeType != xml.dom.minidom.Element.nodeType or node.tagName != 'menu':
489 nodex['name'] = xloader.get_txt(node, "name", "no name")
490 data.append((_("*" + nodex['name']), ["node", node]))
492 for node in self.xmlnode.childNodes:
493 if node.nodeType != xml.dom.minidom.Element.nodeType or node.tagName != 'cam':
496 nodex['name'] = xloader.get_txt(node, "name", "no name")
497 nodex['url'] =xloader.get_txt(node, "url", "no url")
498 data.append((_(nodex['name']), ["cam", nodex['url']]))
503 class PictureList(MenuList):
504 def __init__(self, directory, matchingPattern = None, enableWrapAround = False):
505 MenuList.__init__(self, None, enableWrapAround, eListboxPythonMultiContent)
506 self.showDirectories = True
507 self.showFiles = True
509 self.matchingPattern = matchingPattern
510 self.changeDir(directory)
511 self.l.setFont(0, gFont("Regular", 18))
512 self.currentDir = directory
514 def getCurrentDir(self):
515 return self.currentDir
517 def getSelection(self):
518 return self.l.getCurrentSelection()[0]
520 def getFileList(self):
523 def changeDir(self, directory):
524 self.currentDir = directory
529 files = os.listdir(directory)
533 if os.path.isdir(directory + "/" + x):
534 directories.append(x)
538 if directory != "/" and self.showDirectories and not self.isTop:
539 self.list.append(self.getPictureEntryComponent("..", '/'.join(directory.split('/')[:-2]) + '/', True))
541 if self.showDirectories:
542 for x in directories:
543 name = (directory+x).split('/')[-1]
544 self.list.append(self.getPictureEntryComponent(name, '/'.join(directory.split('/')[:-1]) + '/' + x + '/', True))
550 if self.matchingPattern is not None:
551 if compile(self.matchingPattern).search(path):
552 self.list.append(self.getPictureEntryComponent(name,path, False))
556 self.l.setList(self.list)
558 def canDescent(self):
559 return self.getSelection()[1]
562 self.changeDir(self.getSelection()[0])
564 def getFilename(self):
565 return self.getSelection()[0].getPath()
567 def getServiceRef(self):
568 return self.getSelection()[0]
570 def postWidgetCreate(self, instance):
571 MenuList.postWidgetCreate(self, instance)
572 instance.setItemHeight(23)
574 def getPictureEntryComponent(self,name, absolute, isDir):
575 """ name={angezeigter Name}, absolute={vollstaendiger Pfad}, isDir={True,False} """
576 res = [ (absolute, isDir) ]
577 res.append((eListboxPythonMultiContent.TYPE_TEXT, 35, 1, 200, 20, 0, 0, name))
579 png = loadPNG("/usr/share/enigma2/extensions/directory.png")
581 extension = name.split('.')
582 extension = extension[-1].lower()
583 if EXTENSIONS.has_key(extension):
584 png = loadPNG("/usr/share/enigma2/extensions/" + EXTENSIONS[extension] + ".png")
588 res.append((eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, 10, 2, 20, 20, png))
594 DEFAULT_NAMESPACES = (
595 None, # RSS 0.91, 0.92, 0.93, 0.94, 2.0
596 'http://purl.org/rss/1.0/', # RSS 1.0
597 'http://my.netscape.com/rdf/simple/0.9/' # RSS 0.90
599 DUBLIN_CORE = ('http://purl.org/dc/elements/1.1/',)
600 def getElementsByTagName(self, node, tagName, possibleNamespaces = DEFAULT_NAMESPACES):
601 for namespace in possibleNamespaces:
602 children = node.getElementsByTagNameNS(namespace, tagName)
607 def node_data(self, node, tagName, possibleNamespaces = DEFAULT_NAMESPACES):
608 children = self.getElementsByTagName(node, tagName, possibleNamespaces)
609 node = len(children) and children[0] or None
610 return node and "".join([child.data.encode("utf-8") for child in node.childNodes]) or None
612 def get_txt(self, node, tagName, default_txt = ""):
614 Liefert den Inhalt >tagName< des >node< zurueck, ist dieser nicht
615 vorhanden, wird >default_txt< zurueck gegeben.
617 return self.node_data(node, tagName) or self.node_data(node, tagName, self.DUBLIN_CORE) or default_txt
619 def getScreenXMLTitle(self,node):
620 return self.get_txt(node, "name", "no title")