1 from enigma import eListbox
2 from enigma import eListboxPythonMultiContent
3 from enigma import loadPic
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
16 from Components.config import config, ConfigSubsection,ConfigSelection,ConfigText,ConfigYesNo
18 from Components.Input import Input
19 from Components.Pixmap import Pixmap
20 from Plugins.Plugin import PluginDescriptor
23 from re import compile
25 from pyexpat import ExpatError
26 import xml.dom.minidom
27 from Tools.XMLTools import elementsWithTag
30 from WebcamViewConfig import WebcamViewerMenu
31 from PictureScreen import PictureScreen
33 myname = "Webcam/Picture Viewer"
38 config.plugins.pictureviewer = ConfigSubsection()
39 config.plugins.pictureviewer.slideshowtime = ConfigSelection(default="5000", choices = [("5000", _("5 Sekunden")), ("10000", _("10 Sekunden")), ("20000", _("20 Sekunden")), ("60000", _("1 Minute"))])
40 config.plugins.pictureviewer.slideshowmode = ConfigSelection(default="0", choices = [("0", _("normal")), ("1", _("endlos"))])
42 config.plugins.pictureviewer.slideshowext = ConfigText(default=".3ssl")
43 config.plugins.pictureviewer.matchingPattern = ConfigText(default="(?i)^.*\.(jpeg|jpg|jpe|png|bmp|gif)")
44 config.plugins.pictureviewer.slideshowdir = ConfigText(default="/media/hdd/slideshows/")
45 config.plugins.pictureviewer.rootdir = ConfigText(default="/media/")
46 config.plugins.pictureviewer.stopserviceonstart = ConfigYesNo(default = False)
47 SLIDESHOWMODE_NORMAL = 0
48 SLIDESHOWMODE_REPEAT = 1
50 originalservice = None
53 def main1(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 main2(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])
73 session.open(MessageBox,_("Loading config file failed!\n\n%s"%e), MessageBox.TYPE_WARNING)
75 session.open(MessageBox,_("Loading config file failed!\n\nconfigfile not found!"), MessageBox.TYPE_WARNING)
78 global originalservice,mysession
79 if config.plugins.pictureviewer.stopserviceonstart.value:
80 mysession.nav.playService(originalservice)
82 def Plugins(path,**kwargs):
86 description="browse your local pictures",
87 where = PluginDescriptor.WHERE_PLUGINMENU,
89 icon="pictureviewer.png"
94 description="view webcams around the world",
95 where = PluginDescriptor.WHERE_PLUGINMENU,
97 icon="webcamviewer.png"
108 currentslideshowitem =0
110 def __init__(self,session,callback):
111 self.session = session
112 self.callback = callback
113 def setfiles(self,filelist):
114 self.filelist = filelist
117 if len(self.filelist)>0:
118 self.currentslideshowitem = -1
119 self.nextSlideshowItem()
121 def nextSlideshowItem(self):
122 if self.currentslideshowitem is not (len(self.filelist)-1):
123 self.currentslideshowitem = self.currentslideshowitem+1
124 filetoshow = self.filelist[self.currentslideshowitem][1]
125 if self.wbviewer is False:
126 self.wbviewer = self.session.openWithCallback(self.cb,PictureScreen,filetoshow.split("/")[-1],filetoshow,slideshowcallback=self.nextSlideshowItem)
128 self.wbviewer.filename = filetoshow
130 elif self.currentslideshowitem is (len(self.filelist)-1) and int(config.plugins.pictureviewer.slideshowmode.value) is SLIDESHOWMODE_REPEAT:
131 print "["+myname+"] restarting slideshow"
134 print "["+myname+"] slideshow finished"
140 class PictureViewer(Screen):
143 currList = "slideshowlist"
145 loadedslideshowlistlistname = False
146 def __init__(self, session, args = 0):
147 self.session = session
148 s = "<screen position=\"93,70\" size=\"550,450\" title=\"%s\">\n" %config.plugins.pictureviewer.rootdir.value
149 s = s+"<widget name=\"menu\" position=\"1,1\" size=\"275,400\" scrollbarMode=\"showOnDemand\" />\n"
150 s = s+"<widget name=\"pixmap\" position=\"550,450\" size=\"275,200\" backgroundColor=\"red\"/>\n"
151 s = s+"<widget name=\"slist\" position=\"275,200\" size=\"275,200\" scrollbarMode=\"showOnDemand\"/>\n"
152 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"
153 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"
154 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"
155 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"
156 self.skin = s+"</screen>"
157 Screen.__init__(self, session)
158 self.filelist = PictureList(config.plugins.pictureviewer.rootdir.value, matchingPattern = config.plugins.pictureviewer.matchingPattern.value)
159 self["menu"] = self.filelist
160 self.preview = Pixmap()
161 self["pixmap"] = self.preview
162 self.slideshowfiles = []
163 self.slideshowlist =MenuList(self.slideshowfiles)
164 self["slist"] = self.slideshowlist
165 self["buttonred"] = Label("")
166 self["buttongreen"] = Label("")
167 self["buttonyellow"] = Label("")
168 self["buttonblue"] = Label("")
169 self["actions"] = ActionMap(["WizardActions","MenuActions", "DirectionActions","ShortcutActions"],
173 "menu": self.openMenu,
177 "right": self.rightUp,
179 "green": self.KeyGreen,
180 "yellow": self.KeyYellow,
181 "blue": self.switchList,
183 self.onLayoutFinish.append(self.switchList)
184 self.onLayoutFinish.append(self.updateInfoPanel)
186 if self.currList is "filelist" :
187 ## adding all files in current dir to slideshowlist
188 dirname = self["menu"].getCurrentDir()
189 if os.path.isdir(dirname):
190 s = os.listdir(dirname)
193 if compile(config.plugins.pictureviewer.matchingPattern.value).search(dirname+file):
194 self.slideshowfiles.append((_(file),dirname+file))
195 self["slist"].l.setList(self.slideshowfiles)
201 for file in os.listdir(config.plugins.pictureviewer.slideshowdir.value):
202 if file.endswith(config.plugins.pictureviewer.slideshowext.value):
203 list.append((_(file.split("/")[-1]),file))
204 self.session.openWithCallback(self.fileToLoadFilelistEntered,ChoiceBox,_("select List to load"),list)
206 print "["+myname+"] IOError:",e
208 print "["+myname+"] OSError:",e
211 if self.currList is "filelist" :
214 x = Slideshow(self.session,self.show)
215 x.setfiles(self.slideshowfiles)
219 if self.loadedslideshowlistlistname is False:
220 newname = "slideshowlist"
222 newname = self.loadedslideshowlistlistname
223 self.session.openWithCallback(self.fileToSaveFilelistEntered,InputBox, title=_("Enter filename to save the List:"), text=newname, maxSize=False, type=Input.TEXT)
225 def fileToLoadFilelistEntered(self,fileselection):
226 if fileselection is not None:
228 filename = fileselection[1]
229 fp = open(config.plugins.pictureviewer.slideshowdir.value+filename)
231 for x in fp.readlines():
232 file = x.replace("\n","")
233 if x.startswith("#"):
235 elif os.path.exists(file) is not True:
236 print "["+myname+"] loaded file from filelist isnt avaible! ignoreing ->",file
238 list.append((_(file.split("/")[-1]),file))
239 self.slideshowfiles =list
240 self["slist"].l.setList(self.slideshowfiles)
241 self.loadedslideshowlistlistname = filename.replace(config.plugins.pictureviewer.slideshowext.value,"")
243 print "["+myname+"] error:",e
245 def fileToSaveFilelistEntered(self,filename):
246 if filename is not None:
247 print "["+myname+"] saving list to ",config.plugins.pictureviewer.slideshowdir.value+filename+config.plugins.pictureviewer.slideshowext.value
249 if os.path.exists(config.plugins.pictureviewer.slideshowdir.value) is not True:
250 print "+"*10,os.path.basename(filename)
251 os.mkdir(config.plugins.pictureviewer.slideshowdir.value)
252 fp = open(config.plugins.pictureviewer.slideshowdir.value+filename+config.plugins.pictureviewer.slideshowext.value,"w")
253 fp.write("# this is a slideshow file for "+myname+" made by V"+myversion+"\n")
254 fp.write("# you can make your own... each line with full path of the imagefile\n")
255 fp.write("# by importing this file,we will ignoring a file if is doesnt exist\n")
256 for x in self.slideshowfiles:
260 print "["+myname+"] error:",e
262 if self.currList is "filelist" :
263 # add picture to list
264 fullfile = self["menu"].getSelection()[0]
265 if os.path.isfile(fullfile):
266 self.slideshowfiles.append((_(fullfile.split("/")[-1]),fullfile))
267 self["slist"].l.setList(self.slideshowfiles)
269 # deleting an Picture
270 if len(self.slideshowfiles) >=1:
271 indexinlist = self["slist"].l.getCurrentSelectionIndex()
272 self.slideshowfiles.pop(indexinlist)
273 self["slist"].l.setList(self.slideshowfiles)
275 def switchList(self):
276 if self.currList is "filelist" :
277 # Slideshow activieren
278 self.filelist.selectionEnabled(0)
279 self.slideshowlist.selectionEnabled(1)
280 self["buttonred"].setText("speichern")
281 self["buttongreen"].setText("laden")
282 self["buttonyellow"].setText("loeschen")
283 self["buttonblue"].setText("Dateien")
284 self.currList = "slideshowlist"
286 # filelist activieren
287 self.filelist.selectionEnabled(1)
288 self.slideshowlist.selectionEnabled(0)
289 self["buttonred"].setText("starte Slideshow")
290 self["buttongreen"].setText("alle hinzufuegen")
291 self["buttonyellow"].setText("hinzufuegen")
292 self["buttonblue"].setText("Slideshow bearbeiten")
293 self.currList = "filelist"
296 if self.currList is "filelist" :
297 selection = self["menu"].getSelection()
298 if self.filelist.canDescent():
299 self.setTitle(selection[0])
300 self.filelist.descent()
302 if selection[1] == True: # isDir
305 print "["+myname+"] file selected ",selection[0]
306 if os.path.isfile(selection[0]):
307 self.session.open(PictureScreen,selection[0].split("/")[-1],selection[0])
309 print "["+myname+"] file not found " + selection[0]+""
311 self.updateInfoPanel()
313 if self.currList is "filelist" :
315 self.updateInfoPanel()
317 self.slideshowlist.up()
319 if self.currList is "filelist" :
320 self.filelist.pageUp()
321 self.updateInfoPanel()
324 self.slideshowlist.pageUp()
326 if self.currList is "filelist" :
327 self.filelist.pageDown()
328 self.updateInfoPanel()
330 self.slideshowlist.pageDown()
332 if self.currList is "filelist" :
334 self.updateInfoPanel()
336 self.slideshowlist.down()
338 def updateInfoPanel(self):
339 if self.currList is "filelist" :
340 selectedfile = self["menu"].getSelection()[0]
342 selectedfile = self["slist"].l.getCurrentSelection()[1]
343 pixmap = loadPic(selectedfile, 275,200, 1,1, 0,1)
344 if pixmap is not None:
345 self["pixmap"].instance.setPixmap(pixmap.__deref__())
346 self["pixmap"].move(275,0)
350 def output(self,str):
353 self.session.open(WebcamViewerMenu)
355 class WebcamViewer(Screen):
358 def __init__(self, session,xmlnode, args = 0):
359 self.xmlnode = xmlnode
364 pos_x = (screen_x/2)-(size_x/2)
365 pos_y = (screen_y/2)-(size_y/2)
366 self.session = session
368 <screen position="%i,%i" size="%i,%i" title="%s">
369 <widget name="menu" position="1,1" size="%i,%i" scrollbarMode="showOnDemand"/>
370 </screen>""" % (pos_x,pos_y,size_x,size_y,myname,size_x,size_y)
371 Screen.__init__(self, session)
372 self.filelist = MenuList(self.getMenuData())
373 self["menu"] = self.filelist
374 self["actions"] = ActionMap(["WizardActions", "DirectionActions"],
379 self.onLayoutFinish.append(self.settingTitle)
381 def settingTitle(self):
382 self.setTitle(myname+": "+self.menutitle)
385 selected = self["menu"].l.getCurrentSelection()[1]
386 menuitemtitle = self["menu"].l.getCurrentSelection()[0]
389 if type.startswith("cam"):
390 self.session.open(PictureScreen,menuitemtitle,data)
393 self.session.openWithCallback(self.cb,WebcamViewer,data)
398 def getMenuData(self):
399 xloader = XMLloader()
400 self.menutitle = xloader.getScreenXMLTitle(self.xmlnode)
402 for node in elementsWithTag(self.xmlnode._get_childNodes(), 'menu'):
404 nodex['name'] = xloader.get_txt( node, "name", "no name" )
405 data.append((_("*"+nodex['name']),["node",node]))
407 for node2 in elementsWithTag(self.xmlnode._get_childNodes(), 'cam'):
409 nodex['name'] = xloader.get_txt( node2, "name", "no name" )
410 nodex['url'] = xloader.get_txt( node2, "url", "no url" )
411 data.append((_(nodex['name']),["cam",nodex['url']]))
416 class PictureList(MenuList):
417 def __init__(self, directory, matchingPattern = None, enableWrapAround = False):
418 MenuList.__init__(self, None, enableWrapAround, eListboxPythonMultiContent)
419 self.showDirectories = True
420 self.showFiles = True
422 self.matchingPattern = matchingPattern
423 self.changeDir(directory)
424 self.l.setFont(0, gFont("Regular", 18))
425 self.currentDir = directory
427 def getCurrentDir(self):
428 return self.currentDir
430 def getSelection(self):
431 return self.l.getCurrentSelection()[0]
433 def getFileList(self):
436 def changeDir(self, directory):
437 self.currentDir = directory
442 files = os.listdir(directory)
446 if os.path.isdir(directory +"/"+ x):
447 directories.append(x)
451 if directory != "/" and self.showDirectories and not self.isTop:
452 self.list.append(self.getPictureEntryComponent("..",'/'.join(directory.split('/')[:-2]) + '/',True))
454 if self.showDirectories:
455 for x in directories:
456 name = (directory+x).split('/')[-1]
457 self.list.append(self.getPictureEntryComponent(name,'/'.join(directory.split('/')[:-1]) + '/'+x+'/',True))
463 if self.matchingPattern is not None:
464 if compile(self.matchingPattern).search(path):
465 self.list.append(self.getPictureEntryComponent(name,path ,False))
469 self.l.setList(self.list)
471 def canDescent(self):
472 return self.getSelection()[1]
475 self.changeDir(self.getSelection()[0])
477 def getFilename(self):
478 return self.getSelection()[0].getPath()
480 def getServiceRef(self):
481 return self.getSelection()[0]
483 def postWidgetCreate(self, instance):
484 MenuList.postWidgetCreate(self, instance)
485 instance.setItemHeight(23)
487 def getPictureEntryComponent(self,name, absolute, isDir):
488 """ name={angezeigter Name}, absolute={vollstaendiger Pfad}, isDir={True,False} """
489 res = [ (absolute, isDir) ]
490 res.append((eListboxPythonMultiContent.TYPE_TEXT, 35, 1, 200, 20, 0, 0, name))
492 png = loadPNG("/usr/share/enigma2/extensions/directory.png")
494 extension = name.split('.')
495 extension = extension[-1].lower()
496 if EXTENSIONS.has_key(extension):
497 png = loadPNG("/usr/share/enigma2/extensions/" + EXTENSIONS[extension] + ".png")
501 res.append((eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, 10, 2, 20, 20, png))
507 DEFAULT_NAMESPACES = (
508 None, # RSS 0.91, 0.92, 0.93, 0.94, 2.0
509 'http://purl.org/rss/1.0/', # RSS 1.0
510 'http://my.netscape.com/rdf/simple/0.9/' # RSS 0.90
512 DUBLIN_CORE = ('http://purl.org/dc/elements/1.1/',)
513 def getElementsByTagName( self, node, tagName, possibleNamespaces=DEFAULT_NAMESPACES ):
514 for namespace in possibleNamespaces:
515 children = node.getElementsByTagNameNS(namespace, tagName)
516 if len(children): return children
519 def node_data( self, node, tagName, possibleNamespaces=DEFAULT_NAMESPACES):
520 children = self.getElementsByTagName(node, tagName, possibleNamespaces)
521 node = len(children) and children[0] or None
522 return node and "".join([child.data.encode("utf-8") for child in node.childNodes]) or None
524 def get_txt( self, node, tagName, default_txt="" ):
526 Liefert den Inhalt >tagName< des >node< zurueck, ist dieser nicht
527 vorhanden, wird >default_txt< zurueck gegeben.
529 return self.node_data( node, tagName ) or self.node_data( node, tagName, self.DUBLIN_CORE ) or default_txt
531 def getScreenXMLTitle( self,node ):
532 return self.get_txt( node, "name", "no title" )