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