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