32e359332a48da00e6c68cbc66b0218e3c9258e5
[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.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:
506                         cur = self.session.nav.getCurrentlyPlayingServiceReference()
507                         if cur and not cur.toString().endswith(harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD())):
508                             choices.insert(0,(_("Play DVD"), "playPhysical" ))
509                 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list = choices)
510
511         def sendKey(self, key):
512                 keys = self.getServiceInterface("keys")
513                 if keys:
514                         keys.keyPressed(key)
515                 return keys
516
517         def nextAudioTrack(self):
518                 self.sendKey(iServiceKeys.keyUser)
519
520         def nextSubtitleTrack(self):
521                 self.sendKey(iServiceKeys.keyUser+1)
522
523         def enterDVDAudioMenu(self):
524                 self.sendKey(iServiceKeys.keyUser+2)
525
526         def nextChapter(self):
527                 self.sendKey(iServiceKeys.keyUser+3)
528
529         def prevChapter(self):
530                 self.sendKey(iServiceKeys.keyUser+4)
531
532         def nextTitle(self):
533                 self.sendKey(iServiceKeys.keyUser+5)
534
535         def prevTitle(self):
536                 self.sendKey(iServiceKeys.keyUser+6)
537
538         def enterDVDMenu(self):
539                 self.sendKey(iServiceKeys.keyUser+7)
540         
541         def nextAngle(self):
542                 self.sendKey(iServiceKeys.keyUser+8)
543
544         def seekBeginning(self):
545                 if self.service:
546                         seekable = self.getSeek()
547                         if seekable:
548                                 seekable.seekTo(0)
549
550         def zapToNumber(self, number):
551                 if self.service:
552                         seekable = self.getSeek()
553                         if seekable:
554                                 print "seek to chapter %d" % number
555                                 seekable.seekChapter(number)
556
557 #       MENU ACTIONS
558         def keyRight(self):
559                 self.sendKey(iServiceKeys.keyRight)
560
561         def keyLeft(self):
562                 self.sendKey(iServiceKeys.keyLeft)
563
564         def keyUp(self):
565                 self.sendKey(iServiceKeys.keyUp)
566
567         def keyDown(self):
568                 self.sendKey(iServiceKeys.keyDown)
569
570         def keyOk(self):
571                 if self.sendKey(iServiceKeys.keyOk) and not self.in_menu:
572                         self.toggleInfo()
573
574         def keyCancel(self):
575                 self.askLeavePlayer()
576
577         def opened(self):
578                 if len(self.dvd_filelist) == 1:
579                         # opened via autoplay
580                         self.FileBrowserClosed(self.dvd_filelist[0])
581                 elif self.physicalDVD:
582                         # opened from menu with dvd in drive
583                         self.session.openWithCallback(self.playPhysicalCB, MessageBox, text=_("Do you want to play DVD in drive?"), timeout=5 )
584                 else:
585                         # opened from menu without dvd in drive
586                         self.session.openWithCallback(self.FileBrowserClosed, FileBrowser, self.dvd_filelist)
587
588         def playPhysicalCB(self, answer):
589                 if answer == True:
590                         self.FileBrowserClosed(harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD()))
591                 else:
592                         self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
593
594         def FileBrowserClosed(self, val):
595                 curref = self.session.nav.getCurrentlyPlayingServiceReference()
596                 print "FileBrowserClosed", val
597                 if val is None:
598                         self.askLeavePlayer()
599                 else:
600                         newref = eServiceReference(4369, 0, val)
601                         print "play", newref.toString()
602                         if curref is None or curref != newref:
603                                 self.session.nav.playService(newref)
604                                 self.service = self.session.nav.getCurrentService()
605                                 print "self.service", self.service
606                                 print "cur_dlg", self.session.current_dialog
607                                 subs = self.getServiceInterface("subtitle")
608                                 if subs:
609                                         subs.enableSubtitles(self.dvdScreen.instance, None)
610
611         def exitCB(self, answer):
612                 if answer is not None:
613                         if answer[1] == "exit":
614                                 if self.service:
615                                         self.service = None
616                                 self.close()
617                         if answer[1] == "browser":
618                                 #TODO check here if a paused dvd playback is already running... then re-start it...
619                                 #else
620                                 if self.service:
621                                         self.service = None
622                                 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
623                         if answer[1] == "playPhysical":
624                                 if self.service:
625                                         self.service = None
626                                 self.playPhysicalCB(True)
627                         else:
628                                 pass
629
630         def __onClose(self):
631                 self.restore_infobar_seek_config()
632                 self.session.nav.playService(self.oldService)
633                 from Plugins.SystemPlugins.Hotplug.plugin import hotplugNotifier
634                 hotplugNotifier.remove(self.hotplugCB)
635
636         def playLastCB(self, answer): # overwrite infobar cuesheet function
637                 print "playLastCB", answer, self.resume_point
638                 if self.service:
639                         if answer == True:
640                                 seekable = self.getSeek()
641                                 if seekable:
642                                         seekable.seekTo(self.resume_point)
643                         pause = self.service.pause()
644                         pause.unpause()
645                 self.hideAfterResume()
646
647         def showAfterCuesheetOperation(self):
648                 if not self.in_menu:
649                         self.show()
650
651         def createSummary(self):
652                 return DVDSummary
653
654 #override some InfoBarSeek functions
655         def doEof(self):
656                 self.setSeekState(self.SEEK_STATE_PLAY)
657
658         def calcRemainingTime(self):
659                 return 0
660
661         def hotplugCB(self, dev, media_state):
662                 print "[hotplugCB]", dev, media_state
663                 if dev == harddiskmanager.getCD():
664                         if media_state == "1":
665                                 self.scanHotplug()
666                         else:
667                                 self.physicalDVD = False
668
669         def scanHotplug(self):
670                 devicepath = harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD())
671                 if pathExists(devicepath):
672                         from Components.Scanner import scanDevice
673                         res = scanDevice(devicepath)
674                         list = [ (r.description, r, res[r], self.session) for r in res ]
675                         if list:
676                                 (desc, scanner, files, session) = list[0]
677                                 for file in files:
678                                         print file
679                                         if file.mimetype == "video/x-dvd":
680                                                 print "physical dvd found:", devicepath
681                                                 self.physicalDVD = True
682                                                 return
683                 self.physicalDVD = False
684
685 def main(session, **kwargs):
686         session.open(DVDPlayer)
687
688 def menu(menuid, **kwargs):
689         if menuid == "mainmenu":
690                 return [(_("DVD Player"), main, "dvd_player", 46)]
691         return []
692
693 from Plugins.Plugin import PluginDescriptor
694
695 def filescan_open(list, session, **kwargs):
696         if len(list) == 1 and list[0].mimetype == "video/x-dvd":
697                 splitted = list[0].path.split('/')
698                 print "splitted", splitted
699                 if len(splitted) > 2:
700                         if splitted[1] == 'autofs':
701                                 session.open(DVDPlayer, dvd_device="/dev/%s" %(splitted[2]))
702                                 return
703                         else:
704                                 print "splitted[0]", splitted[1]
705         else:
706                 dvd_filelist = []
707                 for x in list:
708                         if x.mimetype == "video/x-dvd-iso":
709                                 dvd_filelist.append(x.path)
710                         if x.mimetype == "video/x-dvd":
711                                 dvd_filelist.append(x.path.rsplit('/',1)[0])                    
712                 session.open(DVDPlayer, dvd_filelist=dvd_filelist)
713
714 def filescan(**kwargs):
715         from Components.Scanner import Scanner, ScanPath
716
717         # Overwrite checkFile to only detect local
718         class LocalScanner(Scanner):
719                 def checkFile(self, file):
720                         return fileExists(file.path)
721
722         return [
723                 LocalScanner(mimetypes = ["video/x-dvd","video/x-dvd-iso"],
724                         paths_to_scan =
725                                 [
726                                         ScanPath(path = "video_ts", with_subdirs = False),
727                                         ScanPath(path = "", with_subdirs = False),
728                                 ],
729                         name = "DVD",
730                         description = _("Play DVD"),
731                         openfnc = filescan_open,
732                 )]              
733
734 def Plugins(**kwargs):
735         return [PluginDescriptor(name = "DVDPlayer", description = "Play DVDs", where = PluginDescriptor.WHERE_MENU, fnc = menu),
736                         PluginDescriptor(where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)]