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, InfoBarBase
14 from Components.config import config
15 from Components.ProgressBar import ProgressBar
16 from ServiceReference import ServiceReference
17 from Tools.Directories import pathExists, fileExists
20 import servicedvd # load c++ part of dvd player plugin
24 class FileBrowser(Screen):
26 <screen name="FileBrowser" position="100,100" size="520,376" title="DVD File Browser" >
27 <widget name="filelist" position="0,0" size="520,376" scrollbarMode="showOnDemand" />
29 def __init__(self, session):
30 Screen.__init__(self, session)
32 if lastpath is not None:
33 currDir = lastpath + "/"
35 currDir = "/media/dvd/"
36 if not pathExists(currDir):
39 #print system("mount "+currDir)
40 self.filelist = FileList(currDir, matchingPattern = "(?i)^.*\.(iso)", useServiceRef = True)
41 self["filelist"] = self.filelist
43 self["FilelistActions"] = ActionMap(["OkCancelActions"],
51 filename = self["filelist"].getFilename()
52 if filename is not None:
53 lastpath = filename[0:filename.rfind("/")]
54 if filename.upper().endswith("VIDEO_TS/"):
55 print "dvd structure found, trying to open..."
56 self.close(filename[0:-9])
57 if self["filelist"].canDescent(): # isDir
58 self["filelist"].descent()
65 class DVDSummary(Screen):
67 <screen position="0,0" size="132,64">
68 <widget source="session.CurrentService" render="Label" position="5,4" size="120,28" font="Regular;12" transparent="1" >
69 <convert type="ServiceName">Name</convert>
71 <widget name="DVDPlayer" position="5,30" size="66,16" font="Regular;12" transparent="1" />
72 <widget name="Chapter" position="72,30" size="54,16" font="Regular;12" transparent="1" halign="right" />
73 <widget source="session.CurrentService" render="Label" position="66,46" size="60,18" font="Regular;16" transparent="1" halign="right" >
74 <convert type="ServicePosition">Position</convert>
76 <widget source="session.CurrentService" render="Progress" position="6,46" size="60,18" borderWidth="1" >
77 <convert type="ServicePosition">Position</convert>
81 def __init__(self, session, parent):
82 Screen.__init__(self, session, parent)
84 self["DVDPlayer"] = Label("DVD Player")
85 self["Title"] = Label("")
86 self["Time"] = Label("")
87 self["Chapter"] = Label("")
89 def updateChapter(self, chapter):
90 self["Chapter"].setText(chapter)
92 def setTitle(self, title):
93 self["Title"].setText(title)
95 class DVDOverlay(Screen):
96 skin = """<screen name="DVDOverlay" position="0,0" size="720,576" flags="wfNoBorder" zPosition="-1" backgroundColor="transparent" />"""
97 def __init__(self, session, args = None):
98 Screen.__init__(self, session)
100 class ChapterZap(Screen):
102 <screen name="ChapterZap" position="235,255" size="250,60" title="Chapter" >
103 <widget name="chapter" position="35,15" size="110,25" font="Regular;23" />
104 <widget name="number" position="145,15" size="80,25" halign="right" font="Regular;23" />
113 self.close(int(self["number"].getText()))
115 def keyNumberGlobal(self, number):
116 self.Timer.start(3000, True) #reset timer
117 self.field = self.field + str(number)
118 self["number"].setText(self.field)
119 if len(self.field) >= 4:
122 def __init__(self, session, number):
123 Screen.__init__(self, session)
124 self.field = str(number)
126 self["chapter"] = Label(_("Chapter:"))
128 self["number"] = Label(self.field)
130 self["actions"] = NumberActionMap( [ "SetupActions" ],
134 "1": self.keyNumberGlobal,
135 "2": self.keyNumberGlobal,
136 "3": self.keyNumberGlobal,
137 "4": self.keyNumberGlobal,
138 "5": self.keyNumberGlobal,
139 "6": self.keyNumberGlobal,
140 "7": self.keyNumberGlobal,
141 "8": self.keyNumberGlobal,
142 "9": self.keyNumberGlobal,
143 "0": self.keyNumberGlobal
146 self.Timer = eTimer()
147 self.Timer.callback.append(self.keyOK)
148 self.Timer.start(3000, True)
150 class DVDPlayer(Screen, InfoBarBase, InfoBarNotifications, InfoBarSeek, InfoBarPVRState, InfoBarShowHide, HelpableScreen):
151 #InfoBarCueSheetSupport,
152 # ALLOW_SUSPEND = True
153 # ENABLE_RESUME_SUPPORT = True
156 <screen name="DVDPlayer" flags="wfNoBorder" position="0,380" size="720,160" title="InfoBar" backgroundColor="transparent" >
158 <ePixmap position="0,0" zPosition="-2" size="720,160" pixmap="skin_default/info-bg_mp.png" alphatest="off" />
159 <ePixmap position="29,40" zPosition="0" size="665,104" pixmap="skin_default/screws_mp.png" alphatest="on" transparent="1" />
160 <!-- colorbuttons -->
161 <ePixmap position="48,70" zPosition="0" size="108,13" pixmap="skin_default/icons/mp_buttons.png" alphatest="on" />
163 <ePixmap pixmap="skin_default/icons/icon_event.png" position="207,78" zPosition="1" size="15,10" alphatest="on" />
164 <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">
165 <convert type="ServiceName">Name</convert>
167 <!-- Chapter info -->
168 <widget name="chapterLabel" position="230,96" size="360,22" font="Regular;20" foregroundColor="#c3c3c9" backgroundColor="#263c59" transparent="1" />
169 <!-- Audio track info -->
170 <ePixmap pixmap="skin_default/icons/icon_dolby.png" position="540,73" zPosition="1" size="26,16" alphatest="on"/>
171 <widget name="audioLabel" position="570,73" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
172 <!-- Subtitle track info -->
173 <widget source="session.CurrentService" render="Pixmap" pixmap="skin_default/icons/icon_txt.png" position="540,96" zPosition="1" size="26,16" alphatest="on" >
174 <convert type="ServiceInfo">HasTelext</convert>
175 <convert type="ConditionalShowHide" />
177 <widget name="subtitleLabel" position="570,96" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
178 <!-- Elapsed time -->
179 <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" >
180 <convert type="ServicePosition">Position,ShowHours</convert>
182 <!-- Progressbar (movie position)-->
183 <widget source="session.CurrentService" render="PositionGauge" position="300,133" size="270,10" zPosition="2" pointer="skin_default/position_pointer.png:540,0" transparent="1" >
184 <convert type="ServicePosition">Gauge</convert>
186 <!-- Remaining time -->
187 <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" >
188 <convert type="ServicePosition">Remaining,Negate,ShowHours</convert>
192 def save_infobar_seek_config(self):
193 self.saved_config_speeds_forward = config.seek.speeds_forward.value
194 self.saved_config_speeds_backward = config.seek.speeds_backward.value
195 self.saved_config_enter_forward = config.seek.enter_forward.value
196 self.saved_config_enter_backward = config.seek.enter_backward.value
197 self.saved_config_seek_stepwise_minspeed = config.seek.stepwise_minspeed.value
198 self.saved_config_seek_stepwise_repeat = config.seek.stepwise_repeat.value
199 self.saved_config_seek_on_pause = config.seek.on_pause.value
200 self.saved_config_seek_speeds_slowmotion = config.seek.speeds_slowmotion.value
202 def change_infobar_seek_config(self):
203 config.seek.speeds_forward.value = [2, 4, 8, 16, 32, 64]
204 config.seek.speeds_backward.value = [8, 16, 32, 64]
205 config.seek.speeds_slowmotion.value = [ ]
206 config.seek.enter_forward.value = "2"
207 config.seek.enter_backward.value = "2"
208 config.seek.stepwise_minspeed.value = "Never"
209 config.seek.stepwise_repeat.value = "3"
210 config.seek.on_pause.value = "play"
212 def restore_infobar_seek_config(self):
213 config.seek.speeds_forward.value = self.saved_config_speeds_forward
214 config.seek.speeds_backward.value = self.saved_config_speeds_backward
215 config.seek.speeds_slowmotion.value = self.saved_config_seek_speeds_slowmotion
216 config.seek.enter_forward.value = self.saved_config_enter_forward
217 config.seek.enter_backward.value = self.saved_config_enter_backward
218 config.seek.stepwise_minspeed.value = self.saved_config_seek_stepwise_minspeed
219 config.seek.stepwise_repeat.value = self.saved_config_seek_stepwise_repeat
220 config.seek.on_pause.value = self.saved_config_seek_on_pause
222 def __init__(self, session, args = None):
223 Screen.__init__(self, session)
224 InfoBarBase.__init__(self)
225 InfoBarNotifications.__init__(self)
226 # InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions")
227 InfoBarShowHide.__init__(self)
228 HelpableScreen.__init__(self)
229 self.save_infobar_seek_config()
230 self.change_infobar_seek_config()
231 InfoBarSeek.__init__(self, useSeekBackHack=False)
232 InfoBarPVRState.__init__(self)
233 self.dvdScreen = self.session.instantiateDialog(DVDOverlay)
235 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
236 self.session.nav.stopService()
237 self["audioLabel"] = Label("1")
238 self["subtitleLabel"] = Label("")
239 self["chapterLabel"] = Label("")
240 self.totalChapters = 0
241 self.currentChapter = 0
243 self.currentTitle = 0
245 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
247 iPlayableService.evStopped: self.__serviceStopped,
248 iPlayableService.evUser: self.__timeUpdated,
249 iPlayableService.evUser+1: self.__statePlay,
250 iPlayableService.evUser+2: self.__statePause,
251 iPlayableService.evUser+3: self.__osdFFwdInfoAvail,
252 iPlayableService.evUser+4: self.__osdFBwdInfoAvail,
253 iPlayableService.evUser+5: self.__osdStringAvail,
254 iPlayableService.evUser+6: self.__osdAudioInfoAvail,
255 iPlayableService.evUser+7: self.__osdSubtitleInfoAvail,
256 iPlayableService.evUser+8: self.__chapterUpdated,
257 iPlayableService.evUser+9: self.__titleUpdated,
258 #iPlayableService.evUser+10: self.__initializeDVDinfo,
259 iPlayableService.evUser+11: self.__menuOpened,
260 iPlayableService.evUser+12: self.__menuClosed
263 self["DVDPlayerDirectionActions"] = HelpableActionMap(self, "DirectionActions",
265 #MENU KEY DOWN ACTIONS
266 "left": (self.keyLeft, _("DVD left key")),
267 "right": (self.keyRight, _("DVD right key")),
268 "up": (self.keyUp, _("DVD up key")),
269 "down": (self.keyDown, _("DVD down key")),
271 #MENU KEY REPEATED ACTIONS
272 "leftRepeated": self.doNothing,
273 "rightRepeated": self.doNothing,
274 "upRepeated": self.doNothing,
275 "downRepeated": self.doNothing,
278 "leftUp": self.doNothing,
279 "rightUp": self.doNothing,
280 "upUp": self.doNothing,
281 "downUp": self.doNothing,
284 self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions",
286 "ok": (self.keyOk, _("DVD ENTER key")),
287 "cancel": self.keyCancel,
290 self["DVDPlayerPlaybackActions"] = HelpableActionMap(self, "DVDPlayerActions",
293 "dvdMenu": (self.enterDVDMenu, _("show DVD main menu")),
294 "toggleInfo": (self.toggleInfo, _("toggle time, chapter, audio, subtitle info")),
295 "nextChapter": (self.nextChapter, _("forward to the next chapter")),
296 "prevChapter": (self.prevChapter, _("rewind to the previous chapter")),
297 "nextTitle": (self.nextTitle, _("jump forward to the next title")),
298 "prevTitle": (self.prevTitle, _("jump back to the previous title")),
299 "tv": (self.askLeavePlayer, _("exit DVD player or return to file browser")),
300 "dvdAudioMenu": (self.enterDVDAudioMenu, _("(show optional DVD audio menu)")),
301 "nextAudioTrack": (self.nextAudioTrack, _("switch to the next audio track")),
302 "nextSubtitleTrack": (self.nextSubtitleTrack, _("switch to the next subtitle language")),
303 "seekBeginning": (self.seekBeginning, _("Jump to video title 1 (play movie from start)")),
306 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
308 "1": self.keyNumberGlobal,
309 "2": self.keyNumberGlobal,
310 "3": self.keyNumberGlobal,
311 "4": self.keyNumberGlobal,
312 "5": self.keyNumberGlobal,
313 "6": self.keyNumberGlobal,
314 "7": self.keyNumberGlobal,
315 "8": self.keyNumberGlobal,
316 "9": self.keyNumberGlobal,
317 "0": self.keyNumberGlobal,
320 self.onClose.append(self.__onClose)
321 self.onFirstExecBegin.append(self.showFileBrowser)
324 self.old_aspect = open("/proc/stb/video/aspect", "r").read()
325 self.old_policy = open("/proc/stb/video/policy", "r").read()
326 self.old_wss = open("/proc/stb/denc/0/wss", "r").read()
328 def keyNumberGlobal(self, number):
329 print "You pressed number " + str(number)
330 self.session.openWithCallback(self.numberEntered, ChapterZap, number)
332 def numberEntered(self, retval):
333 # print self.servicelist
335 self.zapToNumber(retval)
337 def __serviceStopped(self):
338 self.dvdScreen.hide()
339 self.service.subtitle().disableSubtitles(self.session.current_dialog.instance)
341 def serviceStarted(self): #override InfoBarShowHide function
342 self.dvdScreen.show()
343 self.service.subtitle().enableSubtitles(self.dvdScreen.instance, None)
345 def doEofInternal(self, playing):
349 def __menuOpened(self):
352 self["NumberActions"].setEnabled(False)
354 def __menuClosed(self):
357 self["NumberActions"].setEnabled(True)
359 def setChapterLabel(self):
361 chapterOSD = "DVD Menu"
362 if self.currentTitle > 0:
363 chapterLCD = "%s %d" % (_("Chap."), self.currentChapter)
364 chapterOSD = "DVD %s %d/%d" % (_("Chapter"), self.currentChapter, self.totalChapters)
365 chapterOSD += " (%s %d/%d)" % (_("Title"), self.currentTitle, self.totalTitles)
366 self["chapterLabel"].setText(chapterOSD)
368 self.session.summary.updateChapter(chapterLCD)
375 def toggleInfo(self):
380 def __timeUpdated(self):
383 def __statePlay(self):
386 def __statePause(self):
389 def __osdFFwdInfoAvail(self):
390 self.setChapterLabel()
391 print "FFwdInfoAvail"
393 def __osdFBwdInfoAvail(self):
394 self.setChapterLabel()
395 print "FBwdInfoAvail"
397 def __osdStringAvail(self):
400 def __osdAudioInfoAvail(self):
401 audioString = self.service.info().getInfoString(iServiceInformation.sUser+6)
402 print "AudioInfoAvail "+audioString
403 self["audioLabel"].setText(audioString)
407 def __osdSubtitleInfoAvail(self):
408 subtitleString = self.service.info().getInfoString(iServiceInformation.sUser+7)
409 print "SubtitleInfoAvail "+subtitleString
410 self["subtitleLabel"].setText(subtitleString)
414 def __chapterUpdated(self):
415 self.currentChapter = self.service.info().getInfo(iServiceInformation.sUser+8)
416 self.totalChapters = self.service.info().getInfo(iServiceInformation.sUser+80)
417 self.setChapterLabel()
418 print "__chapterUpdated: %d/%d" % (self.currentChapter, self.totalChapters)
420 def __titleUpdated(self):
421 self.currentTitle = self.service.info().getInfo(iServiceInformation.sUser+9)
422 self.totalTitles = self.service.info().getInfo(iServiceInformation.sUser+90)
423 self.setChapterLabel()
424 print "__titleUpdated: %d/%d" % (self.currentTitle, self.totalTitles)
428 #def __initializeDVDinfo(self):
429 #self.__osdAudioInfoAvail()
430 #self.__osdSubtitleInfoAvail()
432 def askLeavePlayer(self):
433 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list=[(_("Exit"), "exit"), (_("Return to file browser"), "browser"), (_("Continue playing"), "play")])
435 def nextAudioTrack(self):
437 self.service.keys().keyPressed(iServiceKeys.keyUser)
439 def nextSubtitleTrack(self):
441 self.service.keys().keyPressed(iServiceKeys.keyUser+1)
443 def enterDVDAudioMenu(self):
445 self.service.keys().keyPressed(iServiceKeys.keyUser+2)
447 def nextChapter(self):
449 self.service.keys().keyPressed(iServiceKeys.keyUser+3)
451 def prevChapter(self):
453 self.service.keys().keyPressed(iServiceKeys.keyUser+4)
457 self.service.keys().keyPressed(iServiceKeys.keyUser+5)
461 self.service.keys().keyPressed(iServiceKeys.keyUser+6)
463 def enterDVDMenu(self):
465 self.service.keys().keyPressed(iServiceKeys.keyUser+7)
467 def seekBeginning(self):
469 seekable = self.getSeek()
470 if seekable is not None:
473 def zapToNumber(self, number):
475 seekable = self.getSeek()
476 if seekable is not None:
477 print "seek to chapter %d" % number
478 seekable.seekChapter(number)
483 self.service.keys().keyPressed(iServiceKeys.keyRight)
487 self.service.keys().keyPressed(iServiceKeys.keyLeft)
491 self.service.keys().keyPressed(iServiceKeys.keyUp)
495 self.service.keys().keyPressed(iServiceKeys.keyDown)
501 self.service.keys().keyPressed(iServiceKeys.keyOk)
504 self.askLeavePlayer()
506 def showFileBrowser(self):
507 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
509 def FileBrowserClosed(self, val):
510 curref = self.session.nav.getCurrentlyPlayingServiceReference()
511 print "FileBrowserClosed", val
513 self.askLeavePlayer()
515 newref = eServiceReference(4369, 0, val)
516 print "play", newref.toString()
517 if curref is None or curref != newref:
518 self.session.nav.playService(newref)
519 self.service = self.session.nav.getCurrentService()
520 print "self.service", self.service
521 print "cur_dlg", self.session.current_dialog
523 def exitCB(self, answer):
524 if answer is not None:
525 if answer[1] == "exit":
529 if answer[1] == "browser":
530 #TODO check here if a paused dvd playback is already running... then re-start it...
532 self.showFileBrowser()
537 for i in (("/proc/stb/video/aspect", self.old_aspect), ("/proc/stb/video/policy", self.old_policy), ("/proc/stb/denc/0/wss", self.old_wss)):
539 open(i[0], "w").write(i[1])
541 print "restore", i[0], "failed"
542 self.restore_infobar_seek_config()
543 self.session.nav.playService(self.oldService)
545 # def playLastCB(self, answer): # overwrite infobar cuesheet function
546 # print "playLastCB", answer, self.resume_point
547 # pos = self.resume_point
548 # title = self.resume_point % 90000
550 # chapter = title % 256
552 # print "pos", pos, "title", title, "chapter", chapter
554 # seek = self.service.seek()
556 # seek.seekTitle(title)
557 # self.resume_state = 1
559 # seek.seekChapter(chapter)
560 # self.resume_state = 2
563 # self.hideAfterResume()
565 def showAfterCuesheetOperation(self):
569 def createSummary(self):
570 print "DVDCreateSummary"
573 #override some InfoBarSeek functions
575 self.setSeekState(self.SEEK_STATE_PLAY)
577 def calcRemainingTime(self):
580 def main(session, **kwargs):
581 session.open(DVDPlayer)
583 def menu(menuid, **kwargs):
584 if menuid == "mainmenu":
585 return [(_("DVD Player"), main, "dvd_player", 46)]
588 from Plugins.Plugin import PluginDescriptor
589 def Plugins(**kwargs):
590 return [PluginDescriptor(name = "DVDPlayer", description = "Play DVDs", where = PluginDescriptor.WHERE_MENU, fnc = menu)]