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