stop service playback on start
[enigma2-plugins.git] / webcamviewer / src / plugin.py
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
6 ### Picturelist
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 ## configmenu
16 from Components.config import config, ConfigSubsection,ConfigSelection,ConfigText,ConfigYesNo
17 ####
18 from Components.Input import Input
19 from Components.Pixmap import Pixmap
20 from Plugins.Plugin import PluginDescriptor
21 ### System
22 import os
23 from re import compile
24 ## XML
25 from pyexpat import ExpatError
26 import xml.dom.minidom
27 from Tools.XMLTools import elementsWithTag
28
29 ### my
30 from WebcamViewConfig import WebcamViewerMenu
31 from PictureScreen import PictureScreen
32 ###
33 myname = "Webcam/Picture Viewer"    
34 myversion = "1.1"
35
36
37
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"))])
41 #not editable configs
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
49
50 originalservice = None
51 mysession = None
52   
53 def main1(session,**kwargs):
54     global originalservice,mysession
55     mysession = session
56     originalservice = session.nav.getCurrentlyPlayingServiceReference()
57     if config.plugins.pictureviewer.stopserviceonstart.value:
58         session.nav.stopService()
59     session.openWithCallback(mainCB,PictureViewer)
60
61 def main2(session,**kwargs):
62     global originalservice,mysession
63     mysession = session
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):
69         try:
70             xmlnode = xml.dom.minidom.parse( open(xmlfile) )
71             session.openWithCallback(mainCB,WebcamViewer,xmlnode.childNodes[1])
72         except ExpatError,e:
73             session.open(MessageBox,_("Loading config file failed!\n\n%s"%e), MessageBox.TYPE_WARNING)
74     else:
75         session.open(MessageBox,_("Loading config file failed!\n\nconfigfile not found!"), MessageBox.TYPE_WARNING)
76         
77 def mainCB():
78     global originalservice,mysession
79     if config.plugins.pictureviewer.stopserviceonstart.value:
80         mysession.nav.playService(originalservice)
81     
82 def Plugins(path,**kwargs):
83     p = [
84              PluginDescriptor(
85                               name="PictureViewer", 
86                               description="browse your local pictures", 
87                               where = PluginDescriptor.WHERE_PLUGINMENU,
88                               fnc = main1,
89                               icon="pictureviewer.png"
90                               )
91         ,
92             PluginDescriptor(
93                              name="WebcamViewer", 
94                              description="view webcams around the world", 
95                              where = PluginDescriptor.WHERE_PLUGINMENU,
96                              fnc = main2,
97                              icon="webcamviewer.png"
98                              )
99          ]
100     return p 
101
102
103         
104
105 ###################
106 class Slideshow:
107     filelist=[]
108     currentslideshowitem =0
109     wbviewer = False
110     def __init__(self,session,callback):
111         self.session = session
112         self.callback = callback
113     def setfiles(self,filelist):
114         self.filelist = filelist 
115
116     def start(self):
117         if len(self.filelist)>0:            
118             self.currentslideshowitem = -1
119             self.nextSlideshowItem()
120             
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)              
127             else:
128                 self.wbviewer.filename = filetoshow
129                 self.wbviewer.do()    
130         elif self.currentslideshowitem is (len(self.filelist)-1) and int(config.plugins.pictureviewer.slideshowmode.value) is SLIDESHOWMODE_REPEAT:
131             print "["+myname+"] restarting slideshow"
132             self.start()
133         else:
134             print "["+myname+"] slideshow finished"
135             self.wbviewer.exit()
136             self.cb()
137     def cb(self):
138         self.callback()
139 ###################
140 class PictureViewer(Screen):
141     skin = ""
142     filelist = []
143     currList = "slideshowlist"
144     wbviewer = False
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"], 
170             {
171              "ok": self.go,
172              "back": self.close,
173              "menu": self.openMenu,
174              "up": self.up,
175              "down": self.down,
176              "left": self.leftUp,
177              "right": self.rightUp,
178              "red": self.KeyRed,
179              "green": self.KeyGreen,
180              "yellow": self.KeyYellow,
181              "blue": self.switchList,
182              }, -1)
183         self.onLayoutFinish.append(self.switchList)
184         self.onLayoutFinish.append(self.updateInfoPanel)
185     def KeyGreen(self):
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)
191                 s.sort()
192                 for file in s:
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)
196                     
197         else:
198             #loading list
199             list = []
200             try:
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)
205             except IOError,e:
206                 print "["+myname+"] IOError:",e
207             except OSError,e:
208                 print "["+myname+"] OSError:",e
209                
210     def KeyRed(self):
211         if self.currList is "filelist" :
212             #do slideshow
213             self.hide()
214             x = Slideshow(self.session,self.show)
215             x.setfiles(self.slideshowfiles)
216             x.start()
217         else:
218             # save filelist
219             if self.loadedslideshowlistlistname is False:
220                 newname = "slideshowlist"
221             else:
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)
224
225     def fileToLoadFilelistEntered(self,fileselection):
226         if fileselection is not None: 
227                try:
228                    filename = fileselection[1]
229                    fp = open(config.plugins.pictureviewer.slideshowdir.value+filename)
230                    list = []
231                    for x in fp.readlines():
232                        file = x.replace("\n","")
233                        if x.startswith("#"):
234                            pass
235                        elif os.path.exists(file) is not True:
236                            print "["+myname+"] loaded file from filelist isnt avaible! ignoreing ->",file
237                        else:
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,"")
242                except IOError,e:
243                    print "["+myname+"] error:",e
244                
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
248             try:
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:
257                     fp.write(x[1]+"\n")
258                 fp.close()
259             except IOError,e:
260                 print "["+myname+"] error:",e
261     def KeyYellow(self):
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)
268         else:
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)
274
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"
285         else:
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"
294                 
295     def go(self):
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()
301             else:
302                 if selection[1] == True: # isDir
303                     pass
304                 else:
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])
308                     else:
309                         print "["+myname+"] file not found " + selection[0]+""
310         else:
311             self.updateInfoPanel()
312     def up(self):
313          if self.currList is "filelist" :
314              self.filelist.up()
315              self.updateInfoPanel()
316          else:
317              self.slideshowlist.up()
318     def leftUp(self):
319          if self.currList is "filelist" :
320              self.filelist.pageUp()         
321              self.updateInfoPanel()
322          else:
323
324              self.slideshowlist.pageUp()
325     def rightUp(self):
326         if self.currList is "filelist" :
327              self.filelist.pageDown()
328              self.updateInfoPanel()
329         else:
330              self.slideshowlist.pageDown()
331     def down(self):
332          if self.currList is "filelist" :
333              self.filelist.down()
334              self.updateInfoPanel()
335          else:
336              self.slideshowlist.down()
337              
338     def updateInfoPanel(self):
339         if self.currList is "filelist" :
340             selectedfile = self["menu"].getSelection()[0]
341         else:
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)
347         else:
348             pass
349                 
350     def output(self,str):
351         print "+"*10,str  
352     def openMenu(self):
353         self.session.open(WebcamViewerMenu)
354 ###################
355 class WebcamViewer(Screen):
356     skin = ""
357     filelist = []
358     def __init__(self, session,xmlnode, args = 0):
359         self.xmlnode = xmlnode
360         screen_x = 736
361         screen_y = 576
362         size_x = 350
363         size_y = 250
364         pos_x = (screen_x/2)-(size_x/2)
365         pos_y = (screen_y/2)-(size_y/2)
366         self.session = session
367         self.skin = """
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"], 
375             {
376              "ok": self.go,
377              "back": self.close,
378              }, -1)
379         self.onLayoutFinish.append(self.settingTitle)
380         
381     def settingTitle(self):
382         self.setTitle(myname+": "+self.menutitle)
383         
384     def go(self):
385         selected = self["menu"].l.getCurrentSelection()[1]
386         menuitemtitle = self["menu"].l.getCurrentSelection()[0]
387         type = selected[0]
388         data = selected[1]
389         if type.startswith("cam"):
390             self.session.open(PictureScreen,menuitemtitle,data)
391         else:
392             self.hide()
393             self.session.openWithCallback(self.cb,WebcamViewer,data)
394
395     def cb(self):
396         self.show() 
397                
398     def getMenuData(self):
399         xloader = XMLloader()
400         self.menutitle = xloader.getScreenXMLTitle(self.xmlnode)
401         data =[]        
402         for node in  elementsWithTag(self.xmlnode._get_childNodes(), 'menu'):
403             nodex={}
404             nodex['name'] =  xloader.get_txt( node, "name", "no name" )
405             data.append((_("*"+nodex['name']),["node",node]))
406         
407         for node2 in elementsWithTag(self.xmlnode._get_childNodes(), 'cam'):
408             nodex={}
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']]))
412         return data
413 ###################
414
415 ##################
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
421         self.isTop = False
422         self.matchingPattern = matchingPattern
423         self.changeDir(directory)
424         self.l.setFont(0, gFont("Regular", 18))
425         self.currentDir = directory
426
427     def getCurrentDir(self):
428         return self.currentDir
429     
430     def getSelection(self):
431         return self.l.getCurrentSelection()[0]
432     
433     def getFileList(self):
434         return self.list
435     
436     def changeDir(self, directory):
437         self.currentDir = directory
438         self.list = []
439         
440         directories = []
441         files = []
442         files = os.listdir(directory)
443         files.sort()
444         tmpfiles = files[:]
445         for x in tmpfiles:
446             if os.path.isdir(directory +"/"+ x):
447                 directories.append(x)
448                 files.remove(x)
449         directories.sort()
450         files.sort()
451         if directory != "/" and self.showDirectories and not self.isTop:
452             self.list.append(self.getPictureEntryComponent("..",'/'.join(directory.split('/')[:-2]) + '/',True))
453
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))
458
459         if self.showFiles:
460             for x in files:
461                 path = directory + x
462                 name = x
463                 if self.matchingPattern is not None:
464                     if compile(self.matchingPattern).search(path):
465                         self.list.append(self.getPictureEntryComponent(name,path ,False))
466                 else:
467                     pass 
468                 
469         self.l.setList(self.list)
470         
471     def canDescent(self):
472         return self.getSelection()[1]
473     
474     def descent(self):
475         self.changeDir(self.getSelection()[0])
476         
477     def getFilename(self):
478         return self.getSelection()[0].getPath()
479
480     def getServiceRef(self):
481         return self.getSelection()[0]
482
483     def postWidgetCreate(self, instance):
484         MenuList.postWidgetCreate(self, instance)
485         instance.setItemHeight(23)
486     
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))
491         if isDir:
492             png = loadPNG("/usr/share/enigma2/extensions/directory.png")
493         else: 
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")
498             else:
499                 png = None
500         if png is not None:
501             res.append((eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, 10, 2, 20, 20, png))
502         return res
503
504
505 ##################
506 class XMLloader:
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
511         )
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
517         return []
518
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
523
524     def get_txt( self, node, tagName, default_txt="" ):
525         """
526         Liefert den Inhalt >tagName< des >node< zurueck, ist dieser nicht
527         vorhanden, wird >default_txt< zurueck gegeben.
528         """
529         return self.node_data( node, tagName ) or self.node_data( node, tagName, self.DUBLIN_CORE ) or default_txt
530
531     def getScreenXMLTitle( self,node ):
532         return self.get_txt( node, "name", "no title" )