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
3 from Screens.Screen import Screen
4 from Screens.MessageBox import MessageBox
5 from Screens.ChoiceBox import ChoiceBox
6 from Screens.HelpMenu import HelpableScreen
7 from Screens.InfoBarGenerics import InfoBarSeek, InfoBarPVRState, InfoBarCueSheetSupport, InfoBarShowHide, InfoBarNotifications
8 from Components.ActionMap import ActionMap, NumberActionMap, HelpableActionMap
9 from Components.Label import Label
10 from Components.FileList import FileList
11 from Components.MenuList import MenuList
12 from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
13 from Components.config import config
14 from Tools.Directories import pathExists, fileExists
16 import servicedvd # load c++ part of dvd player plugin
20 class FileBrowser(Screen):
22 <screen name="FileBrowser" position="100,100" size="520,376" title="DVD File Browser" >
23 <widget name="filelist" position="0,0" size="520,376" scrollbarMode="showOnDemand" />
25 def __init__(self, session, dvd_filelist = None):
26 Screen.__init__(self, session)
29 self.dvd_filelist = dvd_filelist
30 self["filelist"] = MenuList(self.dvd_filelist)
33 self.dvd_filelist = None
35 if lastpath is not None:
36 currDir = lastpath + "/"
38 currDir = "/media/dvd/"
39 if not pathExists(currDir):
42 self.filelist = FileList(currDir, matchingPattern = "(?i)^.*\.(iso)", useServiceRef = True)
43 self["filelist"] = self.filelist
45 self["FilelistActions"] = ActionMap(["OkCancelActions"],
53 print "OK " + self["filelist"].getCurrent()
54 self.close(self["filelist"].getCurrent())
57 filename = self["filelist"].getFilename()
58 if filename is not None:
59 lastpath = filename[0:filename.rfind("/")]
60 if filename.upper().endswith("VIDEO_TS/"):
61 print "dvd structure found, trying to open..."
62 self.close(filename[0:-9])
63 if self["filelist"].canDescent(): # isDir
64 self["filelist"].descent()
65 pathname = self["filelist"].getCurrentDirectory() or ""
66 if fileExists(pathname+"VIDEO_TS.IFO"):
67 print "dvd structure found, trying to open..."
75 class DVDSummary(Screen):
77 <screen position="0,0" size="132,64">
78 <widget source="session.CurrentService" render="Label" position="5,4" size="120,28" font="Regular;12" transparent="1" >
79 <convert type="ServiceName">Name</convert>
81 <widget name="DVDPlayer" position="5,30" size="66,16" font="Regular;12" transparent="1" />
82 <widget name="Chapter" position="72,30" size="54,16" font="Regular;12" transparent="1" halign="right" />
83 <widget source="session.CurrentService" render="Label" position="66,46" size="60,18" font="Regular;16" transparent="1" halign="right" >
84 <convert type="ServicePosition">Position</convert>
86 <widget source="session.CurrentService" render="Progress" position="6,46" size="60,18" borderWidth="1" >
87 <convert type="ServicePosition">Position</convert>
91 def __init__(self, session, parent):
92 Screen.__init__(self, session, parent)
94 self["DVDPlayer"] = Label("DVD Player")
95 self["Title"] = Label("")
96 self["Time"] = Label("")
97 self["Chapter"] = Label("")
99 def updateChapter(self, chapter):
100 self["Chapter"].setText(chapter)
102 def setTitle(self, title):
103 self["Title"].setText(title)
105 class DVDOverlay(Screen):
106 skin = """<screen name="DVDOverlay" position="0,0" size="720,576" flags="wfNoBorder" zPosition="-1" backgroundColor="transparent" />"""
107 def __init__(self, session, args = None):
108 Screen.__init__(self, session)
110 class ChapterZap(Screen):
112 <screen name="ChapterZap" position="235,255" size="250,60" title="Chapter" >
113 <widget name="chapter" position="35,15" size="110,25" font="Regular;23" />
114 <widget name="number" position="145,15" size="80,25" halign="right" font="Regular;23" />
123 self.close(int(self["number"].getText()))
125 def keyNumberGlobal(self, number):
126 self.Timer.start(3000, True) #reset timer
127 self.field = self.field + str(number)
128 self["number"].setText(self.field)
129 if len(self.field) >= 4:
132 def __init__(self, session, number):
133 Screen.__init__(self, session)
134 self.field = str(number)
136 self["chapter"] = Label(_("Chapter:"))
138 self["number"] = Label(self.field)
140 self["actions"] = NumberActionMap( [ "SetupActions" ],
144 "1": self.keyNumberGlobal,
145 "2": self.keyNumberGlobal,
146 "3": self.keyNumberGlobal,
147 "4": self.keyNumberGlobal,
148 "5": self.keyNumberGlobal,
149 "6": self.keyNumberGlobal,
150 "7": self.keyNumberGlobal,
151 "8": self.keyNumberGlobal,
152 "9": self.keyNumberGlobal,
153 "0": self.keyNumberGlobal
156 self.Timer = eTimer()
157 self.Timer.callback.append(self.keyOK)
158 self.Timer.start(3000, True)
160 class DVDPlayer(Screen, InfoBarBase, InfoBarNotifications, InfoBarSeek, InfoBarPVRState, InfoBarShowHide, HelpableScreen, InfoBarCueSheetSupport):
161 # ALLOW_SUSPEND = True
162 ENABLE_RESUME_SUPPORT = True
165 <screen name="DVDPlayer" flags="wfNoBorder" position="0,380" size="720,160" title="InfoBar" backgroundColor="transparent" >
167 <ePixmap position="0,0" zPosition="-2" size="720,160" pixmap="skin_default/info-bg_mp.png" alphatest="off" />
168 <ePixmap position="29,40" zPosition="0" size="665,104" pixmap="skin_default/screws_mp.png" alphatest="on" transparent="1" />
169 <!-- colorbuttons -->
170 <ePixmap position="48,70" zPosition="0" size="108,13" pixmap="skin_default/icons/mp_buttons.png" alphatest="on" />
172 <ePixmap pixmap="skin_default/icons/icon_event.png" position="207,78" zPosition="1" size="15,10" alphatest="on" />
173 <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">
174 <convert type="ServiceName">Name</convert>
176 <!-- Chapter info -->
177 <widget name="chapterLabel" position="230,96" size="360,22" font="Regular;20" foregroundColor="#c3c3c9" backgroundColor="#263c59" transparent="1" />
178 <!-- Audio track info -->
179 <ePixmap pixmap="skin_default/icons/icon_dolby.png" position="540,73" zPosition="1" size="26,16" alphatest="on"/>
180 <widget name="audioLabel" position="570,73" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
181 <!-- Subtitle track info -->
182 <widget source="session.CurrentService" render="Pixmap" pixmap="skin_default/icons/icon_txt.png" position="540,96" zPosition="1" size="26,16" alphatest="on" >
183 <convert type="ServiceInfo">HasTelext</convert>
184 <convert type="ConditionalShowHide" />
186 <widget name="subtitleLabel" position="570,96" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
187 <!-- Elapsed time -->
188 <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" >
189 <convert type="ServicePosition">Position,ShowHours</convert>
191 <!-- Progressbar (movie position)-->
192 <widget source="session.CurrentService" render="PositionGauge" position="300,133" size="270,10" zPosition="2" pointer="skin_default/position_pointer.png:540,0" transparent="1" >
193 <convert type="ServicePosition">Gauge</convert>
195 <!-- Remaining time -->
196 <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" >
197 <convert type="ServicePosition">Remaining,Negate,ShowHours</convert>
201 def save_infobar_seek_config(self):
202 self.saved_config_speeds_forward = config.seek.speeds_forward.value
203 self.saved_config_speeds_backward = config.seek.speeds_backward.value
204 self.saved_config_enter_forward = config.seek.enter_forward.value
205 self.saved_config_enter_backward = config.seek.enter_backward.value
206 self.saved_config_seek_stepwise_minspeed = config.seek.stepwise_minspeed.value
207 self.saved_config_seek_stepwise_repeat = config.seek.stepwise_repeat.value
208 self.saved_config_seek_on_pause = config.seek.on_pause.value
209 self.saved_config_seek_speeds_slowmotion = config.seek.speeds_slowmotion.value
211 def change_infobar_seek_config(self):
212 config.seek.speeds_forward.value = [2, 4, 8, 16, 32, 64]
213 config.seek.speeds_backward.value = [8, 16, 32, 64]
214 config.seek.speeds_slowmotion.value = [ ]
215 config.seek.enter_forward.value = "2"
216 config.seek.enter_backward.value = "2"
217 config.seek.stepwise_minspeed.value = "Never"
218 config.seek.stepwise_repeat.value = "3"
219 config.seek.on_pause.value = "play"
221 def restore_infobar_seek_config(self):
222 config.seek.speeds_forward.value = self.saved_config_speeds_forward
223 config.seek.speeds_backward.value = self.saved_config_speeds_backward
224 config.seek.speeds_slowmotion.value = self.saved_config_seek_speeds_slowmotion
225 config.seek.enter_forward.value = self.saved_config_enter_forward
226 config.seek.enter_backward.value = self.saved_config_enter_backward
227 config.seek.stepwise_minspeed.value = self.saved_config_seek_stepwise_minspeed
228 config.seek.stepwise_repeat.value = self.saved_config_seek_stepwise_repeat
229 config.seek.on_pause.value = self.saved_config_seek_on_pause
231 def __init__(self, session, dvd_device = None, dvd_filelist = None, args = None):
232 Screen.__init__(self, session)
233 InfoBarBase.__init__(self)
234 InfoBarNotifications.__init__(self)
235 InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions")
236 InfoBarShowHide.__init__(self)
237 HelpableScreen.__init__(self)
238 self.save_infobar_seek_config()
239 self.change_infobar_seek_config()
240 InfoBarSeek.__init__(self, useSeekBackHack=False)
241 InfoBarPVRState.__init__(self)
242 self.dvdScreen = self.session.instantiateDialog(DVDOverlay)
244 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
245 self.session.nav.stopService()
246 self["audioLabel"] = Label("n/a")
247 self["subtitleLabel"] = Label("")
248 self["chapterLabel"] = Label("")
249 self.totalChapters = 0
250 self.currentChapter = 0
252 self.currentTitle = 0
254 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
256 iPlayableService.evStopped: self.__serviceStopped,
257 iPlayableService.evUser: self.__timeUpdated,
258 iPlayableService.evUser+1: self.__statePlay,
259 iPlayableService.evUser+2: self.__statePause,
260 iPlayableService.evUser+3: self.__osdFFwdInfoAvail,
261 iPlayableService.evUser+4: self.__osdFBwdInfoAvail,
262 iPlayableService.evUser+5: self.__osdStringAvail,
263 iPlayableService.evUser+6: self.__osdAudioInfoAvail,
264 iPlayableService.evUser+7: self.__osdSubtitleInfoAvail,
265 iPlayableService.evUser+8: self.__chapterUpdated,
266 iPlayableService.evUser+9: self.__titleUpdated,
267 iPlayableService.evUser+11: self.__menuOpened,
268 iPlayableService.evUser+12: self.__menuClosed
271 self["DVDPlayerDirectionActions"] = HelpableActionMap(self, "DirectionActions",
273 #MENU KEY DOWN ACTIONS
274 "left": (self.keyLeft, _("DVD left key")),
275 "right": (self.keyRight, _("DVD right key")),
276 "up": (self.keyUp, _("DVD up key")),
277 "down": (self.keyDown, _("DVD down key")),
279 #MENU KEY REPEATED ACTIONS
280 "leftRepeated": self.doNothing,
281 "rightRepeated": self.doNothing,
282 "upRepeated": self.doNothing,
283 "downRepeated": self.doNothing,
286 "leftUp": self.doNothing,
287 "rightUp": self.doNothing,
288 "upUp": self.doNothing,
289 "downUp": self.doNothing,
292 self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions",
294 "ok": (self.keyOk, _("DVD ENTER key")),
295 "cancel": self.keyCancel,
298 self["DVDPlayerPlaybackActions"] = HelpableActionMap(self, "DVDPlayerActions",
301 "dvdMenu": (self.enterDVDMenu, _("show DVD main menu")),
302 "toggleInfo": (self.toggleInfo, _("toggle time, chapter, audio, subtitle info")),
303 "nextChapter": (self.nextChapter, _("forward to the next chapter")),
304 "prevChapter": (self.prevChapter, _("rewind to the previous chapter")),
305 "nextTitle": (self.nextTitle, _("jump forward to the next title")),
306 "prevTitle": (self.prevTitle, _("jump back to the previous title")),
307 "tv": (self.askLeavePlayer, _("exit DVD player or return to file browser")),
308 "dvdAudioMenu": (self.enterDVDAudioMenu, _("(show optional DVD audio menu)")),
309 "nextAudioTrack": (self.nextAudioTrack, _("switch to the next audio track")),
310 "nextSubtitleTrack": (self.nextSubtitleTrack, _("switch to the next subtitle language")),
311 "seekBeginning": (self.seekBeginning, _("Jump to video title 1 (play movie from start)")),
314 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
316 "1": self.keyNumberGlobal,
317 "2": self.keyNumberGlobal,
318 "3": self.keyNumberGlobal,
319 "4": self.keyNumberGlobal,
320 "5": self.keyNumberGlobal,
321 "6": self.keyNumberGlobal,
322 "7": self.keyNumberGlobal,
323 "8": self.keyNumberGlobal,
324 "9": self.keyNumberGlobal,
325 "0": self.keyNumberGlobal,
328 self.onClose.append(self.__onClose)
331 self.dvd_device = dvd_device
332 self.physicalDVD = True
334 if fileExists("/dev/cdroms/cdrom0"):
335 print "physical dvd found (/dev/cdroms/cdrom0)"
336 self.dvd_device = "/dev/cdroms/cdrom0"
337 self.physicalDVD = True
339 self.dvd_device = None
340 self.physicalDVD = False
342 self.dvd_filelist = dvd_filelist
343 self.onFirstExecBegin.append(self.showFileBrowser)
346 self.old_aspect = open("/proc/stb/video/aspect", "r").read()
347 self.old_policy = open("/proc/stb/video/policy", "r").read()
348 self.old_wss = open("/proc/stb/denc/0/wss", "r").read()
350 def keyNumberGlobal(self, number):
351 print "You pressed number " + str(number)
352 self.session.openWithCallback(self.numberEntered, ChapterZap, number)
354 def numberEntered(self, retval):
355 # print self.servicelist
357 self.zapToNumber(retval)
359 def __serviceStopped(self):
360 self.dvdScreen.hide()
361 self.service.subtitle().disableSubtitles(self.session.current_dialog.instance)
363 def serviceStarted(self): #override InfoBarShowHide function
364 self.dvdScreen.show()
365 self.service.subtitle().enableSubtitles(self.dvdScreen.instance, None)
367 def doEofInternal(self, playing):
371 def __menuOpened(self):
374 self["NumberActions"].setEnabled(False)
376 def __menuClosed(self):
379 self["NumberActions"].setEnabled(True)
381 def setChapterLabel(self):
383 chapterOSD = "DVD Menu"
384 if self.currentTitle > 0:
385 chapterLCD = "%s %d" % (_("Chap."), self.currentChapter)
386 chapterOSD = "DVD %s %d/%d" % (_("Chapter"), self.currentChapter, self.totalChapters)
387 chapterOSD += " (%s %d/%d)" % (_("Title"), self.currentTitle, self.totalTitles)
388 self["chapterLabel"].setText(chapterOSD)
390 self.session.summary.updateChapter(chapterLCD)
397 def toggleInfo(self):
402 def __timeUpdated(self):
405 def __statePlay(self):
408 def __statePause(self):
411 def __osdFFwdInfoAvail(self):
412 self.setChapterLabel()
413 print "FFwdInfoAvail"
415 def __osdFBwdInfoAvail(self):
416 self.setChapterLabel()
417 print "FBwdInfoAvail"
419 def __osdStringAvail(self):
422 def __osdAudioInfoAvail(self):
423 audioTuple = self.service.info().getInfoObject(iServiceInformation.sUser+6)
424 print "AudioInfoAvail ", repr(audioTuple)
425 audioString = "%d: %s (%s)" % (audioTuple[0],audioTuple[1],audioTuple[2])
426 self["audioLabel"].setText(audioString)
430 def __osdSubtitleInfoAvail(self):
431 subtitleTuple = self.service.info().getInfoObject(iServiceInformation.sUser+7)
432 print "SubtitleInfoAvail ", repr(subtitleTuple)
434 if subtitleTuple[0] is not 0:
435 subtitleString = "%d: %s" % (subtitleTuple[0],subtitleTuple[1])
436 self["subtitleLabel"].setText(subtitleString)
440 def __chapterUpdated(self):
441 self.currentChapter = self.service.info().getInfo(iServiceInformation.sCurrentChapter)
442 self.totalChapters = self.service.info().getInfo(iServiceInformation.sTotalChapters)
443 self.setChapterLabel()
444 print "__chapterUpdated: %d/%d" % (self.currentChapter, self.totalChapters)
446 def __titleUpdated(self):
447 self.currentTitle = self.service.info().getInfo(iServiceInformation.sCurrentTitle)
448 self.totalTitles = self.service.info().getInfo(iServiceInformation.sTotalTitles)
449 self.setChapterLabel()
450 print "__titleUpdated: %d/%d" % (self.currentTitle, self.totalTitles)
454 def askLeavePlayer(self):
456 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list=[(_("Continue playing"), "play"), (_("Exit"), "exit")])
458 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list=[(_("Continue playing"), "play"), (_("Return to file browser"), "browser"), (_("Exit"), "exit")])
460 def nextAudioTrack(self):
462 self.service.keys().keyPressed(iServiceKeys.keyUser)
464 def nextSubtitleTrack(self):
466 self.service.keys().keyPressed(iServiceKeys.keyUser+1)
468 def enterDVDAudioMenu(self):
470 self.service.keys().keyPressed(iServiceKeys.keyUser+2)
472 def nextChapter(self):
474 self.service.keys().keyPressed(iServiceKeys.keyUser+3)
476 def prevChapter(self):
478 self.service.keys().keyPressed(iServiceKeys.keyUser+4)
482 self.service.keys().keyPressed(iServiceKeys.keyUser+5)
486 self.service.keys().keyPressed(iServiceKeys.keyUser+6)
488 def enterDVDMenu(self):
490 self.service.keys().keyPressed(iServiceKeys.keyUser+7)
492 def seekBeginning(self):
494 seekable = self.getSeek()
495 if seekable is not None:
498 def zapToNumber(self, number):
500 seekable = self.getSeek()
501 if seekable is not None:
502 print "seek to chapter %d" % number
503 seekable.seekChapter(number)
508 self.service.keys().keyPressed(iServiceKeys.keyRight)
512 self.service.keys().keyPressed(iServiceKeys.keyLeft)
516 self.service.keys().keyPressed(iServiceKeys.keyUp)
520 self.service.keys().keyPressed(iServiceKeys.keyDown)
526 self.service.keys().keyPressed(iServiceKeys.keyOk)
529 self.askLeavePlayer()
531 def showFileBrowser(self):
533 if self.dvd_device == "/dev/cdroms/cdrom0":
534 self.session.openWithCallback(self.DVDdriveCB, MessageBox, text=_("Do you want to play DVD in drive?"), timeout=5 )
536 self.DVDdriveCB(True)
538 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser, self.dvd_filelist)
540 def DVDdriveCB(self, answer):
542 self.FileBrowserClosed(self.dvd_device)
544 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
546 def FileBrowserClosed(self, val):
547 curref = self.session.nav.getCurrentlyPlayingServiceReference()
548 print "FileBrowserClosed", val
550 self.askLeavePlayer()
552 newref = eServiceReference(4369, 0, val)
553 print "play", newref.toString()
554 if curref is None or curref != newref:
555 self.session.nav.playService(newref)
556 self.service = self.session.nav.getCurrentService()
557 print "self.service", self.service
558 print "cur_dlg", self.session.current_dialog
560 def exitCB(self, answer):
561 if answer is not None:
562 if answer[1] == "exit":
566 if answer[1] == "browser":
567 #TODO check here if a paused dvd playback is already running... then re-start it...
571 self.showFileBrowser()
576 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)):
578 open(i[0], "w").write(i[1])
580 print "restore", i[0], "failed"
581 self.restore_infobar_seek_config()
582 self.session.nav.playService(self.oldService)
584 def playLastCB(self, answer): # overwrite infobar cuesheet function
585 print "playLastCB", answer, self.resume_point
587 seek = self.service.seek()
588 seek.seekTo(self.resume_point)
589 self.hideAfterResume()
591 def showAfterCuesheetOperation(self):
595 def createSummary(self):
598 #override some InfoBarSeek functions
600 self.setSeekState(self.SEEK_STATE_PLAY)
602 def calcRemainingTime(self):
605 def main(session, **kwargs):
606 session.open(DVDPlayer)
608 def menu(menuid, **kwargs):
609 if menuid == "mainmenu":
610 return [(_("DVD Player"), main, "dvd_player", 46)]
613 from Plugins.Plugin import PluginDescriptor
615 def filescan_open(list, session, **kwargs):
616 if len(list) == 1 and list[0].mimetype == "video/x-dvd":
617 splitted = list[0].path.split('/')
618 print "splitted", splitted
619 if len(splitted) > 2:
620 if splitted[1] == 'autofs':
621 session.open(DVDPlayer, dvd_device="/dev/%s" %(splitted[2]))
624 print "splitted[0]", splitted[1]
628 if x.mimetype == "video/x-dvd-iso":
629 dvd_filelist.append(x.path)
630 if x.mimetype == "video/x-dvd":
631 dvd_filelist.append(x.path.rsplit('/',1)[0])
632 session.open(DVDPlayer, dvd_filelist=dvd_filelist)
634 def filescan(**kwargs):
635 from Components.Scanner import Scanner, ScanPath
637 # Overwrite checkFile to only detect local
638 class LocalScanner(Scanner):
639 def checkFile(self, file):
640 return fileExists(file.path)
643 LocalScanner(mimetypes = ["video/x-dvd","video/x-dvd-iso"],
646 ScanPath(path = "video_ts", with_subdirs = False),
647 ScanPath(path = "", with_subdirs = False),
650 description = "Play DVD",
651 openfnc = filescan_open,
654 def Plugins(**kwargs):
655 return [PluginDescriptor(name = "DVDPlayer", description = "Play DVDs", where = PluginDescriptor.WHERE_MENU, fnc = menu),
656 PluginDescriptor(where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)]