ce5fa9d262cd8f5687fe1db67d8bae31f12387d6
[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 = Screen.SUSPEND_PAUSES
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                 self.autoplay = dvd_device or dvd_filelist
353
354                 if dvd_device:
355                         self.physicalDVD = True
356                 else:
357                         self.scanHotplug()
358
359                 self.dvd_filelist = dvd_filelist
360                 self.onFirstExecBegin.append(self.opened)
361                 self.service = None
362                 self.in_menu = False
363
364         def keyNumberGlobal(self, number):
365                 print "You pressed number " + str(number)
366                 self.session.openWithCallback(self.numberEntered, ChapterZap, number)
367
368         def numberEntered(self, retval):
369 #               print self.servicelist
370                 if retval > 0:
371                         self.zapToNumber(retval)
372
373         def getServiceInterface(self, iface):
374                 service = self.service
375                 if service:
376                         attr = getattr(service, iface, None)
377                         if callable(attr):
378                                 return attr()
379                 return None
380
381         def __serviceStopped(self):
382                 self.dvdScreen.hide()
383                 subs = self.getServiceInterface("subtitle")
384                 if subs:
385                         subs.disableSubtitles(self.session.current_dialog.instance)
386
387         def serviceStarted(self): #override InfoBarShowHide function
388                 self.dvdScreen.show()
389
390         def doEofInternal(self, playing):
391                 if self.in_menu:
392                         self.hide()
393
394         def __menuOpened(self):
395                 self.hide()
396                 self.in_menu = True
397                 self["NumberActions"].setEnabled(False)
398
399         def __menuClosed(self):
400                 self.show()
401                 self.in_menu = False
402                 self["NumberActions"].setEnabled(True)
403
404         def setChapterLabel(self):
405                 chapterLCD = "Menu"
406                 chapterOSD = "DVD Menu"
407                 if self.currentTitle > 0:
408                         chapterLCD = "%s %d" % (_("Chap."), self.currentChapter)
409                         chapterOSD = "DVD %s %d/%d" % (_("Chapter"), self.currentChapter, self.totalChapters)
410                         chapterOSD += " (%s %d/%d)" % (_("Title"), self.currentTitle, self.totalTitles)
411                 self["chapterLabel"].setText(chapterOSD)
412                 try:
413                         self.session.summary.updateChapter(chapterLCD)
414                 except:
415                         pass
416
417         def doNothing(self):
418                 pass
419
420         def toggleInfo(self):
421                 if not self.in_menu:
422                         self.toggleShow()
423                         print "toggleInfo"
424
425         def __timeUpdated(self):
426                 print "timeUpdated"
427
428         def __statePlay(self):
429                 print "statePlay"
430
431         def __statePause(self):
432                 print "statePause"
433
434         def __osdFFwdInfoAvail(self):
435                 self.setChapterLabel()
436                 print "FFwdInfoAvail"
437
438         def __osdFBwdInfoAvail(self):
439                 self.setChapterLabel()
440                 print "FBwdInfoAvail"
441
442         def __osdStringAvail(self):
443                 print "StringAvail"
444
445         def __osdAudioInfoAvail(self):
446                 info = self.getServiceInterface("info")
447                 audioTuple = info and info.getInfoObject(iServiceInformation.sUser+6)
448                 print "AudioInfoAvail ", repr(audioTuple)
449                 if audioTuple:
450                         audioString = "%d: %s (%s)" % (audioTuple[0],audioTuple[1],audioTuple[2])
451                         self["audioLabel"].setText(audioString)
452                         if audioTuple != self.last_audioTuple and not self.in_menu:
453                                 self.doShow()
454                 self.last_audioTuple = audioTuple
455
456         def __osdSubtitleInfoAvail(self):
457                 info = self.getServiceInterface("info")
458                 subtitleTuple = info and info.getInfoObject(iServiceInformation.sUser+7)
459                 print "SubtitleInfoAvail ", repr(subtitleTuple)
460                 if subtitleTuple:
461                         subtitleString = ""
462                         if subtitleTuple[0] is not 0:
463                                 subtitleString = "%d: %s" % (subtitleTuple[0],subtitleTuple[1])
464                         self["subtitleLabel"].setText(subtitleString)
465                         if subtitleTuple != self.last_subtitleTuple and not self.in_menu:
466                                 self.doShow()
467                 self.last_subtitleTuple = subtitleTuple
468         
469         def __osdAngleInfoAvail(self):
470                 info = self.getServiceInterface("info")
471                 angleTuple = info and info.getInfoObject(iServiceInformation.sUser+8)
472                 print "AngleInfoAvail ", repr(angleTuple)
473                 if angleTuple:
474                         angleString = ""
475                         if angleTuple[1] > 1:
476                                 angleString = "%d / %d" % (angleTuple[0],angleTuple[1])
477                                 self["anglePix"].show()
478                         else:
479                                 self["anglePix"].hide()
480                         self["angleLabel"].setText(angleString)
481                         if angleTuple != self.last_angleTuple and not self.in_menu:
482                                 self.doShow()
483                 self.last_angleTuple = angleTuple
484
485         def __chapterUpdated(self):
486                 info = self.getServiceInterface("info")
487                 if info:
488                         self.currentChapter = info.getInfo(iServiceInformation.sCurrentChapter)
489                         self.totalChapters = info.getInfo(iServiceInformation.sTotalChapters)
490                         self.setChapterLabel()
491                         print "__chapterUpdated: %d/%d" % (self.currentChapter, self.totalChapters)
492
493         def __titleUpdated(self):
494                 info = self.getServiceInterface("info")
495                 if info:
496                         self.currentTitle = info.getInfo(iServiceInformation.sCurrentTitle)
497                         self.totalTitles = info.getInfo(iServiceInformation.sTotalTitles)
498                         self.setChapterLabel()
499                         print "__titleUpdated: %d/%d" % (self.currentTitle, self.totalTitles)
500                         if not self.in_menu:
501                                 self.doShow()
502                 
503         def askLeavePlayer(self):
504                 choices = [(_("Exit"), "exit"), (_("Continue playing"), "play")]
505                 if True or not self.physicalDVD:
506                         choices.insert(1,(_("Return to file browser"), "browser"))
507                 if self.physicalDVD:
508                         cur = self.session.nav.getCurrentlyPlayingServiceReference()
509                         if cur and not cur.toString().endswith(harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD())):
510                             choices.insert(0,(_("Play DVD"), "playPhysical" ))
511                 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list = choices)
512
513         def sendKey(self, key):
514                 keys = self.getServiceInterface("keys")
515                 if keys:
516                         keys.keyPressed(key)
517                 return keys
518
519         def nextAudioTrack(self):
520                 self.sendKey(iServiceKeys.keyUser)
521
522         def nextSubtitleTrack(self):
523                 self.sendKey(iServiceKeys.keyUser+1)
524
525         def enterDVDAudioMenu(self):
526                 self.sendKey(iServiceKeys.keyUser+2)
527
528         def nextChapter(self):
529                 self.sendKey(iServiceKeys.keyUser+3)
530
531         def prevChapter(self):
532                 self.sendKey(iServiceKeys.keyUser+4)
533
534         def nextTitle(self):
535                 self.sendKey(iServiceKeys.keyUser+5)
536
537         def prevTitle(self):
538                 self.sendKey(iServiceKeys.keyUser+6)
539
540         def enterDVDMenu(self):
541                 self.sendKey(iServiceKeys.keyUser+7)
542         
543         def nextAngle(self):
544                 self.sendKey(iServiceKeys.keyUser+8)
545
546         def seekBeginning(self):
547                 if self.service:
548                         seekable = self.getSeek()
549                         if seekable:
550                                 seekable.seekTo(0)
551
552         def zapToNumber(self, number):
553                 if self.service:
554                         seekable = self.getSeek()
555                         if seekable:
556                                 print "seek to chapter %d" % number
557                                 seekable.seekChapter(number)
558
559 #       MENU ACTIONS
560         def keyRight(self):
561                 self.sendKey(iServiceKeys.keyRight)
562
563         def keyLeft(self):
564                 self.sendKey(iServiceKeys.keyLeft)
565
566         def keyUp(self):
567                 self.sendKey(iServiceKeys.keyUp)
568
569         def keyDown(self):
570                 self.sendKey(iServiceKeys.keyDown)
571
572         def keyOk(self):
573                 if self.sendKey(iServiceKeys.keyOk) and not self.in_menu:
574                         self.toggleInfo()
575
576         def keyCancel(self):
577                 self.askLeavePlayer()
578
579         def opened(self):
580                 if self.autoplay and self.dvd_filelist:
581                         # opened via autoplay
582                         self.FileBrowserClosed(self.dvd_filelist[0])
583                 elif self.autoplay and self.physicalDVD:
584                         self.playPhysicalCB(True)
585                 elif self.physicalDVD:
586                         # opened from menu with dvd in drive
587                         self.session.openWithCallback(self.playPhysicalCB, MessageBox, text=_("Do you want to play DVD in drive?"), timeout=5 )
588                 else:
589                         # opened from menu without dvd in drive
590                         self.session.openWithCallback(self.FileBrowserClosed, FileBrowser, self.dvd_filelist)
591
592         def playPhysicalCB(self, answer):
593                 if answer == True:
594                         self.FileBrowserClosed(harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD()))
595                 else:
596                         self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
597
598         def FileBrowserClosed(self, val):
599                 curref = self.session.nav.getCurrentlyPlayingServiceReference()
600                 print "FileBrowserClosed", val
601                 if val is None:
602                         self.askLeavePlayer()
603                 else:
604                         newref = eServiceReference(4369, 0, val)
605                         print "play", newref.toString()
606                         if curref is None or curref != newref:
607                                 self.session.nav.playService(newref)
608                                 self.service = self.session.nav.getCurrentService()
609                                 print "self.service", self.service
610                                 print "cur_dlg", self.session.current_dialog
611                                 subs = self.getServiceInterface("subtitle")
612                                 if subs:
613                                         subs.enableSubtitles(self.dvdScreen.instance, None)
614
615         def exitCB(self, answer):
616                 if answer is not None:
617                         if answer[1] == "exit":
618                                 if self.service:
619                                         self.service = None
620                                 self.close()
621                         if answer[1] == "browser":
622                                 #TODO check here if a paused dvd playback is already running... then re-start it...
623                                 #else
624                                 if self.service:
625                                         self.service = None
626                                 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
627                         if answer[1] == "playPhysical":
628                                 if self.service:
629                                         self.service = None
630                                 self.playPhysicalCB(True)
631                         else:
632                                 pass
633
634         def __onClose(self):
635                 self.restore_infobar_seek_config()
636                 self.session.nav.playService(self.oldService)
637                 from Plugins.SystemPlugins.Hotplug.plugin import hotplugNotifier
638                 hotplugNotifier.remove(self.hotplugCB)
639
640         def playLastCB(self, answer): # overwrite infobar cuesheet function
641                 print "playLastCB", answer, self.resume_point
642                 if self.service:
643                         if answer == True:
644                                 seekable = self.getSeek()
645                                 if seekable:
646                                         seekable.seekTo(self.resume_point)
647                         pause = self.service.pause()
648                         pause.unpause()
649                 self.hideAfterResume()
650
651         def showAfterCuesheetOperation(self):
652                 if not self.in_menu:
653                         self.show()
654
655         def createSummary(self):
656                 return DVDSummary
657
658 #override some InfoBarSeek functions
659         def doEof(self):
660                 self.setSeekState(self.SEEK_STATE_PLAY)
661
662         def calcRemainingTime(self):
663                 return 0
664
665         def hotplugCB(self, dev, media_state):
666                 print "[hotplugCB]", dev, media_state
667                 if dev == harddiskmanager.getCD():
668                         if media_state == "1":
669                                 self.scanHotplug()
670                         else:
671                                 self.physicalDVD = False
672
673         def scanHotplug(self):
674                 devicepath = harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD())
675                 if pathExists(devicepath):
676                         from Components.Scanner import scanDevice
677                         res = scanDevice(devicepath)
678                         list = [ (r.description, r, res[r], self.session) for r in res ]
679                         if list:
680                                 (desc, scanner, files, session) = list[0]
681                                 for file in files:
682                                         print file
683                                         if file.mimetype == "video/x-dvd":
684                                                 print "physical dvd found:", devicepath
685                                                 self.physicalDVD = True
686                                                 return
687                 self.physicalDVD = False
688
689 def main(session, **kwargs):
690         session.open(DVDPlayer)
691
692 def menu(menuid, **kwargs):
693         if menuid == "mainmenu":
694                 return [(_("DVD Player"), main, "dvd_player", 46)]
695         return []
696
697 from Plugins.Plugin import PluginDescriptor
698
699 def filescan_open(list, session, **kwargs):
700         if len(list) == 1 and list[0].mimetype == "video/x-dvd":
701                 splitted = list[0].path.split('/')
702                 print "splitted", splitted
703                 if len(splitted) > 2:
704                         if splitted[1] == 'autofs':
705                                 session.open(DVDPlayer, dvd_device="/dev/%s" %(splitted[2]))
706                                 return
707                         else:
708                                 print "splitted[0]", splitted[1]
709         else:
710                 dvd_filelist = []
711                 for x in list:
712                         if x.mimetype == "video/x-dvd-iso":
713                                 dvd_filelist.append(x.path)
714                         if x.mimetype == "video/x-dvd":
715                                 dvd_filelist.append(x.path.rsplit('/',1)[0])                    
716                 session.open(DVDPlayer, dvd_filelist=dvd_filelist)
717
718 def filescan(**kwargs):
719         from Components.Scanner import Scanner, ScanPath
720
721         # Overwrite checkFile to only detect local
722         class LocalScanner(Scanner):
723                 def checkFile(self, file):
724                         return fileExists(file.path)
725
726         return [
727                 LocalScanner(mimetypes = ["video/x-dvd","video/x-dvd-iso"],
728                         paths_to_scan =
729                                 [
730                                         ScanPath(path = "video_ts", with_subdirs = False),
731                                         ScanPath(path = "", with_subdirs = False),
732                                 ],
733                         name = "DVD",
734                         description = _("Play DVD"),
735                         openfnc = filescan_open,
736                 )]              
737
738 def Plugins(**kwargs):
739         return [PluginDescriptor(name = "DVDPlayer", description = "Play DVDs", where = PluginDescriptor.WHERE_MENU, fnc = menu),
740                         PluginDescriptor(where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)]