Merge branch 'obi/master' into experimental
[vuplus_dvbapp] / lib / python / Plugins / Extensions / DVDPlayer / plugin.py
1 from os import path as os_path, remove as os_remove, listdir as os_listdir, system
2 from enigma import eTimer, iPlayableService, iServiceInformation, eServiceReference, iServiceKeys, getDesktop
3 from Screens.Screen import Screen
4 from Screens.MessageBox import MessageBox
5 from Screens.ChoiceBox import ChoiceBox
6 from Screens.HelpMenu import HelpableScreen
7 from Screens.InfoBarGenerics import InfoBarSeek, InfoBarPVRState, InfoBarCueSheetSupport, InfoBarShowHide, InfoBarNotifications
8 from Components.ActionMap import ActionMap, NumberActionMap, HelpableActionMap
9 from Components.Label import Label
10 from Components.Sources.StaticText import StaticText
11 from Components.Pixmap import Pixmap
12 from Components.FileList import FileList
13 from Components.MenuList import MenuList
14 from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
15 from Components.config import config
16 from Tools.Directories import pathExists, fileExists
17 from Components.Harddisk import harddiskmanager
18
19 import servicedvd # load c++ part of dvd player plugin
20
21 lastpath = ""
22
23 class FileBrowser(Screen):
24
25         def __init__(self, session, dvd_filelist = [ ]):
26                 Screen.__init__(self, session)
27
28                 # for the skin: first try FileBrowser_DVDPlayer, then FileBrowser, this allows individual skinning
29                 self.skinName = ["FileBrowser_DVDPlayer", "FileBrowser" ]
30
31                 self.dvd_filelist = dvd_filelist
32                 if len(dvd_filelist):   
33                         self["filelist"] = MenuList(self.dvd_filelist)
34                 else:
35                         global lastpath
36                         if lastpath is not None:
37                                 currDir = lastpath + "/"
38                         else:
39                                 currDir = "/media/dvd/"
40                         if not pathExists(currDir):
41                                 currDir = "/"
42                         if lastpath == "":  # 'None' is magic to start at the list of mountpoints
43                                 currDir = None
44
45                         inhibitDirs = ["/bin", "/boot", "/dev", "/etc", "/home", "/lib", "/proc", "/sbin", "/share", "/sys", "/tmp", "/usr", "/var"]
46                         self.filelist = FileList(currDir, matchingPattern = "(?i)^.*\.(iso|img)", useServiceRef = True)
47                         self["filelist"] = self.filelist
48
49                 self["FilelistActions"] = ActionMap(["SetupActions"],
50                         {
51                                 "save": self.ok,
52                                 "ok": self.ok,
53                                 "cancel": self.exit
54                         })
55                 self["key_red"] = StaticText(_("Cancel"))
56                 self["key_green"] = StaticText(_("OK"))
57                 self.onLayoutFinish.append(self.layoutFinished)
58
59         def layoutFinished(self):
60                 self.setTitle(_("DVD File Browser"))
61
62         def ok(self):
63                 if len(self.dvd_filelist):
64                         print "OK " + self["filelist"].getCurrent()
65                         self.close(self["filelist"].getCurrent())
66                 else:
67                         global lastpath
68                         filename = self["filelist"].getFilename()
69                         if filename is not None:
70                                 if filename.upper().endswith("VIDEO_TS/"):
71                                         print "dvd structure found, trying to open..."
72                                         dvdpath = filename[0:-9]
73                                         lastpath = (dvdpath.rstrip("/").rsplit("/",1))[0]
74                                         print "lastpath video_ts/=", lastpath
75                                         self.close(dvdpath)
76                                         return
77                         if self["filelist"].canDescent(): # isDir
78                                 self["filelist"].descent()
79                                 pathname = self["filelist"].getCurrentDirectory() or ""
80                                 if fileExists(pathname+"VIDEO_TS.IFO"):
81                                         print "dvd structure found, trying to open..."
82                                         lastpath = (pathname.rstrip("/").rsplit("/",1))[0]
83                                         print "lastpath video_ts.ifo=", lastpath
84                                         self.close(pathname)
85                                 if fileExists(pathname+"VIDEO_TS/VIDEO_TS.IFO"):
86                                         print "dvd structure found, trying to open..."
87                                         lastpath = (pathname.rstrip("/").rsplit("/",1))[0]
88                                         print "lastpath video_ts.ifo=", lastpath
89                                         pathname += "VIDEO_TS"
90                                         self.close(pathname)
91                         else:
92                                 lastpath = filename[0:filename.rfind("/")]
93                                 print "lastpath directory=", lastpath
94                                 self.close(filename)
95
96         def exit(self):
97                 self.close(None)
98
99 class DVDSummary(Screen):
100         skin = (
101         """<screen name="DVDSummary" position="0,0" size="132,64" id="1">
102                 <widget source="session.CurrentService" render="Label" position="5,4" size="120,28" font="Regular;12" transparent="1" >
103                         <convert type="ServiceName">Name</convert>
104                 </widget>
105                 <widget name="DVDPlayer" position="5,30" size="66,16" font="Regular;11" transparent="1" />
106                 <widget name="Chapter" position="72,30" size="54,16" font="Regular;12" transparent="1" halign="right" />
107                 <widget source="session.CurrentService" render="Label" position="66,46" size="60,18" font="Regular;16" transparent="1" halign="right" >
108                         <convert type="ServicePosition">Position</convert>
109                 </widget>
110                 <widget source="session.CurrentService" render="Progress" position="6,46" size="60,18" borderWidth="1" >
111                         <convert type="ServicePosition">Position</convert>
112                 </widget>
113         </screen>""",
114         """<screen name="DVDSummary" position="0,0" size="96,64" id="2">
115                 <widget source="session.CurrentService" render="Label" position="0,0" size="96,25" font="Regular;12" transparent="1" >
116                         <convert type="ServiceName">Name</convert>
117                 </widget>
118                 <widget name="DVDPlayer" position="0,26" size="96,12" font="Regular;10" transparent="1" />
119                 <widget name="Chapter" position="0,40" size="66,12" font="Regular;10" transparent="1" halign="left" />
120                 <widget source="session.CurrentService" render="Label" position="66,40" size="30,12" font="Regular;10" transparent="1" halign="right" >
121                         <convert type="ServicePosition">Position</convert>
122                 </widget>
123                 <widget source="session.CurrentService" render="Progress" position="0,52" size="96,12" borderWidth="1" >
124                         <convert type="ServicePosition">Position</convert>
125                 </widget>
126         </screen>""")
127
128         def __init__(self, session, parent):
129                 Screen.__init__(self, session, parent)
130
131                 self["DVDPlayer"] = Label("DVD Player")
132                 self["Title"] = Label("")
133                 self["Time"] = Label("")
134                 self["Chapter"] = Label("")
135
136         def updateChapter(self, chapter):
137                 self["Chapter"].setText(chapter)
138
139         def setTitle(self, title):
140                 self["Title"].setText(title)
141
142 class DVDOverlay(Screen):
143         def __init__(self, session, args = None):
144                 desktop_size = getDesktop(0).size()
145                 DVDOverlay.skin = """<screen name="DVDOverlay" position="0,0" size="%d,%d" flags="wfNoBorder" zPosition="-1" backgroundColor="transparent" />""" %(desktop_size.width(), desktop_size.height())
146                 Screen.__init__(self, session)
147
148 class ChapterZap(Screen):
149         skin = """
150         <screen name="ChapterZap" position="235,255" size="250,60" title="Chapter" >
151                 <widget name="chapter" position="35,15" size="110,25" font="Regular;23" />
152                 <widget name="number" position="145,15" size="80,25" halign="right" font="Regular;23" />
153         </screen>"""
154         
155         def quit(self):
156                 self.Timer.stop()
157                 self.close(0)
158
159         def keyOK(self):
160                 self.Timer.stop()
161                 self.close(int(self["number"].getText()))
162
163         def keyNumberGlobal(self, number):
164                 self.Timer.start(3000, True)            #reset timer
165                 self.field = self.field + str(number)
166                 self["number"].setText(self.field)
167                 if len(self.field) >= 4:
168                         self.keyOK()
169
170         def __init__(self, session, number):
171                 Screen.__init__(self, session)
172                 self.field = str(number)
173
174                 self["chapter"] = Label(_("Chapter:"))
175
176                 self["number"] = Label(self.field)
177
178                 self["actions"] = NumberActionMap( [ "SetupActions" ],
179                         {
180                                 "cancel": self.quit,
181                                 "ok": self.keyOK,
182                                 "1": self.keyNumberGlobal,
183                                 "2": self.keyNumberGlobal,
184                                 "3": self.keyNumberGlobal,
185                                 "4": self.keyNumberGlobal,
186                                 "5": self.keyNumberGlobal,
187                                 "6": self.keyNumberGlobal,
188                                 "7": self.keyNumberGlobal,
189                                 "8": self.keyNumberGlobal,
190                                 "9": self.keyNumberGlobal,
191                                 "0": self.keyNumberGlobal
192                         })
193
194                 self.Timer = eTimer()
195                 self.Timer.callback.append(self.keyOK)
196                 self.Timer.start(3000, True)
197
198 class DVDPlayer(Screen, InfoBarBase, InfoBarNotifications, InfoBarSeek, InfoBarPVRState, InfoBarShowHide, HelpableScreen, InfoBarCueSheetSupport):
199         ALLOW_SUSPEND = Screen.SUSPEND_PAUSES
200         ENABLE_RESUME_SUPPORT = True
201         
202         skin = """
203         <screen name="DVDPlayer" flags="wfNoBorder" position="0,380" size="720,160" title="InfoBar" backgroundColor="transparent" >
204                 <!-- Background -->
205                 <ePixmap position="0,0" zPosition="-2" size="720,160" pixmap="skin_default/info-bg_mp.png" alphatest="off" />
206                 <ePixmap position="29,40" zPosition="0" size="665,104" pixmap="skin_default/screws_mp.png" alphatest="on" transparent="1" />
207                 <!-- colorbuttons -->
208                 <ePixmap position="48,70" zPosition="0" size="108,13" pixmap="skin_default/icons/mp_buttons.png" alphatest="on" />
209                 <!-- Servicename -->
210                 <ePixmap pixmap="skin_default/icons/icon_event.png" position="207,78" zPosition="1" size="15,10" alphatest="on" />
211                 <widget source="session.CurrentService" render="Label" position="230,73" size="300,22" font="Regular;20" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" noWrap="1">
212                         <convert type="ServiceName">Name</convert>
213                 </widget>
214                 <!-- Chapter info -->
215                 <widget name="chapterLabel" position="230,96" size="360,22" font="Regular;20" foregroundColor="#c3c3c9" backgroundColor="#263c59" transparent="1" />
216                 <!-- Audio track info -->
217                 <ePixmap pixmap="skin_default/icons/icon_dolby.png" position="540,60" zPosition="1" size="26,16" alphatest="on"/>
218                 <widget name="audioLabel" position="570,60" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
219                 <!-- Subtitle track info -->
220                 <widget source="session.CurrentService" render="Pixmap" pixmap="skin_default/icons/icon_txt.png" position="540,83" zPosition="1" size="26,16" alphatest="on" >
221                         <convert type="ServiceInfo">HasTelext</convert>
222                         <convert type="ConditionalShowHide" />
223                 </widget>
224                 <widget name="subtitleLabel" position="570,83" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
225                 <!-- Angle info -->
226                 <widget name="anglePix" pixmap="skin_default/icons/icon_view.png" position="540,106" size="26,16" alphatest="on" />
227                 <widget name="angleLabel" position="570,106" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
228                 <!-- Elapsed time -->
229                 <widget source="session.CurrentService" render="Label" position="205,129" size="100,20" font="Regular;18" halign="center" valign="center" backgroundColor="#06224f" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" >
230                         <convert type="ServicePosition">Position,ShowHours</convert>
231                 </widget>
232                 <!-- Progressbar (movie position)-->
233                 <widget source="session.CurrentService" render="PositionGauge" position="300,133" size="270,10" zPosition="2" pointer="skin_default/position_pointer.png:540,0" transparent="1" >
234                         <convert type="ServicePosition">Gauge</convert>
235                 </widget>
236                 <!-- Remaining time -->
237                 <widget source="session.CurrentService" render="Label" position="576,129" size="100,20" font="Regular;18" halign="center" valign="center" backgroundColor="#06224f" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" >
238                         <convert type="ServicePosition">Remaining,Negate,ShowHours</convert>
239                 </widget>
240         </screen>"""
241
242         def save_infobar_seek_config(self):
243                 self.saved_config_speeds_forward = config.seek.speeds_forward.value
244                 self.saved_config_speeds_backward = config.seek.speeds_backward.value
245                 self.saved_config_enter_forward = config.seek.enter_forward.value
246                 self.saved_config_enter_backward = config.seek.enter_backward.value
247                 self.saved_config_seek_on_pause = config.seek.on_pause.value
248                 self.saved_config_seek_speeds_slowmotion = config.seek.speeds_slowmotion.value
249
250         def change_infobar_seek_config(self):
251                 config.seek.speeds_forward.value = [2, 4, 8, 16, 32, 64]
252                 config.seek.speeds_backward.value = [8, 16, 32, 64]
253                 config.seek.speeds_slowmotion.value = [ ]
254                 config.seek.enter_forward.value = "2"
255                 config.seek.enter_backward.value = "2"
256                 config.seek.on_pause.value = "play"
257
258         def restore_infobar_seek_config(self):
259                 config.seek.speeds_forward.value = self.saved_config_speeds_forward
260                 config.seek.speeds_backward.value = self.saved_config_speeds_backward
261                 config.seek.speeds_slowmotion.value = self.saved_config_seek_speeds_slowmotion
262                 config.seek.enter_forward.value = self.saved_config_enter_forward
263                 config.seek.enter_backward.value = self.saved_config_enter_backward
264                 config.seek.on_pause.value = self.saved_config_seek_on_pause
265
266         def __init__(self, session, dvd_device = None, dvd_filelist = [ ], args = None):
267                 Screen.__init__(self, session)
268                 InfoBarBase.__init__(self)
269                 InfoBarNotifications.__init__(self)
270                 InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions")
271                 InfoBarShowHide.__init__(self)
272                 HelpableScreen.__init__(self)
273                 self.save_infobar_seek_config()
274                 self.change_infobar_seek_config()
275                 InfoBarSeek.__init__(self)
276                 InfoBarPVRState.__init__(self)
277                 self.dvdScreen = self.session.instantiateDialog(DVDOverlay)
278
279                 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
280                 self.session.nav.stopService()
281                 self["audioLabel"] = Label("n/a")
282                 self["subtitleLabel"] = Label("")
283                 self["angleLabel"] = Label("")
284                 self["chapterLabel"] = Label("")
285                 self["anglePix"] = Pixmap()
286                 self["anglePix"].hide()
287                 self.last_audioTuple = None
288                 self.last_subtitleTuple = None
289                 self.last_angleTuple = None
290                 self.totalChapters = 0
291                 self.currentChapter = 0
292                 self.totalTitles = 0
293                 self.currentTitle = 0
294
295                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
296                         {
297                                 iPlayableService.evStopped: self.__serviceStopped,
298                                 iPlayableService.evUser: self.__timeUpdated,
299                                 iPlayableService.evUser+1: self.__statePlay,
300                                 iPlayableService.evUser+2: self.__statePause,
301                                 iPlayableService.evUser+3: self.__osdFFwdInfoAvail,
302                                 iPlayableService.evUser+4: self.__osdFBwdInfoAvail,
303                                 iPlayableService.evUser+5: self.__osdStringAvail,
304                                 iPlayableService.evUser+6: self.__osdAudioInfoAvail,
305                                 iPlayableService.evUser+7: self.__osdSubtitleInfoAvail,
306                                 iPlayableService.evUser+8: self.__chapterUpdated,
307                                 iPlayableService.evUser+9: self.__titleUpdated,
308                                 iPlayableService.evUser+11: self.__menuOpened,
309                                 iPlayableService.evUser+12: self.__menuClosed,
310                                 iPlayableService.evUser+13: self.__osdAngleInfoAvail
311                         })
312
313                 self["DVDPlayerDirectionActions"] = ActionMap(["DirectionActions"],
314                         {
315                                 #MENU KEY DOWN ACTIONS
316                                 "left": self.keyLeft,
317                                 "right": self.keyRight,
318                                 "up": self.keyUp,
319                                 "down": self.keyDown,
320
321                                 #MENU KEY REPEATED ACTIONS
322                                 "leftRepeated": self.doNothing,
323                                 "rightRepeated": self.doNothing,
324                                 "upRepeated": self.doNothing,
325                                 "downRepeated": self.doNothing,
326
327                                 #MENU KEY UP ACTIONS
328                                 "leftUp": self.doNothing,
329                                 "rightUp": self.doNothing,
330                                 "upUp": self.doNothing,
331                                 "downUp": self.doNothing,
332                         })
333
334                 self["OkCancelActions"] = ActionMap(["OkCancelActions"],
335                         {
336                                 "ok": self.keyOk,
337                                 "cancel": self.keyCancel,
338                         })
339
340                 self["DVDPlayerPlaybackActions"] = HelpableActionMap(self, "DVDPlayerActions",
341                         {
342                                 #PLAYER ACTIONS
343                                 "dvdMenu": (self.enterDVDMenu, _("show DVD main menu")),
344                                 "toggleInfo": (self.toggleInfo, _("toggle time, chapter, audio, subtitle info")),
345                                 "nextChapter": (self.nextChapter, _("forward to the next chapter")),
346                                 "prevChapter": (self.prevChapter, _("rewind to the previous chapter")),
347                                 "nextTitle": (self.nextTitle, _("jump forward to the next title")),
348                                 "prevTitle": (self.prevTitle, _("jump back to the previous title")),
349                                 "tv": (self.askLeavePlayer, _("exit DVD player or return to file browser")),
350                                 "dvdAudioMenu": (self.enterDVDAudioMenu, _("(show optional DVD audio menu)")),
351                                 "nextAudioTrack": (self.nextAudioTrack, _("switch to the next audio track")),
352                                 "nextSubtitleTrack": (self.nextSubtitleTrack, _("switch to the next subtitle language")),
353                                 "nextAngle": (self.nextAngle, _("switch to the next angle")),
354                                 "seekBeginning": self.seekBeginning,
355                         }, -2)
356                         
357                 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
358                         {
359                                 "1": self.keyNumberGlobal,
360                                 "2": self.keyNumberGlobal,
361                                 "3": self.keyNumberGlobal,
362                                 "4": self.keyNumberGlobal,
363                                 "5": self.keyNumberGlobal,
364                                 "6": self.keyNumberGlobal,
365                                 "7": self.keyNumberGlobal,
366                                 "8": self.keyNumberGlobal,
367                                 "9": self.keyNumberGlobal,
368                                 "0": self.keyNumberGlobal,
369                         })
370
371                 self.onClose.append(self.__onClose)
372
373                 from Plugins.SystemPlugins.Hotplug.plugin import hotplugNotifier
374                 hotplugNotifier.append(self.hotplugCB)
375                 
376                 self.autoplay = dvd_device or dvd_filelist
377
378                 if dvd_device:
379                         self.physicalDVD = True
380                 else:
381                         self.scanHotplug()
382
383                 self.dvd_filelist = dvd_filelist
384                 self.onFirstExecBegin.append(self.opened)
385                 self.service = None
386                 self.in_menu = False
387
388         def keyNumberGlobal(self, number):
389                 print "You pressed number " + str(number)
390                 self.session.openWithCallback(self.numberEntered, ChapterZap, number)
391
392         def numberEntered(self, retval):
393 #               print self.servicelist
394                 if retval > 0:
395                         self.zapToNumber(retval)
396
397         def getServiceInterface(self, iface):
398                 service = self.service
399                 if service:
400                         attr = getattr(service, iface, None)
401                         if callable(attr):
402                                 return attr()
403                 return None
404
405         def __serviceStopped(self):
406                 self.dvdScreen.hide()
407                 subs = self.getServiceInterface("subtitle")
408                 if subs:
409                         subs.disableSubtitles(self.session.current_dialog.instance)
410
411         def serviceStarted(self): #override InfoBarShowHide function
412                 self.dvdScreen.show()
413
414         def doEofInternal(self, playing):
415                 if self.in_menu:
416                         self.hide()
417
418         def __menuOpened(self):
419                 self.hide()
420                 self.in_menu = True
421                 self["NumberActions"].setEnabled(False)
422
423         def __menuClosed(self):
424                 self.show()
425                 self.in_menu = False
426                 self["NumberActions"].setEnabled(True)
427
428         def setChapterLabel(self):
429                 chapterLCD = "Menu"
430                 chapterOSD = "DVD Menu"
431                 if self.currentTitle > 0:
432                         chapterLCD = "%s %d" % (_("Chap."), self.currentChapter)
433                         chapterOSD = "DVD %s %d/%d" % (_("Chapter"), self.currentChapter, self.totalChapters)
434                         chapterOSD += " (%s %d/%d)" % (_("Title"), self.currentTitle, self.totalTitles)
435                 self["chapterLabel"].setText(chapterOSD)
436                 try:
437                         self.session.summary.updateChapter(chapterLCD)
438                 except:
439                         pass
440
441         def doNothing(self):
442                 pass
443
444         def toggleInfo(self):
445                 if not self.in_menu:
446                         self.toggleShow()
447                         print "toggleInfo"
448
449         def __timeUpdated(self):
450                 print "timeUpdated"
451
452         def __statePlay(self):
453                 print "statePlay"
454
455         def __statePause(self):
456                 print "statePause"
457
458         def __osdFFwdInfoAvail(self):
459                 self.setChapterLabel()
460                 print "FFwdInfoAvail"
461
462         def __osdFBwdInfoAvail(self):
463                 self.setChapterLabel()
464                 print "FBwdInfoAvail"
465
466         def __osdStringAvail(self):
467                 print "StringAvail"
468
469         def __osdAudioInfoAvail(self):
470                 info = self.getServiceInterface("info")
471                 audioTuple = info and info.getInfoObject(iServiceInformation.sUser+6)
472                 print "AudioInfoAvail ", repr(audioTuple)
473                 if audioTuple:
474                         audioString = "%d: %s (%s)" % (audioTuple[0],audioTuple[1],audioTuple[2])
475                         self["audioLabel"].setText(audioString)
476                         if audioTuple != self.last_audioTuple and not self.in_menu:
477                                 self.doShow()
478                 self.last_audioTuple = audioTuple
479
480         def __osdSubtitleInfoAvail(self):
481                 info = self.getServiceInterface("info")
482                 subtitleTuple = info and info.getInfoObject(iServiceInformation.sUser+7)
483                 print "SubtitleInfoAvail ", repr(subtitleTuple)
484                 if subtitleTuple:
485                         subtitleString = ""
486                         if subtitleTuple[0] is not 0:
487                                 subtitleString = "%d: %s" % (subtitleTuple[0],subtitleTuple[1])
488                         self["subtitleLabel"].setText(subtitleString)
489                         if subtitleTuple != self.last_subtitleTuple and not self.in_menu:
490                                 self.doShow()
491                 self.last_subtitleTuple = subtitleTuple
492         
493         def __osdAngleInfoAvail(self):
494                 info = self.getServiceInterface("info")
495                 angleTuple = info and info.getInfoObject(iServiceInformation.sUser+8)
496                 print "AngleInfoAvail ", repr(angleTuple)
497                 if angleTuple:
498                         angleString = ""
499                         if angleTuple[1] > 1:
500                                 angleString = "%d / %d" % (angleTuple[0],angleTuple[1])
501                                 self["anglePix"].show()
502                         else:
503                                 self["anglePix"].hide()
504                         self["angleLabel"].setText(angleString)
505                         if angleTuple != self.last_angleTuple and not self.in_menu:
506                                 self.doShow()
507                 self.last_angleTuple = angleTuple
508
509         def __chapterUpdated(self):
510                 info = self.getServiceInterface("info")
511                 if info:
512                         self.currentChapter = info.getInfo(iServiceInformation.sCurrentChapter)
513                         self.totalChapters = info.getInfo(iServiceInformation.sTotalChapters)
514                         self.setChapterLabel()
515                         print "__chapterUpdated: %d/%d" % (self.currentChapter, self.totalChapters)
516
517         def __titleUpdated(self):
518                 info = self.getServiceInterface("info")
519                 if info:
520                         self.currentTitle = info.getInfo(iServiceInformation.sCurrentTitle)
521                         self.totalTitles = info.getInfo(iServiceInformation.sTotalTitles)
522                         self.setChapterLabel()
523                         print "__titleUpdated: %d/%d" % (self.currentTitle, self.totalTitles)
524                         if not self.in_menu:
525                                 self.doShow()
526                 
527         def askLeavePlayer(self):
528                 choices = [(_("Exit"), "exit"), (_("Continue playing"), "play")]
529                 if True or not self.physicalDVD:
530                         choices.insert(1,(_("Return to file browser"), "browser"))
531                 if self.physicalDVD:
532                         cur = self.session.nav.getCurrentlyPlayingServiceReference()
533                         if cur and not cur.toString().endswith(harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD())):
534                             choices.insert(0,(_("Play DVD"), "playPhysical" ))
535                 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list = choices)
536
537         def sendKey(self, key):
538                 keys = self.getServiceInterface("keys")
539                 if keys:
540                         keys.keyPressed(key)
541                 return keys
542
543         def nextAudioTrack(self):
544                 self.sendKey(iServiceKeys.keyUser)
545
546         def nextSubtitleTrack(self):
547                 self.sendKey(iServiceKeys.keyUser+1)
548
549         def enterDVDAudioMenu(self):
550                 self.sendKey(iServiceKeys.keyUser+2)
551
552         def nextChapter(self):
553                 self.sendKey(iServiceKeys.keyUser+3)
554
555         def prevChapter(self):
556                 self.sendKey(iServiceKeys.keyUser+4)
557
558         def nextTitle(self):
559                 self.sendKey(iServiceKeys.keyUser+5)
560
561         def prevTitle(self):
562                 self.sendKey(iServiceKeys.keyUser+6)
563
564         def enterDVDMenu(self):
565                 self.sendKey(iServiceKeys.keyUser+7)
566         
567         def nextAngle(self):
568                 self.sendKey(iServiceKeys.keyUser+8)
569
570         def seekBeginning(self):
571                 if self.service:
572                         seekable = self.getSeek()
573                         if seekable:
574                                 seekable.seekTo(0)
575
576         def zapToNumber(self, number):
577                 if self.service:
578                         seekable = self.getSeek()
579                         if seekable:
580                                 print "seek to chapter %d" % number
581                                 seekable.seekChapter(number)
582
583 #       MENU ACTIONS
584         def keyRight(self):
585                 self.sendKey(iServiceKeys.keyRight)
586
587         def keyLeft(self):
588                 self.sendKey(iServiceKeys.keyLeft)
589
590         def keyUp(self):
591                 self.sendKey(iServiceKeys.keyUp)
592
593         def keyDown(self):
594                 self.sendKey(iServiceKeys.keyDown)
595
596         def keyOk(self):
597                 if self.sendKey(iServiceKeys.keyOk) and not self.in_menu:
598                         self.toggleInfo()
599
600         def keyCancel(self):
601                 self.askLeavePlayer()
602
603         def opened(self):
604                 if self.autoplay and self.dvd_filelist:
605                         # opened via autoplay
606                         self.FileBrowserClosed(self.dvd_filelist[0])
607                 elif self.autoplay and self.physicalDVD:
608                         self.playPhysicalCB(True)
609                 elif self.physicalDVD:
610                         # opened from menu with dvd in drive
611                         self.session.openWithCallback(self.playPhysicalCB, MessageBox, text=_("Do you want to play DVD in drive?"), timeout=5 )
612                 else:
613                         # opened from menu without dvd in drive
614                         self.session.openWithCallback(self.FileBrowserClosed, FileBrowser, self.dvd_filelist)
615
616         def playPhysicalCB(self, answer):
617                 if answer == True:
618                         self.FileBrowserClosed(harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD()))
619                 else:
620                         self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
621
622         def FileBrowserClosed(self, val):
623                 curref = self.session.nav.getCurrentlyPlayingServiceReference()
624                 print "FileBrowserClosed", val
625                 if val is None:
626                         self.askLeavePlayer()
627                 else:
628                         newref = eServiceReference(4369, 0, val)
629                         print "play", newref.toString()
630                         if curref is None or curref != newref:
631                                 if newref.toString().endswith("/VIDEO_TS") or newref.toString().endswith("/"):
632                                         names = newref.toString().rsplit("/",3)
633                                         if names[2].startswith("Disk ") or names[2].startswith("DVD "):
634                                                 name = str(names[1]) + " - " + str(names[2])
635                                         else:
636                                                 name = names[2]
637                                         print "setting name to: ", self.service
638                                         newref.setName(str(name))
639                                 self.session.nav.playService(newref)
640                                 self.service = self.session.nav.getCurrentService()
641                                 print "self.service", self.service
642                                 print "cur_dlg", self.session.current_dialog
643                                 subs = self.getServiceInterface("subtitle")
644                                 if subs:
645                                         subs.enableSubtitles(self.dvdScreen.instance, None)
646
647         def exitCB(self, answer):
648                 if answer is not None:
649                         if answer[1] == "exit":
650                                 if self.service:
651                                         self.service = None
652                                 self.close()
653                         if answer[1] == "browser":
654                                 #TODO check here if a paused dvd playback is already running... then re-start it...
655                                 #else
656                                 if self.service:
657                                         self.service = None
658                                 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
659                         if answer[1] == "playPhysical":
660                                 if self.service:
661                                         self.service = None
662                                 self.playPhysicalCB(True)
663                         else:
664                                 pass
665
666         def __onClose(self):
667                 self.restore_infobar_seek_config()
668                 self.session.nav.playService(self.oldService)
669                 from Plugins.SystemPlugins.Hotplug.plugin import hotplugNotifier
670                 hotplugNotifier.remove(self.hotplugCB)
671
672         def playLastCB(self, answer): # overwrite infobar cuesheet function
673                 print "playLastCB", answer, self.resume_point
674                 if self.service:
675                         if answer == True:
676                                 seekable = self.getSeek()
677                                 if seekable:
678                                         seekable.seekTo(self.resume_point)
679                         pause = self.service.pause()
680                         pause.unpause()
681                 self.hideAfterResume()
682
683         def showAfterCuesheetOperation(self):
684                 if not self.in_menu:
685                         self.show()
686
687         def createSummary(self):
688                 return DVDSummary
689
690 #override some InfoBarSeek functions
691         def doEof(self):
692                 self.setSeekState(self.SEEK_STATE_PLAY)
693
694         def calcRemainingTime(self):
695                 return 0
696
697         def hotplugCB(self, dev, media_state):
698                 print "[hotplugCB]", dev, media_state
699                 if dev == harddiskmanager.getCD():
700                         if media_state == "1":
701                                 self.scanHotplug()
702                         else:
703                                 self.physicalDVD = False
704
705         def scanHotplug(self):
706                 devicepath = harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD())
707                 if pathExists(devicepath):
708                         from Components.Scanner import scanDevice
709                         res = scanDevice(devicepath)
710                         list = [ (r.description, r, res[r], self.session) for r in res ]
711                         if list:
712                                 (desc, scanner, files, session) = list[0]
713                                 for file in files:
714                                         print file
715                                         if file.mimetype == "video/x-dvd":
716                                                 print "physical dvd found:", devicepath
717                                                 self.physicalDVD = True
718                                                 return
719                 self.physicalDVD = False
720
721 def main(session, **kwargs):
722         session.open(DVDPlayer)
723
724 def menu(menuid, **kwargs):
725         if menuid == "mainmenu":
726                 return [(_("DVD Player"), main, "dvd_player", 46)]
727         return []
728
729 from Plugins.Plugin import PluginDescriptor
730
731 def filescan_open(list, session, **kwargs):
732         if len(list) == 1 and list[0].mimetype == "video/x-dvd":
733                 splitted = list[0].path.split('/')
734                 print "splitted", splitted
735                 if len(splitted) > 2:
736                         if splitted[1] == 'autofs':
737                                 session.open(DVDPlayer, dvd_device="/dev/%s" %(splitted[2]))
738                                 return
739                         else:
740                                 print "splitted[0]", splitted[1]
741         else:
742                 dvd_filelist = []
743                 for x in list:
744                         if x.mimetype == "video/x-dvd-iso":
745                                 dvd_filelist.append(x.path)
746                         if x.mimetype == "video/x-dvd":
747                                 dvd_filelist.append(x.path.rsplit('/',1)[0])                    
748                 session.open(DVDPlayer, dvd_filelist=dvd_filelist)
749
750 def filescan(**kwargs):
751         from Components.Scanner import Scanner, ScanPath
752
753         # Overwrite checkFile to only detect local
754         class LocalScanner(Scanner):
755                 def checkFile(self, file):
756                         return fileExists(file.path)
757
758         return [
759                 LocalScanner(mimetypes = ["video/x-dvd","video/x-dvd-iso"],
760                         paths_to_scan =
761                                 [
762                                         ScanPath(path = "video_ts", with_subdirs = False),
763                                         ScanPath(path = "VIDEO_TS", with_subdirs = False),
764                                         ScanPath(path = "", with_subdirs = False),
765                                 ],
766                         name = "DVD",
767                         description = _("Play DVD"),
768                         openfnc = filescan_open,
769                 )]              
770
771 def Plugins(**kwargs):
772         return [PluginDescriptor(name = "DVDPlayer", description = "Play DVDs", where = PluginDescriptor.WHERE_MENU, fnc = menu),
773                         PluginDescriptor(where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)]