Merge branch 'obi/master' into experimental
[vuplus_dvbapp] / lib / python / Plugins / Extensions / DVDPlayer / plugin.py
1 from os import path as os_path, remove as os_remove, listdir as os_listdir, system
2 from enigma import eTimer, iPlayableService, iServiceInformation, eServiceReference, iServiceKeys, getDesktop
3 from Screens.Screen import Screen
4 from Screens.MessageBox import MessageBox
5 from Screens.ChoiceBox import ChoiceBox
6 from Screens.HelpMenu import HelpableScreen
7 from Screens.InfoBarGenerics import InfoBarSeek, InfoBarPVRState, InfoBarCueSheetSupport, InfoBarShowHide, InfoBarNotifications, InfoBarAudioSelection, InfoBarSubtitleSupport
8 from Components.ActionMap import ActionMap, NumberActionMap, HelpableActionMap
9 from Components.Label import Label
10 from Components.Sources.StaticText import StaticText
11 from Components.Pixmap import Pixmap
12 from Components.FileList import FileList
13 from Components.MenuList import MenuList
14 from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
15 from Components.config import config
16 from Tools.Directories import pathExists, fileExists
17 from Components.Harddisk import harddiskmanager
18
19 import servicedvd # load c++ part of dvd player plugin
20
21 lastpath = ""
22
23 class FileBrowser(Screen):
24
25         def __init__(self, session, dvd_filelist = [ ]):
26                 Screen.__init__(self, session)
27
28                 # for the skin: first try FileBrowser_DVDPlayer, then FileBrowser, this allows individual skinning
29                 self.skinName = ["FileBrowser_DVDPlayer", "FileBrowser" ]
30
31                 self.dvd_filelist = dvd_filelist
32                 if len(dvd_filelist):   
33                         self["filelist"] = MenuList(self.dvd_filelist)
34                 else:
35                         global lastpath
36                         if lastpath is not None:
37                                 currDir = lastpath + "/"
38                         else:
39                                 currDir = "/media/dvd/"
40                         if not pathExists(currDir):
41                                 currDir = "/"
42                         if lastpath == "":  # 'None' is magic to start at the list of mountpoints
43                                 currDir = None
44
45                         inhibitDirs = ["/bin", "/boot", "/dev", "/etc", "/home", "/lib", "/proc", "/sbin", "/share", "/sys", "/tmp", "/usr", "/var"]
46                         self.filelist = FileList(currDir, matchingPattern = "(?i)^.*\.(iso|img)", useServiceRef = True)
47                         self["filelist"] = self.filelist
48
49                 self["FilelistActions"] = ActionMap(["SetupActions"],
50                         {
51                                 "save": self.ok,
52                                 "ok": self.ok,
53                                 "cancel": self.exit
54                         })
55                 self["key_red"] = StaticText(_("Cancel"))
56                 self["key_green"] = StaticText(_("OK"))
57                 self.onLayoutFinish.append(self.layoutFinished)
58
59         def layoutFinished(self):
60                 self.setTitle(_("DVD File Browser"))
61
62         def ok(self):
63                 if len(self.dvd_filelist):
64                         print "OK " + self["filelist"].getCurrent()
65                         self.close(self["filelist"].getCurrent())
66                 else:
67                         global lastpath
68                         filename = self["filelist"].getFilename()
69                         if filename is not None:
70                                 if filename.upper().endswith("VIDEO_TS/"):
71                                         print "dvd structure found, trying to open..."
72                                         dvdpath = filename[0:-9]
73                                         lastpath = (dvdpath.rstrip("/").rsplit("/",1))[0]
74                                         print "lastpath video_ts/=", lastpath
75                                         self.close(dvdpath)
76                                         return
77                         if self["filelist"].canDescent(): # isDir
78                                 self["filelist"].descent()
79                                 pathname = self["filelist"].getCurrentDirectory() or ""
80                                 if fileExists(pathname+"VIDEO_TS.IFO"):
81                                         print "dvd structure found, trying to open..."
82                                         lastpath = (pathname.rstrip("/").rsplit("/",1))[0]
83                                         print "lastpath video_ts.ifo=", lastpath
84                                         self.close(pathname)
85                                 if fileExists(pathname+"VIDEO_TS/VIDEO_TS.IFO"):
86                                         print "dvd structure found, trying to open..."
87                                         lastpath = (pathname.rstrip("/").rsplit("/",1))[0]
88                                         print "lastpath video_ts.ifo=", lastpath
89                                         pathname += "VIDEO_TS"
90                                         self.close(pathname)
91                         else:
92                                 lastpath = filename[0:filename.rfind("/")]
93                                 print "lastpath directory=", lastpath
94                                 self.close(filename)
95
96         def exit(self):
97                 self.close(None)
98
99 class DVDSummary(Screen):
100         skin = (
101         """<screen name="DVDSummary" position="0,0" size="132,64" id="1">
102                 <widget source="session.CurrentService" render="Label" position="5,4" size="120,28" font="Regular;12" transparent="1" >
103                         <convert type="ServiceName">Name</convert>
104                 </widget>
105                 <widget name="DVDPlayer" position="5,30" size="66,16" font="Regular;11" transparent="1" />
106                 <widget name="Chapter" position="72,30" size="54,16" font="Regular;12" transparent="1" halign="right" />
107                 <widget source="session.CurrentService" render="Label" position="66,46" size="60,18" font="Regular;16" transparent="1" halign="right" >
108                         <convert type="ServicePosition">Position</convert>
109                 </widget>
110                 <widget source="session.CurrentService" render="Progress" position="6,46" size="60,18" borderWidth="1" >
111                         <convert type="ServicePosition">Position</convert>
112                 </widget>
113         </screen>""",
114         """<screen name="DVDSummary" position="0,0" size="96,64" id="2">
115                 <widget source="session.CurrentService" render="Label" position="0,0" size="96,25" font="Regular;12" transparent="1" >
116                         <convert type="ServiceName">Name</convert>
117                 </widget>
118                 <widget name="DVDPlayer" position="0,26" size="96,12" font="Regular;10" transparent="1" />
119                 <widget name="Chapter" position="0,40" size="66,12" font="Regular;10" transparent="1" halign="left" />
120                 <widget source="session.CurrentService" render="Label" position="66,40" size="30,12" font="Regular;10" transparent="1" halign="right" >
121                         <convert type="ServicePosition">Position</convert>
122                 </widget>
123                 <widget source="session.CurrentService" render="Progress" position="0,52" size="96,12" borderWidth="1" >
124                         <convert type="ServicePosition">Position</convert>
125                 </widget>
126         </screen>""")
127
128         def __init__(self, session, parent):
129                 Screen.__init__(self, session, parent)
130
131                 self["DVDPlayer"] = Label("DVD Player")
132                 self["Title"] = Label("")
133                 self["Time"] = Label("")
134                 self["Chapter"] = Label("")
135
136         def updateChapter(self, chapter):
137                 self["Chapter"].setText(chapter)
138
139         def setTitle(self, title):
140                 self["Title"].setText(title)
141
142 class DVDOverlay(Screen):
143         def __init__(self, session, args = None):
144                 desktop_size = getDesktop(0).size()
145                 DVDOverlay.skin = """<screen name="DVDOverlay" position="0,0" size="%d,%d" flags="wfNoBorder" zPosition="-1" backgroundColor="transparent" />""" %(desktop_size.width(), desktop_size.height())
146                 Screen.__init__(self, session)
147
148 class ChapterZap(Screen):
149         skin = """
150         <screen name="ChapterZap" position="235,255" size="250,60" title="Chapter" >
151                 <widget name="chapter" position="35,15" size="110,25" font="Regular;23" />
152                 <widget name="number" position="145,15" size="80,25" halign="right" font="Regular;23" />
153         </screen>"""
154         
155         def quit(self):
156                 self.Timer.stop()
157                 self.close(0)
158
159         def keyOK(self):
160                 self.Timer.stop()
161                 self.close(int(self["number"].getText()))
162
163         def keyNumberGlobal(self, number):
164                 self.Timer.start(3000, True)            #reset timer
165                 self.field = self.field + str(number)
166                 self["number"].setText(self.field)
167                 if len(self.field) >= 4:
168                         self.keyOK()
169
170         def __init__(self, session, number):
171                 Screen.__init__(self, session)
172                 self.field = str(number)
173
174                 self["chapter"] = Label(_("Chapter:"))
175
176                 self["number"] = Label(self.field)
177
178                 self["actions"] = NumberActionMap( [ "SetupActions" ],
179                         {
180                                 "cancel": self.quit,
181                                 "ok": self.keyOK,
182                                 "1": self.keyNumberGlobal,
183                                 "2": self.keyNumberGlobal,
184                                 "3": self.keyNumberGlobal,
185                                 "4": self.keyNumberGlobal,
186                                 "5": self.keyNumberGlobal,
187                                 "6": self.keyNumberGlobal,
188                                 "7": self.keyNumberGlobal,
189                                 "8": self.keyNumberGlobal,
190                                 "9": self.keyNumberGlobal,
191                                 "0": self.keyNumberGlobal
192                         })
193
194                 self.Timer = eTimer()
195                 self.Timer.callback.append(self.keyOK)
196                 self.Timer.start(3000, True)
197
198 class DVDPlayer(Screen, InfoBarBase, InfoBarNotifications, InfoBarSeek, InfoBarPVRState, InfoBarShowHide, HelpableScreen, InfoBarCueSheetSupport, InfoBarAudioSelection, InfoBarSubtitleSupport):
199         ALLOW_SUSPEND = Screen.SUSPEND_PAUSES
200         ENABLE_RESUME_SUPPORT = True
201         
202         skin = """
203         <screen name="DVDPlayer" flags="wfNoBorder" position="0,380" size="720,160" title="InfoBar" backgroundColor="transparent" >
204                 <!-- Background -->
205                 <ePixmap position="0,0" zPosition="-2" size="720,160" pixmap="skin_default/info-bg_mp.png" alphatest="off" />
206                 <ePixmap position="29,40" zPosition="0" size="665,104" pixmap="skin_default/screws_mp.png" alphatest="on" transparent="1" />
207                 <!-- colorbuttons -->
208                 <ePixmap position="48,70" zPosition="0" size="108,13" pixmap="skin_default/icons/mp_buttons.png" alphatest="on" />
209                 <!-- Servicename -->
210                 <ePixmap pixmap="skin_default/icons/icon_event.png" position="207,78" zPosition="1" size="15,10" alphatest="on" />
211                 <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">
212                         <convert type="ServiceName">Name</convert>
213                 </widget>
214                 <!-- Chapter info -->
215                 <widget name="chapterLabel" position="230,96" size="360,22" font="Regular;20" foregroundColor="#c3c3c9" backgroundColor="#263c59" transparent="1" />
216                 <!-- Audio track info -->
217                 <ePixmap pixmap="skin_default/icons/icon_dolby.png" position="540,60" zPosition="1" size="26,16" alphatest="on"/>
218                 <widget name="audioLabel" position="570,60" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
219                 <!-- Subtitle track info -->
220                 <widget source="session.CurrentService" render="Pixmap" pixmap="skin_default/icons/icon_txt.png" position="540,83" zPosition="1" size="26,16" alphatest="on" >
221                         <convert type="ServiceInfo">HasTelext</convert>
222                         <convert type="ConditionalShowHide" />
223                 </widget>
224                 <widget name="subtitleLabel" position="570,83" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
225                 <!-- Angle info -->
226                 <widget name="anglePix" pixmap="skin_default/icons/icon_view.png" position="540,106" size="26,16" alphatest="on" />
227                 <widget name="angleLabel" position="570,106" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
228                 <!-- Elapsed time -->
229                 <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" >
230                         <convert type="ServicePosition">Position,ShowHours</convert>
231                 </widget>
232                 <!-- Progressbar (movie position)-->
233                 <widget source="session.CurrentService" render="PositionGauge" position="300,133" size="270,10" zPosition="2" pointer="skin_default/position_pointer.png:540,0" transparent="1" >
234                         <convert type="ServicePosition">Gauge</convert>
235                 </widget>
236                 <!-- Remaining time -->
237                 <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" >
238                         <convert type="ServicePosition">Remaining,Negate,ShowHours</convert>
239                 </widget>
240         </screen>"""
241
242         def save_infobar_seek_config(self):
243                 self.saved_config_speeds_forward = config.seek.speeds_forward.value
244                 self.saved_config_speeds_backward = config.seek.speeds_backward.value
245                 self.saved_config_enter_forward = config.seek.enter_forward.value
246                 self.saved_config_enter_backward = config.seek.enter_backward.value
247                 self.saved_config_seek_on_pause = config.seek.on_pause.value
248                 self.saved_config_seek_speeds_slowmotion = config.seek.speeds_slowmotion.value
249
250         def change_infobar_seek_config(self):
251                 config.seek.speeds_forward.value = [2, 4, 8, 16, 32, 64]
252                 config.seek.speeds_backward.value = [8, 16, 32, 64]
253                 config.seek.speeds_slowmotion.value = [ ]
254                 config.seek.enter_forward.value = "2"
255                 config.seek.enter_backward.value = "2"
256                 config.seek.on_pause.value = "play"
257
258         def restore_infobar_seek_config(self):
259                 config.seek.speeds_forward.value = self.saved_config_speeds_forward
260                 config.seek.speeds_backward.value = self.saved_config_speeds_backward
261                 config.seek.speeds_slowmotion.value = self.saved_config_seek_speeds_slowmotion
262                 config.seek.enter_forward.value = self.saved_config_enter_forward
263                 config.seek.enter_backward.value = self.saved_config_enter_backward
264                 config.seek.on_pause.value = self.saved_config_seek_on_pause
265
266         def __init__(self, session, dvd_device = None, dvd_filelist = [ ], args = None):
267                 Screen.__init__(self, session)
268                 InfoBarBase.__init__(self)
269                 InfoBarNotifications.__init__(self)
270                 InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions")
271                 InfoBarShowHide.__init__(self)
272                 InfoBarAudioSelection.__init__(self)
273                 InfoBarSubtitleSupport.__init__(self)
274                 HelpableScreen.__init__(self)
275                 self.save_infobar_seek_config()
276                 self.change_infobar_seek_config()
277                 InfoBarSeek.__init__(self)
278                 InfoBarPVRState.__init__(self)
279                 self.dvdScreen = self.session.instantiateDialog(DVDOverlay)
280
281                 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
282                 self.session.nav.stopService()
283                 self["audioLabel"] = Label("n/a")
284                 self["subtitleLabel"] = Label("")
285                 self["angleLabel"] = Label("")
286                 self["chapterLabel"] = Label("")
287                 self["anglePix"] = Pixmap()
288                 self["anglePix"].hide()
289                 self.last_audioTuple = None
290                 self.last_subtitleTuple = None
291                 self.last_angleTuple = None
292                 self.totalChapters = 0
293                 self.currentChapter = 0
294                 self.totalTitles = 0
295                 self.currentTitle = 0
296
297                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
298                         {
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                 self.dvdScreen.hide()
410                 subs = self.getServiceInterface("subtitle")
411                 if subs:
412                         subs.disableSubtitles(self.session.current_dialog.instance)
413
414         def serviceStarted(self): #override InfoBarShowHide function
415                 self.dvdScreen.show()
416
417         def doEofInternal(self, playing):
418                 if self.in_menu:
419                         self.hide()
420
421         def __menuOpened(self):
422                 self.hide()
423                 self.in_menu = True
424                 self["NumberActions"].setEnabled(False)
425
426         def __menuClosed(self):
427                 self.show()
428                 self.in_menu = False
429                 self["NumberActions"].setEnabled(True)
430
431         def setChapterLabel(self):
432                 chapterLCD = "Menu"
433                 chapterOSD = "DVD Menu"
434                 if self.currentTitle > 0:
435                         chapterLCD = "%s %d" % (_("Chap."), self.currentChapter)
436                         chapterOSD = "DVD %s %d/%d" % (_("Chapter"), self.currentChapter, self.totalChapters)
437                         chapterOSD += " (%s %d/%d)" % (_("Title"), self.currentTitle, self.totalTitles)
438                 self["chapterLabel"].setText(chapterOSD)
439                 try:
440                         self.session.summary.updateChapter(chapterLCD)
441                 except:
442                         pass
443
444         def doNothing(self):
445                 pass
446
447         def toggleInfo(self):
448                 if not self.in_menu:
449                         self.toggleShow()
450                         print "toggleInfo"
451
452         def __timeUpdated(self):
453                 print "timeUpdated"
454
455         def __statePlay(self):
456                 print "statePlay"
457
458         def __statePause(self):
459                 print "statePause"
460
461         def __osdFFwdInfoAvail(self):
462                 self.setChapterLabel()
463                 print "FFwdInfoAvail"
464
465         def __osdFBwdInfoAvail(self):
466                 self.setChapterLabel()
467                 print "FBwdInfoAvail"
468
469         def __osdStringAvail(self):
470                 print "StringAvail"
471
472         def __osdAudioInfoAvail(self):
473                 info = self.getServiceInterface("info")
474                 audioTuple = info and info.getInfoObject(iServiceInformation.sUser+6)
475                 print "AudioInfoAvail ", repr(audioTuple)
476                 if audioTuple:
477                         audioString = "%d: %s (%s)" % (audioTuple[0],audioTuple[1],audioTuple[2])
478                         self["audioLabel"].setText(audioString)
479                         if audioTuple != self.last_audioTuple and not self.in_menu:
480                                 self.doShow()
481                 self.last_audioTuple = audioTuple
482
483         def __osdSubtitleInfoAvail(self):
484                 info = self.getServiceInterface("info")
485                 subtitleTuple = info and info.getInfoObject(iServiceInformation.sUser+7)
486                 print "SubtitleInfoAvail ", repr(subtitleTuple)
487                 if subtitleTuple:
488                         subtitleString = ""
489                         if subtitleTuple[0] is not 0:
490                                 subtitleString = "%d: %s" % (subtitleTuple[0],subtitleTuple[1])
491                         self["subtitleLabel"].setText(subtitleString)
492                         if subtitleTuple != self.last_subtitleTuple and not self.in_menu:
493                                 self.doShow()
494                 self.last_subtitleTuple = subtitleTuple
495         
496         def __osdAngleInfoAvail(self):
497                 info = self.getServiceInterface("info")
498                 angleTuple = info and info.getInfoObject(iServiceInformation.sUser+8)
499                 print "AngleInfoAvail ", repr(angleTuple)
500                 if angleTuple:
501                         angleString = ""
502                         if angleTuple[1] > 1:
503                                 angleString = "%d / %d" % (angleTuple[0],angleTuple[1])
504                                 self["anglePix"].show()
505                         else:
506                                 self["anglePix"].hide()
507                         self["angleLabel"].setText(angleString)
508                         if angleTuple != self.last_angleTuple and not self.in_menu:
509                                 self.doShow()
510                 self.last_angleTuple = angleTuple
511
512         def __chapterUpdated(self):
513                 info = self.getServiceInterface("info")
514                 if info:
515                         self.currentChapter = info.getInfo(iServiceInformation.sCurrentChapter)
516                         self.totalChapters = info.getInfo(iServiceInformation.sTotalChapters)
517                         self.setChapterLabel()
518                         print "__chapterUpdated: %d/%d" % (self.currentChapter, self.totalChapters)
519
520         def __titleUpdated(self):
521                 info = self.getServiceInterface("info")
522                 if info:
523                         self.currentTitle = info.getInfo(iServiceInformation.sCurrentTitle)
524                         self.totalTitles = info.getInfo(iServiceInformation.sTotalTitles)
525                         self.setChapterLabel()
526                         print "__titleUpdated: %d/%d" % (self.currentTitle, self.totalTitles)
527                         if not self.in_menu:
528                                 self.doShow()
529                 
530         def askLeavePlayer(self):
531                 choices = [(_("Exit"), "exit"), (_("Continue playing"), "play")]
532                 if True or not self.physicalDVD:
533                         choices.insert(1,(_("Return to file browser"), "browser"))
534                 if self.physicalDVD:
535                         cur = self.session.nav.getCurrentlyPlayingServiceReference()
536                         if cur and not cur.toString().endswith(harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD())):
537                             choices.insert(0,(_("Play DVD"), "playPhysical" ))
538                 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list = choices)
539
540         def sendKey(self, key):
541                 keys = self.getServiceInterface("keys")
542                 if keys:
543                         keys.keyPressed(key)
544                 return keys
545
546         def enterAudioSelection(self):
547                 self.audioSelection()
548
549         def nextAudioTrack(self):
550                 self.sendKey(iServiceKeys.keyUser)
551
552         def nextSubtitleTrack(self):
553                 self.sendKey(iServiceKeys.keyUser+1)
554
555         def enterDVDAudioMenu(self):
556                 self.sendKey(iServiceKeys.keyUser+2)
557
558         def nextChapter(self):
559                 self.sendKey(iServiceKeys.keyUser+3)
560
561         def prevChapter(self):
562                 self.sendKey(iServiceKeys.keyUser+4)
563
564         def nextTitle(self):
565                 self.sendKey(iServiceKeys.keyUser+5)
566
567         def prevTitle(self):
568                 self.sendKey(iServiceKeys.keyUser+6)
569
570         def enterDVDMenu(self):
571                 self.sendKey(iServiceKeys.keyUser+7)
572         
573         def nextAngle(self):
574                 self.sendKey(iServiceKeys.keyUser+8)
575
576         def seekBeginning(self):
577                 if self.service:
578                         seekable = self.getSeek()
579                         if seekable:
580                                 seekable.seekTo(0)
581
582         def zapToNumber(self, number):
583                 if self.service:
584                         seekable = self.getSeek()
585                         if seekable:
586                                 print "seek to chapter %d" % number
587                                 seekable.seekChapter(number)
588
589 #       MENU ACTIONS
590         def keyRight(self):
591                 self.sendKey(iServiceKeys.keyRight)
592
593         def keyLeft(self):
594                 self.sendKey(iServiceKeys.keyLeft)
595
596         def keyUp(self):
597                 self.sendKey(iServiceKeys.keyUp)
598
599         def keyDown(self):
600                 self.sendKey(iServiceKeys.keyDown)
601
602         def keyOk(self):
603                 if self.sendKey(iServiceKeys.keyOk) and not self.in_menu:
604                         self.toggleInfo()
605
606         def keyCancel(self):
607                 self.askLeavePlayer()
608
609         def opened(self):
610                 if self.autoplay and self.dvd_filelist:
611                         # opened via autoplay
612                         self.FileBrowserClosed(self.dvd_filelist[0])
613                 elif self.autoplay and self.physicalDVD:
614                         self.playPhysicalCB(True)
615                 elif self.physicalDVD:
616                         # opened from menu with dvd in drive
617                         self.session.openWithCallback(self.playPhysicalCB, MessageBox, text=_("Do you want to play DVD in drive?"), timeout=5 )
618                 else:
619                         # opened from menu without dvd in drive
620                         self.session.openWithCallback(self.FileBrowserClosed, FileBrowser, self.dvd_filelist)
621
622         def playPhysicalCB(self, answer):
623                 if answer == True:
624                         self.FileBrowserClosed(harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD()))
625                 else:
626                         self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
627
628         def FileBrowserClosed(self, val):
629                 curref = self.session.nav.getCurrentlyPlayingServiceReference()
630                 print "FileBrowserClosed", val
631                 if val is None:
632                         self.askLeavePlayer()
633                 else:
634                         newref = eServiceReference(4369, 0, val)
635                         print "play", newref.toString()
636                         if curref is None or curref != newref:
637                                 if newref.toString().endswith("/VIDEO_TS") or newref.toString().endswith("/"):
638                                         names = newref.toString().rsplit("/",3)
639                                         if names[2].startswith("Disk ") or names[2].startswith("DVD "):
640                                                 name = str(names[1]) + " - " + str(names[2])
641                                         else:
642                                                 name = names[2]
643                                         print "setting name to: ", self.service
644                                         newref.setName(str(name))
645                                 self.session.nav.playService(newref)
646                                 self.service = self.session.nav.getCurrentService()
647                                 print "self.service", self.service
648                                 print "cur_dlg", self.session.current_dialog
649                                 subs = self.getServiceInterface("subtitle")
650                                 if subs:
651                                         subs.enableSubtitles(self.dvdScreen.instance, None)
652
653         def exitCB(self, answer):
654                 if answer is not None:
655                         if answer[1] == "exit":
656                                 if self.service:
657                                         self.service = None
658                                 self.close()
659                         if answer[1] == "browser":
660                                 #TODO check here if a paused dvd playback is already running... then re-start it...
661                                 #else
662                                 if self.service:
663                                         self.service = None
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_PLAY)
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, fnc = menu),
779                         PluginDescriptor(where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)]