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