bab64ce12faa404dfffb08baa456cce5b5349d5b
[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 time import strftime
3 from enigma import eTimer, iPlayableService, eServiceCenter, iServiceInformation, eServiceReference, iServiceKeys
4 from Screens.Screen import Screen
5 from Screens.MessageBox import MessageBox
6 from Screens.ChoiceBox import ChoiceBox
7 from Screens.InputBox import InputBox
8 from Screens.HelpMenu import HelpableScreen
9 from Screens.InfoBarGenerics import InfoBarSeek, InfoBarPVRState, InfoBarCueSheetSupport, InfoBarShowHide, InfoBarNotifications
10 from Components.ActionMap import ActionMap, NumberActionMap, HelpableActionMap
11 from Components.Label import Label
12 from Components.FileList import FileList
13 from Components.ServiceEventTracker import ServiceEventTracker
14 from Components.config import config
15 from Components.ProgressBar import ProgressBar
16 from ServiceReference import ServiceReference
17 from Tools.Directories import pathExists, fileExists
18
19 import random
20 import servicedvd # load c++ part of dvd player plugin
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):
28                 Screen.__init__(self, session)
29                 currDir = "/media/dvd/"
30                 if not pathExists(currDir):
31                         currDir = "/"
32                 #else:
33                         #print system("mount "+currDir)
34                 self.filelist = FileList(currDir, matchingPattern = "(?i)^.*\.(iso)", useServiceRef = True)
35                 self["filelist"] = self.filelist
36
37                 self["FilelistActions"] = ActionMap(["OkCancelActions"],
38                         {
39                                 "ok": self.ok,
40                                 "cancel": self.exit
41                         })
42
43         def ok(self):
44                 filename = self["filelist"].getFilename()
45                 if filename is not None and filename.upper().endswith("VIDEO_TS/"):
46                         print "dvd structure found, trying to open..."
47                         self.close(filename[0:-9])
48                 elif self["filelist"].canDescent(): # isDir
49                         self["filelist"].descent()
50                 else:
51                         self.close(filename)
52                         
53         def exit(self):
54                 self.close(None)
55                 
56 class DVDSummary(Screen):
57         skin = """
58         <screen position="0,0" size="132,64">
59                 <widget source="session.CurrentService" render="Label" position="5,4" size="120,28" font="Regular;12" transparent="1" >
60                         <convert type="ServiceName">Name</convert>
61                 </widget>
62                 <widget name="DVDPlayer" position="5,30" size="66,16" font="Regular;12" transparent="1" />
63                 <widget name="Chapter" position="72,30" size="54,16" font="Regular;12" transparent="1" halign="right" />
64                 <widget source="session.CurrentService" render="Label" position="66,46" size="60,18" font="Regular;16" transparent="1" halign="right" >
65                         <convert type="ServicePosition">Position</convert>
66                 </widget>
67                 <widget source="session.CurrentService" render="Progress" position="6,46" size="60,18" borderWidth="1" >
68                         <convert type="ServicePosition">Position</convert>
69                 </widget>
70         </screen>"""
71
72         def __init__(self, session, parent):
73                 Screen.__init__(self, session, parent)
74
75                 self["DVDPlayer"] = Label("DVD Player")
76                 self["Title"] = Label("")
77                 self["Time"] = Label("")
78                 self["Chapter"] = Label("")
79
80         def updateChapter(self, chapter):
81                 self["Chapter"].setText(chapter)
82
83         def setTitle(self, title):
84                 self["Title"].setText(title)
85
86 class DVDOverlay(Screen):
87         skin = """<screen name="DVDOverlay" position="0,0" size="720,576" flags="wfNoBorder" zPosition="-1" backgroundColor="transparent" />"""
88         def __init__(self, session, args = None):
89                 Screen.__init__(self, session)
90                 
91 class ChapterZap(Screen):
92         skin = """
93         <screen name="ChapterZap" position="235,255" size="250,60" title="Chapter" >
94                 <widget name="chapter" position="35,15" size="110,25" font="Regular;23" />
95                 <widget name="number" position="145,15" size="80,25" halign="right" font="Regular;23" />
96         </screen>"""
97         
98         def quit(self):
99                 self.Timer.stop()
100                 self.close(0)
101
102         def keyOK(self):
103                 self.Timer.stop()
104                 self.close(int(self["number"].getText()))
105
106         def keyNumberGlobal(self, number):
107                 self.Timer.start(3000, True)            #reset timer
108                 self.field = self.field + str(number)
109                 self["number"].setText(self.field)
110                 if len(self.field) >= 4:
111                         self.keyOK()
112
113         def __init__(self, session, number):
114                 Screen.__init__(self, session)
115                 self.field = str(number)
116
117                 self["chapter"] = Label(_("Chapter:"))
118
119                 self["number"] = Label(self.field)
120
121                 self["actions"] = NumberActionMap( [ "SetupActions" ],
122                         {
123                                 "cancel": self.quit,
124                                 "ok": self.keyOK,
125                                 "1": self.keyNumberGlobal,
126                                 "2": self.keyNumberGlobal,
127                                 "3": self.keyNumberGlobal,
128                                 "4": self.keyNumberGlobal,
129                                 "5": self.keyNumberGlobal,
130                                 "6": self.keyNumberGlobal,
131                                 "7": self.keyNumberGlobal,
132                                 "8": self.keyNumberGlobal,
133                                 "9": self.keyNumberGlobal,
134                                 "0": self.keyNumberGlobal
135                         })
136
137                 self.Timer = eTimer()
138                 self.Timer.callback.append(self.keyOK)
139                 self.Timer.start(3000, True)
140
141 class DVDPlayer(Screen, InfoBarNotifications, InfoBarSeek, InfoBarCueSheetSupport, InfoBarPVRState, InfoBarShowHide, HelpableScreen):
142         ALLOW_SUSPEND = True
143         ENABLE_RESUME_SUPPORT = True
144         
145         skin = """
146         <screen name="DVDPlayer" flags="wfNoBorder" position="0,380" size="720,160" title="InfoBar" backgroundColor="transparent" >
147                 <!-- Background -->
148                 <ePixmap position="0,0" zPosition="-2" size="720,160" pixmap="skin_default/info-bg_mp.png" alphatest="off" />
149                 <ePixmap position="29,40" zPosition="0" size="665,104" pixmap="skin_default/screws_mp.png" alphatest="on" transparent="1" />
150                 <!-- colorbuttons -->
151                 <ePixmap position="48,70" zPosition="0" size="108,13" pixmap="skin_default/icons/mp_buttons.png" alphatest="on" />
152                 <!-- Servicename -->
153                 <ePixmap pixmap="skin_default/icons/icon_event.png" position="207,78" zPosition="1" size="15,10" alphatest="on" />
154                 <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">
155                         <convert type="ServiceName">Name</convert>
156                 </widget>
157                 <!-- Chapter info -->
158                 <widget name="chapterLabel" position="230,96" size="360,22" font="Regular;20" foregroundColor="#c3c3c9" backgroundColor="#263c59" transparent="1" />
159                 <!-- Audio track info -->
160                 <ePixmap pixmap="skin_default/icons/icon_dolby.png" position="540,73" zPosition="1" size="26,16" alphatest="on"/>
161                 <widget name="audioLabel" position="570,73" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
162                 <!-- Subtitle track info -->
163                 <widget source="session.CurrentService" render="Pixmap" pixmap="skin_default/icons/icon_txt.png" position="540,96" zPosition="1" size="26,16" alphatest="on" >
164                         <convert type="ServiceInfo">HasTelext</convert>
165                         <convert type="ConditionalShowHide" />
166                 </widget>
167                 <widget name="subtitleLabel" position="570,96" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
168                 <!-- Elapsed time -->
169                 <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" >
170                         <convert type="ServicePosition">Position,ShowHours</convert>
171                 </widget>
172                 <!-- Progressbar (movie position)-->
173                 <widget source="session.CurrentService" render="PositionGauge" position="300,133" size="270,10" zPosition="2" pointer="skin_default/position_pointer.png:540,0" transparent="1" >
174                         <convert type="ServicePosition">Gauge</convert>
175                 </widget>
176                 <!-- Remaining time -->
177                 <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" >
178                         <convert type="ServicePosition">Remaining,Negate,ShowHours</convert>
179                 </widget>
180         </screen>"""
181
182         def save_infobar_seek_config(self):
183                 self.saved_config_speeds_forward = config.seek.speeds_forward.value
184                 self.saved_config_speeds_backward = config.seek.speeds_backward.value
185                 self.saved_config_enter_forward = config.seek.enter_forward.value
186                 self.saved_config_enter_backward = config.seek.enter_backward.value
187                 self.saved_config_seek_stepwise_minspeed = config.seek.stepwise_minspeed.value
188                 self.saved_config_seek_stepwise_repeat = config.seek.stepwise_repeat.value
189                 self.saved_config_seek_on_pause = config.seek.on_pause.value
190                 self.saved_config_seek_speeds_slowmotion = config.seek.speeds_slowmotion.value
191
192         def change_infobar_seek_config(self):
193                 config.seek.speeds_forward.value = [2, 4, 8, 16, 32, 64]
194                 config.seek.speeds_backward.value = [8, 16, 32, 64]
195                 config.seek.speeds_slowmotion.value = [ ]
196                 config.seek.enter_forward.value = "2"
197                 config.seek.enter_backward.value = "2"
198                 config.seek.stepwise_minspeed.value = "Never"
199                 config.seek.stepwise_repeat.value = "3"
200                 config.seek.on_pause.value = "play"
201
202         def restore_infobar_seek_config(self):
203                 config.seek.speeds_forward.value = self.saved_config_speeds_forward
204                 config.seek.speeds_backward.value = self.saved_config_speeds_backward
205                 config.seek.speeds_slowmotion.value = self.saved_config_seek_speeds_slowmotion
206                 config.seek.enter_forward.value = self.saved_config_enter_forward
207                 config.seek.enter_backward.value = self.saved_config_enter_backward
208                 config.seek.stepwise_minspeed.value = self.saved_config_seek_stepwise_minspeed
209                 config.seek.stepwise_repeat.value = self.saved_config_seek_stepwise_repeat
210                 config.seek.on_pause.value = self.saved_config_seek_on_pause
211
212         def __init__(self, session, args = None):
213                 Screen.__init__(self, session)
214                 InfoBarNotifications.__init__(self)
215                 InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions")
216                 InfoBarShowHide.__init__(self)
217                 HelpableScreen.__init__(self)
218                 self.save_infobar_seek_config()
219                 self.change_infobar_seek_config()
220                 InfoBarSeek.__init__(self)
221                 InfoBarPVRState.__init__(self)
222                 self.dvdScreen = self.session.instantiateDialog(DVDOverlay)
223
224                 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
225                 self.session.nav.stopService()
226                 self["audioLabel"] = Label("1")
227                 self["subtitleLabel"] = Label("")
228                 self["chapterLabel"] = Label("")
229                 self.totalChapters = 0
230                 self.currentChapter = 0
231                 self.totalTitles = 0
232                 self.currentTitle = 0
233
234                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
235                         {
236                                 iPlayableService.evUser: self.__timeUpdated,
237                                 iPlayableService.evUser+1: self.__statePlay,
238                                 iPlayableService.evUser+2: self.__statePause,
239                                 iPlayableService.evUser+3: self.__osdFFwdInfoAvail,
240                                 iPlayableService.evUser+4: self.__osdFBwdInfoAvail,
241                                 iPlayableService.evUser+5: self.__osdStringAvail,
242                                 iPlayableService.evUser+6: self.__osdAudioInfoAvail,
243                                 iPlayableService.evUser+7: self.__osdSubtitleInfoAvail,
244                                 iPlayableService.evUser+8: self.__chapterUpdated,
245                                 iPlayableService.evUser+9: self.__titleUpdated,
246                                 #iPlayableService.evUser+10: self.__initializeDVDinfo,
247                                 iPlayableService.evUser+11: self.__menuOpened,
248                                 iPlayableService.evUser+12: self.__menuClosed
249                         })
250
251                 self["DVDPlayerDirectionActions"] = HelpableActionMap(self, "DirectionActions",
252                         {
253                                 #MENU KEY DOWN ACTIONS
254                                 "left": (self.keyLeft, _("DVD left key")),
255                                 "right": (self.keyRight, _("DVD right key")),
256                                 "up": (self.keyUp, _("DVD up key")),
257                                 "down": (self.keyDown, _("DVD down key")),
258
259                                 #MENU KEY REPEATED ACTIONS
260                                 "leftRepeated": self.doNothing,
261                                 "rightRepeated": self.doNothing,
262                                 "upRepeated": self.doNothing,
263                                 "downRepeated": self.doNothing,
264
265                                 #MENU KEY UP ACTIONS
266                                 "leftUp": self.doNothing,
267                                 "rightUp": self.doNothing,
268                                 "upUp": self.doNothing,
269                                 "downUp": self.doNothing,
270                         }, -2)
271
272                 self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions",
273                         {
274                                 "ok": (self.keyOk, _("DVD ENTER key")),
275                                 "cancel": self.keyCancel,
276                         }, -2)
277
278                 self["DVDPlayerPlaybackActions"] = HelpableActionMap(self, "DVDPlayerActions",
279                         {
280                                 #PLAYER ACTIONS
281                                 "dvdMenu": (self.enterDVDMenu, _("show DVD main menu")),
282                                 "toggleInfo": (self.toggleInfo, _("toggle time, chapter, audio, subtitle info")),
283                                 "nextChapter": (self.nextChapter, _("forward to the next chapter")),
284                                 "prevChapter": (self.prevChapter, _("rewind to the previous chapter")),
285                                 "nextTitle": (self.nextTitle, _("jump forward to the next title")),
286                                 "prevTitle": (self.prevTitle, _("jump back to the previous title")),
287                                 "tv": (self.askLeavePlayer, _("exit DVD player or return to file browser")),
288                                 "dvdAudioMenu": (self.enterDVDAudioMenu, _("(show optional DVD audio menu)")),
289                                 "nextAudioTrack": (self.nextAudioTrack, _("switch to the next audio track")),
290                                 "nextSubtitleTrack": (self.nextSubtitleTrack, _("switch to the next subtitle language")),
291                                 "seekBeginning": (self.seekBeginning, _("Jump to video title 1 (play movie from start)")),
292                         }, -2)
293                         
294                 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
295                         {
296                                 "1": self.keyNumberGlobal,
297                                 "2": self.keyNumberGlobal,
298                                 "3": self.keyNumberGlobal,
299                                 "4": self.keyNumberGlobal,
300                                 "5": self.keyNumberGlobal,
301                                 "6": self.keyNumberGlobal,
302                                 "7": self.keyNumberGlobal,
303                                 "8": self.keyNumberGlobal,
304                                 "9": self.keyNumberGlobal,
305                                 "0": self.keyNumberGlobal,
306                         })
307
308                 self.onClose.append(self.__onClose)
309                 self.onFirstExecBegin.append(self.showFileBrowser)
310                 self.service = None
311                 self.in_menu = False
312                 
313         def keyNumberGlobal(self, number):
314                 print "You pressed number " + str(number)
315                 self.session.openWithCallback(self.numberEntered, ChapterZap, number)
316
317         def numberEntered(self, retval):
318 #               print self.servicelist
319                 if retval > 0:
320                         self.zapToNumber(retval)
321
322         def serviceStarted(self): #override InfoBarShowHide function
323                 pass
324
325         def doEofInternal(self, playing):
326                 if self.in_menu:
327                         self.hide()
328
329         def __menuOpened(self):
330                 self.hide()
331                 self.in_menu = True
332
333         def __menuClosed(self):
334                 self.show()
335                 self.in_menu = False
336
337         def setChapterLabel(self):
338                 chapterLCD = "Menu"
339                 chapterOSD = "DVD Menu"
340                 if self.currentTitle > 0:
341                         chapterLCD = "%s %d" % (_("Chap."), self.currentChapter)
342                         chapterOSD = "DVD %s %d/%d" % (_("Chapter"), self.currentChapter, self.totalChapters)
343                         chapterOSD += " (%s %d/%d)" % (_("Title"), self.currentTitle, self.totalTitles)
344                 self["chapterLabel"].setText(chapterOSD)
345                 try:
346                         self.session.summary.updateChapter(chapterLCD)
347                 except:
348                         pass
349
350         def doNothing(self):
351                 pass
352
353         def toggleInfo(self):
354                 if not self.in_menu:
355                         self.toggleShow()
356                         print "toggleInfo"
357
358         def __timeUpdated(self):
359                 print "timeUpdated"
360
361         def __statePlay(self):
362                 print "statePlay"
363
364         def __statePause(self):
365                 print "statePause"
366
367         def __osdFFwdInfoAvail(self):
368                 self.setChapterLabel()
369                 print "FFwdInfoAvail"
370
371         def __osdFBwdInfoAvail(self):
372                 self.setChapterLabel()
373                 print "FBwdInfoAvail"
374
375         def __osdStringAvail(self):
376                 print "StringAvail"
377
378         def __osdAudioInfoAvail(self):
379                 audioString = self.service.info().getInfoString(iPlayableService.evUser+6)
380                 print "AudioInfoAvail "+audioString
381                 self["audioLabel"].setText(audioString)
382                 if not self.in_menu:
383                         self.doShow()
384
385         def __osdSubtitleInfoAvail(self):
386                 subtitleString = self.service.info().getInfoString(iPlayableService.evUser+7)
387                 print "SubtitleInfoAvail "+subtitleString
388                 self["subtitleLabel"].setText(subtitleString)
389                 if not self.in_menu:
390                         self.doShow()
391
392         def __chapterUpdated(self):
393                 self.currentChapter = self.service.info().getInfo(iPlayableService.evUser+8)
394                 self.totalChapters = self.service.info().getInfo(iPlayableService.evUser+80)
395                 self.setChapterLabel()
396                 print "__chapterUpdated: %d/%d" % (self.currentChapter, self.totalChapters)
397
398         def __titleUpdated(self):
399                 self.currentTitle = self.service.info().getInfo(iPlayableService.evUser+9)
400                 self.totalTitles = self.service.info().getInfo(iPlayableService.evUser+90)
401                 self.setChapterLabel()
402                 print "__titleUpdated: %d/%d" % (self.currentTitle, self.totalTitles)
403                 if not self.in_menu:
404                         self.doShow()
405                 
406         #def __initializeDVDinfo(self):
407                 #self.__osdAudioInfoAvail()
408                 #self.__osdSubtitleInfoAvail()
409
410         def askLeavePlayer(self):
411                 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list=[(_("Exit"), "exit"), (_("Return to file browser"), "browser"), (_("Continue playing"), "play")])
412
413         def nextAudioTrack(self):
414                 if self.service:
415                         self.service.keys().keyPressed(iServiceKeys.keyUser)
416
417         def nextSubtitleTrack(self):
418                 if self.service:
419                         self.service.keys().keyPressed(iServiceKeys.keyUser+1)
420
421         def enterDVDAudioMenu(self):
422                 if self.service:
423                         self.service.keys().keyPressed(iServiceKeys.keyUser+2)
424
425         def nextChapter(self):
426                 if self.service:
427                         self.service.keys().keyPressed(iServiceKeys.keyUser+3)
428
429         def prevChapter(self):
430                 if self.service:
431                         self.service.keys().keyPressed(iServiceKeys.keyUser+4)
432
433         def nextTitle(self):
434                 if self.service:
435                         self.service.keys().keyPressed(iServiceKeys.keyUser+5)
436
437         def prevTitle(self):
438                 if self.service:
439                         self.service.keys().keyPressed(iServiceKeys.keyUser+6)
440
441         def enterDVDMenu(self):
442                 if self.service:
443                         self.service.keys().keyPressed(iServiceKeys.keyUser+7)
444                         
445         def seekBeginning(self):
446                 if self.service:
447                         seekable = self.getSeek()
448                         if seekable is not None:
449                                 seekable.seekTo(0)
450                                 
451         def zapToNumber(self, number):
452                 if self.service:
453                         seekable = self.getSeek()
454                         if seekable is not None:
455                                 print "seek to chapter %d" % number
456                                 seekable.seekChapter(number)
457
458 #       MENU ACTIONS
459         def keyRight(self):
460                 if self.service:
461                         self.service.keys().keyPressed(iServiceKeys.keyRight)
462
463         def keyLeft(self):
464                 if self.service:
465                         self.service.keys().keyPressed(iServiceKeys.keyLeft)
466
467         def keyUp(self):
468                 if self.service:
469                         self.service.keys().keyPressed(iServiceKeys.keyUp)
470
471         def keyDown(self):
472                 if self.service:
473                         self.service.keys().keyPressed(iServiceKeys.keyDown)
474
475         def keyOk(self):
476                 if self.service:
477                         self.service.keys().keyPressed(iServiceKeys.keyOk)
478
479         def keyCancel(self):
480                 self.askLeavePlayer()
481
482         def showFileBrowser(self):
483                 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
484
485         def FileBrowserClosed(self, val):
486                 curref = self.session.nav.getCurrentlyPlayingServiceReference()
487                 print "FileBrowserClosed", val
488                 if val is None:
489                         self.askLeavePlayer()
490                 else:
491                         newref = eServiceReference(4369, 0, val)
492                         print "play", newref.toString()
493                         if curref is None or curref != newref:
494                                 self.session.nav.playService(newref)
495                                 self.service = self.session.nav.getCurrentService()
496                                 print "self.service", self.service
497                                 print "cur_dlg", self.session.current_dialog
498                                 self.dvdScreen.show()
499                                 self.service.subtitle().enableSubtitles(self.dvdScreen.instance, None)
500
501         def exitCB(self, answer):
502                 if answer is not None:
503                         if answer[1] == "exit":
504                                 if self.service:
505                                         self.dvdScreen.hide()
506                                         self.service.subtitle().disableSubtitles(self.session.current_dialog.instance)
507                                         self.service = None
508                                 self.close()
509                         if answer[1] == "browser":
510                                 #TODO check here if a paused dvd playback is already running... then re-start it...
511                                 #else
512                                 self.showFileBrowser()
513                         else:
514                                 pass
515
516         def __onClose(self):
517                 self.restore_infobar_seek_config()
518                 self.session.nav.playService(self.oldService)
519
520         def showAfterCuesheetOperation(self):
521                 if not self.in_menu:
522                         self.show()
523
524         def createSummary(self):
525                 print "DVDCreateSummary"
526                 return DVDSummary
527
528 def main(session, **kwargs):
529         session.open(DVDPlayer)
530
531 def menu(menuid, **kwargs):
532         if menuid == "mainmenu":
533                 return [(_("DVD Player"), main, "dvd_player", 46)]
534         return []
535
536 from Plugins.Plugin import PluginDescriptor
537 def Plugins(**kwargs):
538         return [PluginDescriptor(name = "DVDPlayer", description = "Play DVDs", where = PluginDescriptor.WHERE_MENU, fnc = menu)]