DVDPlayer: AudioSelection integration (#441)
[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, InfoBarAudioSelection, InfoBarSubtitleSupport
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, InfoBarAudioSelection, InfoBarSubtitleSupport):
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_stepwise_minspeed = config.seek.stepwise_minspeed.value
248                 self.saved_config_seek_stepwise_repeat = config.seek.stepwise_repeat.value
249                 self.saved_config_seek_on_pause = config.seek.on_pause.value
250                 self.saved_config_seek_speeds_slowmotion = config.seek.speeds_slowmotion.value
251
252         def change_infobar_seek_config(self):
253                 config.seek.speeds_forward.value = [2, 4, 8, 16, 32, 64]
254                 config.seek.speeds_backward.value = [8, 16, 32, 64]
255                 config.seek.speeds_slowmotion.value = [ ]
256                 config.seek.enter_forward.value = "2"
257                 config.seek.enter_backward.value = "2"
258                 config.seek.stepwise_minspeed.value = "Never"
259                 config.seek.stepwise_repeat.value = "3"
260                 config.seek.on_pause.value = "play"
261
262         def restore_infobar_seek_config(self):
263                 config.seek.speeds_forward.value = self.saved_config_speeds_forward
264                 config.seek.speeds_backward.value = self.saved_config_speeds_backward
265                 config.seek.speeds_slowmotion.value = self.saved_config_seek_speeds_slowmotion
266                 config.seek.enter_forward.value = self.saved_config_enter_forward
267                 config.seek.enter_backward.value = self.saved_config_enter_backward
268                 config.seek.stepwise_minspeed.value = self.saved_config_seek_stepwise_minspeed
269                 config.seek.stepwise_repeat.value = self.saved_config_seek_stepwise_repeat
270                 config.seek.on_pause.value = self.saved_config_seek_on_pause
271
272         def __init__(self, session, dvd_device = None, dvd_filelist = [ ], args = None):
273                 Screen.__init__(self, session)
274                 InfoBarBase.__init__(self)
275                 InfoBarNotifications.__init__(self)
276                 InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions")
277                 InfoBarShowHide.__init__(self)
278                 InfoBarAudioSelection.__init__(self)
279                 InfoBarSubtitleSupport.__init__(self)
280                 HelpableScreen.__init__(self)
281                 self.save_infobar_seek_config()
282                 self.change_infobar_seek_config()
283                 InfoBarSeek.__init__(self, useSeekBackHack=False)
284                 InfoBarPVRState.__init__(self)
285                 self.dvdScreen = self.session.instantiateDialog(DVDOverlay)
286
287                 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
288                 self.session.nav.stopService()
289                 self["audioLabel"] = Label("n/a")
290                 self["subtitleLabel"] = Label("")
291                 self["angleLabel"] = Label("")
292                 self["chapterLabel"] = Label("")
293                 self["anglePix"] = Pixmap()
294                 self["anglePix"].hide()
295                 self.last_audioTuple = None
296                 self.last_subtitleTuple = None
297                 self.last_angleTuple = None
298                 self.totalChapters = 0
299                 self.currentChapter = 0
300                 self.totalTitles = 0
301                 self.currentTitle = 0
302
303                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
304                         {
305                                 iPlayableService.evStopped: self.__serviceStopped,
306                                 iPlayableService.evUser: self.__timeUpdated,
307                                 iPlayableService.evUser+1: self.__statePlay,
308                                 iPlayableService.evUser+2: self.__statePause,
309                                 iPlayableService.evUser+3: self.__osdFFwdInfoAvail,
310                                 iPlayableService.evUser+4: self.__osdFBwdInfoAvail,
311                                 iPlayableService.evUser+5: self.__osdStringAvail,
312                                 iPlayableService.evUser+6: self.__osdAudioInfoAvail,
313                                 iPlayableService.evUser+7: self.__osdSubtitleInfoAvail,
314                                 iPlayableService.evUser+8: self.__chapterUpdated,
315                                 iPlayableService.evUser+9: self.__titleUpdated,
316                                 iPlayableService.evUser+11: self.__menuOpened,
317                                 iPlayableService.evUser+12: self.__menuClosed,
318                                 iPlayableService.evUser+13: self.__osdAngleInfoAvail
319                         })
320
321                 self["DVDPlayerDirectionActions"] = ActionMap(["DirectionActions"],
322                         {
323                                 #MENU KEY DOWN ACTIONS
324                                 "left": self.keyLeft,
325                                 "right": self.keyRight,
326                                 "up": self.keyUp,
327                                 "down": self.keyDown,
328
329                                 #MENU KEY REPEATED ACTIONS
330                                 "leftRepeated": self.doNothing,
331                                 "rightRepeated": self.doNothing,
332                                 "upRepeated": self.doNothing,
333                                 "downRepeated": self.doNothing,
334
335                                 #MENU KEY UP ACTIONS
336                                 "leftUp": self.doNothing,
337                                 "rightUp": self.doNothing,
338                                 "upUp": self.doNothing,
339                                 "downUp": self.doNothing,
340                         })
341
342                 self["OkCancelActions"] = ActionMap(["OkCancelActions"],
343                         {
344                                 "ok": self.keyOk,
345                                 "cancel": self.keyCancel,
346                         })
347
348                 self["DVDPlayerPlaybackActions"] = HelpableActionMap(self, "DVDPlayerActions",
349                         {
350                                 #PLAYER ACTIONS
351                                 "dvdMenu": (self.enterDVDMenu, _("show DVD main menu")),
352                                 "toggleInfo": (self.toggleInfo, _("toggle time, chapter, audio, subtitle info")),
353                                 "nextChapter": (self.nextChapter, _("forward to the next chapter")),
354                                 "prevChapter": (self.prevChapter, _("rewind to the previous chapter")),
355                                 "nextTitle": (self.nextTitle, _("jump forward to the next title")),
356                                 "prevTitle": (self.prevTitle, _("jump back to the previous title")),
357                                 "tv": (self.askLeavePlayer, _("exit DVD player or return to file browser")),
358                                 "dvdAudioMenu": (self.enterDVDAudioMenu, _("(show optional DVD audio menu)")),
359                                 "AudioSelection": (self.enterAudioSelection, _("Select audio track")),
360                                 "nextAudioTrack": (self.nextAudioTrack, _("switch to the next audio track")),
361                                 "nextSubtitleTrack": (self.nextSubtitleTrack, _("switch to the next subtitle language")),
362                                 "nextAngle": (self.nextAngle, _("switch to the next angle")),
363                                 "seekBeginning": self.seekBeginning,
364                         }, -2)
365                         
366                 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
367                         {
368                                 "1": self.keyNumberGlobal,
369                                 "2": self.keyNumberGlobal,
370                                 "3": self.keyNumberGlobal,
371                                 "4": self.keyNumberGlobal,
372                                 "5": self.keyNumberGlobal,
373                                 "6": self.keyNumberGlobal,
374                                 "7": self.keyNumberGlobal,
375                                 "8": self.keyNumberGlobal,
376                                 "9": self.keyNumberGlobal,
377                                 "0": self.keyNumberGlobal,
378                         })
379
380                 self.onClose.append(self.__onClose)
381
382                 from Plugins.SystemPlugins.Hotplug.plugin import hotplugNotifier
383                 hotplugNotifier.append(self.hotplugCB)
384                 
385                 self.autoplay = dvd_device or dvd_filelist
386
387                 if dvd_device:
388                         self.physicalDVD = True
389                 else:
390                         self.scanHotplug()
391
392                 self.dvd_filelist = dvd_filelist
393                 self.onFirstExecBegin.append(self.opened)
394                 self.service = None
395                 self.in_menu = False
396
397         def keyNumberGlobal(self, number):
398                 print "You pressed number " + str(number)
399                 self.session.openWithCallback(self.numberEntered, ChapterZap, number)
400
401         def numberEntered(self, retval):
402 #               print self.servicelist
403                 if retval > 0:
404                         self.zapToNumber(retval)
405
406         def getServiceInterface(self, iface):
407                 service = self.service
408                 if service:
409                         attr = getattr(service, iface, None)
410                         if callable(attr):
411                                 return attr()
412                 return None
413
414         def __serviceStopped(self):
415                 self.dvdScreen.hide()
416                 subs = self.getServiceInterface("subtitle")
417                 if subs:
418                         subs.disableSubtitles(self.session.current_dialog.instance)
419
420         def serviceStarted(self): #override InfoBarShowHide function
421                 self.dvdScreen.show()
422
423         def doEofInternal(self, playing):
424                 if self.in_menu:
425                         self.hide()
426
427         def __menuOpened(self):
428                 self.hide()
429                 self.in_menu = True
430                 self["NumberActions"].setEnabled(False)
431
432         def __menuClosed(self):
433                 self.show()
434                 self.in_menu = False
435                 self["NumberActions"].setEnabled(True)
436
437         def setChapterLabel(self):
438                 chapterLCD = "Menu"
439                 chapterOSD = "DVD Menu"
440                 if self.currentTitle > 0:
441                         chapterLCD = "%s %d" % (_("Chap."), self.currentChapter)
442                         chapterOSD = "DVD %s %d/%d" % (_("Chapter"), self.currentChapter, self.totalChapters)
443                         chapterOSD += " (%s %d/%d)" % (_("Title"), self.currentTitle, self.totalTitles)
444                 self["chapterLabel"].setText(chapterOSD)
445                 try:
446                         self.session.summary.updateChapter(chapterLCD)
447                 except:
448                         pass
449
450         def doNothing(self):
451                 pass
452
453         def toggleInfo(self):
454                 if not self.in_menu:
455                         self.toggleShow()
456                         print "toggleInfo"
457
458         def __timeUpdated(self):
459                 print "timeUpdated"
460
461         def __statePlay(self):
462                 print "statePlay"
463
464         def __statePause(self):
465                 print "statePause"
466
467         def __osdFFwdInfoAvail(self):
468                 self.setChapterLabel()
469                 print "FFwdInfoAvail"
470
471         def __osdFBwdInfoAvail(self):
472                 self.setChapterLabel()
473                 print "FBwdInfoAvail"
474
475         def __osdStringAvail(self):
476                 print "StringAvail"
477
478         def __osdAudioInfoAvail(self):
479                 info = self.getServiceInterface("info")
480                 audioTuple = info and info.getInfoObject(iServiceInformation.sUser+6)
481                 print "AudioInfoAvail ", repr(audioTuple)
482                 if audioTuple:
483                         audioString = "%d: %s (%s)" % (audioTuple[0],audioTuple[1],audioTuple[2])
484                         self["audioLabel"].setText(audioString)
485                         if audioTuple != self.last_audioTuple and not self.in_menu:
486                                 self.doShow()
487                 self.last_audioTuple = audioTuple
488
489         def __osdSubtitleInfoAvail(self):
490                 info = self.getServiceInterface("info")
491                 subtitleTuple = info and info.getInfoObject(iServiceInformation.sUser+7)
492                 print "SubtitleInfoAvail ", repr(subtitleTuple)
493                 if subtitleTuple:
494                         subtitleString = ""
495                         if subtitleTuple[0] is not 0:
496                                 subtitleString = "%d: %s" % (subtitleTuple[0],subtitleTuple[1])
497                         self["subtitleLabel"].setText(subtitleString)
498                         if subtitleTuple != self.last_subtitleTuple and not self.in_menu:
499                                 self.doShow()
500                 self.last_subtitleTuple = subtitleTuple
501         
502         def __osdAngleInfoAvail(self):
503                 info = self.getServiceInterface("info")
504                 angleTuple = info and info.getInfoObject(iServiceInformation.sUser+8)
505                 print "AngleInfoAvail ", repr(angleTuple)
506                 if angleTuple:
507                         angleString = ""
508                         if angleTuple[1] > 1:
509                                 angleString = "%d / %d" % (angleTuple[0],angleTuple[1])
510                                 self["anglePix"].show()
511                         else:
512                                 self["anglePix"].hide()
513                         self["angleLabel"].setText(angleString)
514                         if angleTuple != self.last_angleTuple and not self.in_menu:
515                                 self.doShow()
516                 self.last_angleTuple = angleTuple
517
518         def __chapterUpdated(self):
519                 info = self.getServiceInterface("info")
520                 if info:
521                         self.currentChapter = info.getInfo(iServiceInformation.sCurrentChapter)
522                         self.totalChapters = info.getInfo(iServiceInformation.sTotalChapters)
523                         self.setChapterLabel()
524                         print "__chapterUpdated: %d/%d" % (self.currentChapter, self.totalChapters)
525
526         def __titleUpdated(self):
527                 info = self.getServiceInterface("info")
528                 if info:
529                         self.currentTitle = info.getInfo(iServiceInformation.sCurrentTitle)
530                         self.totalTitles = info.getInfo(iServiceInformation.sTotalTitles)
531                         self.setChapterLabel()
532                         print "__titleUpdated: %d/%d" % (self.currentTitle, self.totalTitles)
533                         if not self.in_menu:
534                                 self.doShow()
535                 
536         def askLeavePlayer(self):
537                 choices = [(_("Exit"), "exit"), (_("Continue playing"), "play")]
538                 if True or not self.physicalDVD:
539                         choices.insert(1,(_("Return to file browser"), "browser"))
540                 if self.physicalDVD:
541                         cur = self.session.nav.getCurrentlyPlayingServiceReference()
542                         if cur and not cur.toString().endswith(harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD())):
543                             choices.insert(0,(_("Play DVD"), "playPhysical" ))
544                 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list = choices)
545
546         def sendKey(self, key):
547                 keys = self.getServiceInterface("keys")
548                 if keys:
549                         keys.keyPressed(key)
550                 return keys
551
552         def enterAudioSelection(self):
553                 self.audioSelection()
554
555         def nextAudioTrack(self):
556                 self.sendKey(iServiceKeys.keyUser)
557
558         def nextSubtitleTrack(self):
559                 self.sendKey(iServiceKeys.keyUser+1)
560
561         def enterDVDAudioMenu(self):
562                 self.sendKey(iServiceKeys.keyUser+2)
563
564         def nextChapter(self):
565                 self.sendKey(iServiceKeys.keyUser+3)
566
567         def prevChapter(self):
568                 self.sendKey(iServiceKeys.keyUser+4)
569
570         def nextTitle(self):
571                 self.sendKey(iServiceKeys.keyUser+5)
572
573         def prevTitle(self):
574                 self.sendKey(iServiceKeys.keyUser+6)
575
576         def enterDVDMenu(self):
577                 self.sendKey(iServiceKeys.keyUser+7)
578         
579         def nextAngle(self):
580                 self.sendKey(iServiceKeys.keyUser+8)
581
582         def seekBeginning(self):
583                 if self.service:
584                         seekable = self.getSeek()
585                         if seekable:
586                                 seekable.seekTo(0)
587
588         def zapToNumber(self, number):
589                 if self.service:
590                         seekable = self.getSeek()
591                         if seekable:
592                                 print "seek to chapter %d" % number
593                                 seekable.seekChapter(number)
594
595 #       MENU ACTIONS
596         def keyRight(self):
597                 self.sendKey(iServiceKeys.keyRight)
598
599         def keyLeft(self):
600                 self.sendKey(iServiceKeys.keyLeft)
601
602         def keyUp(self):
603                 self.sendKey(iServiceKeys.keyUp)
604
605         def keyDown(self):
606                 self.sendKey(iServiceKeys.keyDown)
607
608         def keyOk(self):
609                 if self.sendKey(iServiceKeys.keyOk) and not self.in_menu:
610                         self.toggleInfo()
611
612         def keyCancel(self):
613                 self.askLeavePlayer()
614
615         def opened(self):
616                 if self.autoplay and self.dvd_filelist:
617                         # opened via autoplay
618                         self.FileBrowserClosed(self.dvd_filelist[0])
619                 elif self.autoplay and self.physicalDVD:
620                         self.playPhysicalCB(True)
621                 elif self.physicalDVD:
622                         # opened from menu with dvd in drive
623                         self.session.openWithCallback(self.playPhysicalCB, MessageBox, text=_("Do you want to play DVD in drive?"), timeout=5 )
624                 else:
625                         # opened from menu without dvd in drive
626                         self.session.openWithCallback(self.FileBrowserClosed, FileBrowser, self.dvd_filelist)
627
628         def playPhysicalCB(self, answer):
629                 if answer == True:
630                         self.FileBrowserClosed(harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD()))
631                 else:
632                         self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
633
634         def FileBrowserClosed(self, val):
635                 curref = self.session.nav.getCurrentlyPlayingServiceReference()
636                 print "FileBrowserClosed", val
637                 if val is None:
638                         self.askLeavePlayer()
639                 else:
640                         newref = eServiceReference(4369, 0, val)
641                         print "play", newref.toString()
642                         if curref is None or curref != newref:
643                                 if newref.toString().endswith("/VIDEO_TS") or newref.toString().endswith("/"):
644                                         names = newref.toString().rsplit("/",3)
645                                         if names[2].startswith("Disk ") or names[2].startswith("DVD "):
646                                                 name = str(names[1]) + " - " + str(names[2])
647                                         else:
648                                                 name = names[2]
649                                         print "setting name to: ", self.service
650                                         newref.setName(str(name))
651                                 self.session.nav.playService(newref)
652                                 self.service = self.session.nav.getCurrentService()
653                                 print "self.service", self.service
654                                 print "cur_dlg", self.session.current_dialog
655                                 subs = self.getServiceInterface("subtitle")
656                                 if subs:
657                                         subs.enableSubtitles(self.dvdScreen.instance, None)
658
659         def exitCB(self, answer):
660                 if answer is not None:
661                         if answer[1] == "exit":
662                                 if self.service:
663                                         self.service = None
664                                 self.close()
665                         if answer[1] == "browser":
666                                 #TODO check here if a paused dvd playback is already running... then re-start it...
667                                 #else
668                                 if self.service:
669                                         self.service = None
670                                 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
671                         if answer[1] == "playPhysical":
672                                 if self.service:
673                                         self.service = None
674                                 self.playPhysicalCB(True)
675                         else:
676                                 pass
677
678         def __onClose(self):
679                 self.restore_infobar_seek_config()
680                 self.session.nav.playService(self.oldService)
681                 from Plugins.SystemPlugins.Hotplug.plugin import hotplugNotifier
682                 hotplugNotifier.remove(self.hotplugCB)
683
684         def playLastCB(self, answer): # overwrite infobar cuesheet function
685                 print "playLastCB", answer, self.resume_point
686                 if self.service:
687                         if answer == True:
688                                 seekable = self.getSeek()
689                                 if seekable:
690                                         seekable.seekTo(self.resume_point)
691                         pause = self.service.pause()
692                         pause.unpause()
693                 self.hideAfterResume()
694
695         def showAfterCuesheetOperation(self):
696                 if not self.in_menu:
697                         self.show()
698
699         def createSummary(self):
700                 return DVDSummary
701
702 #override some InfoBarSeek functions
703         def doEof(self):
704                 self.setSeekState(self.SEEK_STATE_PLAY)
705
706         def calcRemainingTime(self):
707                 return 0
708
709         def hotplugCB(self, dev, media_state):
710                 print "[hotplugCB]", dev, media_state
711                 if dev == harddiskmanager.getCD():
712                         if media_state == "1":
713                                 self.scanHotplug()
714                         else:
715                                 self.physicalDVD = False
716
717         def scanHotplug(self):
718                 devicepath = harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD())
719                 if pathExists(devicepath):
720                         from Components.Scanner import scanDevice
721                         res = scanDevice(devicepath)
722                         list = [ (r.description, r, res[r], self.session) for r in res ]
723                         if list:
724                                 (desc, scanner, files, session) = list[0]
725                                 for file in files:
726                                         print file
727                                         if file.mimetype == "video/x-dvd":
728                                                 print "physical dvd found:", devicepath
729                                                 self.physicalDVD = True
730                                                 return
731                 self.physicalDVD = False
732
733 def main(session, **kwargs):
734         session.open(DVDPlayer)
735
736 def menu(menuid, **kwargs):
737         if menuid == "mainmenu":
738                 return [(_("DVD Player"), main, "dvd_player", 46)]
739         return []
740
741 from Plugins.Plugin import PluginDescriptor
742
743 def filescan_open(list, session, **kwargs):
744         if len(list) == 1 and list[0].mimetype == "video/x-dvd":
745                 splitted = list[0].path.split('/')
746                 print "splitted", splitted
747                 if len(splitted) > 2:
748                         if splitted[1] == 'autofs':
749                                 session.open(DVDPlayer, dvd_device="/dev/%s" %(splitted[2]))
750                                 return
751                         else:
752                                 print "splitted[0]", splitted[1]
753         else:
754                 dvd_filelist = []
755                 for x in list:
756                         if x.mimetype == "video/x-dvd-iso":
757                                 dvd_filelist.append(x.path)
758                         if x.mimetype == "video/x-dvd":
759                                 dvd_filelist.append(x.path.rsplit('/',1)[0])                    
760                 session.open(DVDPlayer, dvd_filelist=dvd_filelist)
761
762 def filescan(**kwargs):
763         from Components.Scanner import Scanner, ScanPath
764
765         # Overwrite checkFile to only detect local
766         class LocalScanner(Scanner):
767                 def checkFile(self, file):
768                         return fileExists(file.path)
769
770         return [
771                 LocalScanner(mimetypes = ["video/x-dvd","video/x-dvd-iso"],
772                         paths_to_scan =
773                                 [
774                                         ScanPath(path = "video_ts", with_subdirs = False),
775                                         ScanPath(path = "VIDEO_TS", with_subdirs = False),
776                                         ScanPath(path = "", with_subdirs = False),
777                                 ],
778                         name = "DVD",
779                         description = _("Play DVD"),
780                         openfnc = filescan_open,
781                 )]              
782
783 def Plugins(**kwargs):
784         return [PluginDescriptor(name = "DVDPlayer", description = "Play DVDs", where = PluginDescriptor.WHERE_MENU, fnc = menu),
785                         PluginDescriptor(where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)]