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