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.last_audioTuple = None
250 self.last_subtitleTuple = None
251 self.totalChapters = 0
252 self.currentChapter = 0
254 self.currentTitle = 0
256 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
258 iPlayableService.evStopped: self.__serviceStopped,
259 iPlayableService.evUser: self.__timeUpdated,
260 iPlayableService.evUser+1: self.__statePlay,
261 iPlayableService.evUser+2: self.__statePause,
262 iPlayableService.evUser+3: self.__osdFFwdInfoAvail,
263 iPlayableService.evUser+4: self.__osdFBwdInfoAvail,
264 iPlayableService.evUser+5: self.__osdStringAvail,
265 iPlayableService.evUser+6: self.__osdAudioInfoAvail,
266 iPlayableService.evUser+7: self.__osdSubtitleInfoAvail,
267 iPlayableService.evUser+8: self.__chapterUpdated,
268 iPlayableService.evUser+9: self.__titleUpdated,
269 iPlayableService.evUser+11: self.__menuOpened,
270 iPlayableService.evUser+12: self.__menuClosed
273 self["DVDPlayerDirectionActions"] = HelpableActionMap(self, "DirectionActions",
275 #MENU KEY DOWN ACTIONS
276 "left": (self.keyLeft, _("DVD left key")),
277 "right": (self.keyRight, _("DVD right key")),
278 "up": (self.keyUp, _("DVD up key")),
279 "down": (self.keyDown, _("DVD down key")),
281 #MENU KEY REPEATED ACTIONS
282 "leftRepeated": self.doNothing,
283 "rightRepeated": self.doNothing,
284 "upRepeated": self.doNothing,
285 "downRepeated": self.doNothing,
288 "leftUp": self.doNothing,
289 "rightUp": self.doNothing,
290 "upUp": self.doNothing,
291 "downUp": self.doNothing,
294 self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions",
296 "ok": (self.keyOk, _("DVD ENTER key")),
297 "cancel": self.keyCancel,
300 self["DVDPlayerPlaybackActions"] = HelpableActionMap(self, "DVDPlayerActions",
303 "dvdMenu": (self.enterDVDMenu, _("show DVD main menu")),
304 "toggleInfo": (self.toggleInfo, _("toggle time, chapter, audio, subtitle info")),
305 "nextChapter": (self.nextChapter, _("forward to the next chapter")),
306 "prevChapter": (self.prevChapter, _("rewind to the previous chapter")),
307 "nextTitle": (self.nextTitle, _("jump forward to the next title")),
308 "prevTitle": (self.prevTitle, _("jump back to the previous title")),
309 "tv": (self.askLeavePlayer, _("exit DVD player or return to file browser")),
310 "dvdAudioMenu": (self.enterDVDAudioMenu, _("(show optional DVD audio menu)")),
311 "nextAudioTrack": (self.nextAudioTrack, _("switch to the next audio track")),
312 "nextSubtitleTrack": (self.nextSubtitleTrack, _("switch to the next subtitle language")),
313 "seekBeginning": (self.seekBeginning, _("Jump to video title 1 (play movie from start)")),
316 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
318 "1": self.keyNumberGlobal,
319 "2": self.keyNumberGlobal,
320 "3": self.keyNumberGlobal,
321 "4": self.keyNumberGlobal,
322 "5": self.keyNumberGlobal,
323 "6": self.keyNumberGlobal,
324 "7": self.keyNumberGlobal,
325 "8": self.keyNumberGlobal,
326 "9": self.keyNumberGlobal,
327 "0": self.keyNumberGlobal,
330 self.onClose.append(self.__onClose)
333 self.dvd_device = dvd_device
334 self.physicalDVD = True
336 if fileExists("/dev/cdroms/cdrom0"):
337 print "physical dvd found (/dev/cdroms/cdrom0)"
338 self.dvd_device = "/dev/cdroms/cdrom0"
339 self.physicalDVD = True
341 self.dvd_device = None
342 self.physicalDVD = False
344 self.dvd_filelist = dvd_filelist
345 self.onFirstExecBegin.append(self.showFileBrowser)
348 self.old_aspect = open("/proc/stb/video/aspect", "r").read()
349 self.old_policy = open("/proc/stb/video/policy", "r").read()
350 self.old_wss = open("/proc/stb/denc/0/wss", "r").read()
352 def keyNumberGlobal(self, number):
353 print "You pressed number " + str(number)
354 self.session.openWithCallback(self.numberEntered, ChapterZap, number)
356 def numberEntered(self, retval):
357 # print self.servicelist
359 self.zapToNumber(retval)
361 def __serviceStopped(self):
362 self.dvdScreen.hide()
363 self.service.subtitle().disableSubtitles(self.session.current_dialog.instance)
365 def serviceStarted(self): #override InfoBarShowHide function
366 self.dvdScreen.show()
367 self.service.subtitle().enableSubtitles(self.dvdScreen.instance, None)
369 def doEofInternal(self, playing):
373 def __menuOpened(self):
376 self["NumberActions"].setEnabled(False)
378 def __menuClosed(self):
381 self["NumberActions"].setEnabled(True)
383 def setChapterLabel(self):
385 chapterOSD = "DVD Menu"
386 if self.currentTitle > 0:
387 chapterLCD = "%s %d" % (_("Chap."), self.currentChapter)
388 chapterOSD = "DVD %s %d/%d" % (_("Chapter"), self.currentChapter, self.totalChapters)
389 chapterOSD += " (%s %d/%d)" % (_("Title"), self.currentTitle, self.totalTitles)
390 self["chapterLabel"].setText(chapterOSD)
392 self.session.summary.updateChapter(chapterLCD)
399 def toggleInfo(self):
404 def __timeUpdated(self):
407 def __statePlay(self):
410 def __statePause(self):
413 def __osdFFwdInfoAvail(self):
414 self.setChapterLabel()
415 print "FFwdInfoAvail"
417 def __osdFBwdInfoAvail(self):
418 self.setChapterLabel()
419 print "FBwdInfoAvail"
421 def __osdStringAvail(self):
424 def __osdAudioInfoAvail(self):
425 audioTuple = self.service.info().getInfoObject(iServiceInformation.sUser+6)
426 print "AudioInfoAvail ", repr(audioTuple)
427 audioString = "%d: %s (%s)" % (audioTuple[0],audioTuple[1],audioTuple[2])
428 self["audioLabel"].setText(audioString)
429 if audioTuple != self.last_audioTuple and not self.in_menu:
431 self.last_audioTuple = audioTuple
433 def __osdSubtitleInfoAvail(self):
434 subtitleTuple = self.service.info().getInfoObject(iServiceInformation.sUser+7)
435 print "SubtitleInfoAvail ", repr(subtitleTuple)
437 if subtitleTuple[0] is not 0:
438 subtitleString = "%d: %s" % (subtitleTuple[0],subtitleTuple[1])
439 self["subtitleLabel"].setText(subtitleString)
440 if subtitleTuple != self.last_subtitleTuple and not self.in_menu:
442 self.last_subtitleTuple = subtitleTuple
444 def __chapterUpdated(self):
445 self.currentChapter = self.service.info().getInfo(iServiceInformation.sCurrentChapter)
446 self.totalChapters = self.service.info().getInfo(iServiceInformation.sTotalChapters)
447 self.setChapterLabel()
448 print "__chapterUpdated: %d/%d" % (self.currentChapter, self.totalChapters)
450 def __titleUpdated(self):
451 self.currentTitle = self.service.info().getInfo(iServiceInformation.sCurrentTitle)
452 self.totalTitles = self.service.info().getInfo(iServiceInformation.sTotalTitles)
453 self.setChapterLabel()
454 print "__titleUpdated: %d/%d" % (self.currentTitle, self.totalTitles)
458 def askLeavePlayer(self):
460 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list=[(_("Continue playing"), "play"), (_("Exit"), "exit")])
462 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list=[(_("Continue playing"), "play"), (_("Return to file browser"), "browser"), (_("Exit"), "exit")])
464 def nextAudioTrack(self):
466 self.service.keys().keyPressed(iServiceKeys.keyUser)
468 def nextSubtitleTrack(self):
470 self.service.keys().keyPressed(iServiceKeys.keyUser+1)
472 def enterDVDAudioMenu(self):
474 self.service.keys().keyPressed(iServiceKeys.keyUser+2)
476 def nextChapter(self):
478 self.service.keys().keyPressed(iServiceKeys.keyUser+3)
480 def prevChapter(self):
482 self.service.keys().keyPressed(iServiceKeys.keyUser+4)
486 self.service.keys().keyPressed(iServiceKeys.keyUser+5)
490 self.service.keys().keyPressed(iServiceKeys.keyUser+6)
492 def enterDVDMenu(self):
494 self.service.keys().keyPressed(iServiceKeys.keyUser+7)
496 def seekBeginning(self):
498 seekable = self.getSeek()
499 if seekable is not None:
502 def zapToNumber(self, number):
504 seekable = self.getSeek()
505 if seekable is not None:
506 print "seek to chapter %d" % number
507 seekable.seekChapter(number)
512 self.service.keys().keyPressed(iServiceKeys.keyRight)
516 self.service.keys().keyPressed(iServiceKeys.keyLeft)
520 self.service.keys().keyPressed(iServiceKeys.keyUp)
524 self.service.keys().keyPressed(iServiceKeys.keyDown)
530 self.service.keys().keyPressed(iServiceKeys.keyOk)
533 self.askLeavePlayer()
535 def showFileBrowser(self):
537 if self.dvd_device == "/dev/cdroms/cdrom0":
538 self.session.openWithCallback(self.DVDdriveCB, MessageBox, text=_("Do you want to play DVD in drive?"), timeout=5 )
540 self.DVDdriveCB(True)
542 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser, self.dvd_filelist)
544 def DVDdriveCB(self, answer):
546 self.FileBrowserClosed(self.dvd_device)
548 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
550 def FileBrowserClosed(self, val):
551 curref = self.session.nav.getCurrentlyPlayingServiceReference()
552 print "FileBrowserClosed", val
554 self.askLeavePlayer()
556 newref = eServiceReference(4369, 0, val)
557 print "play", newref.toString()
558 if curref is None or curref != newref:
559 self.session.nav.playService(newref)
560 self.service = self.session.nav.getCurrentService()
561 print "self.service", self.service
562 print "cur_dlg", self.session.current_dialog
564 def exitCB(self, answer):
565 if answer is not None:
566 if answer[1] == "exit":
570 if answer[1] == "browser":
571 #TODO check here if a paused dvd playback is already running... then re-start it...
575 self.showFileBrowser()
580 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)):
582 open(i[0], "w").write(i[1])
584 print "restore", i[0], "failed"
585 self.restore_infobar_seek_config()
586 self.session.nav.playService(self.oldService)
588 def playLastCB(self, answer): # overwrite infobar cuesheet function
589 print "playLastCB", answer, self.resume_point
591 seek = self.service.seek()
593 seek.seekTo(self.resume_point)
594 pause = self.service.pause()
596 self.hideAfterResume()
598 def showAfterCuesheetOperation(self):
602 def createSummary(self):
605 #override some InfoBarSeek functions
607 self.setSeekState(self.SEEK_STATE_PLAY)
609 def calcRemainingTime(self):
612 def main(session, **kwargs):
613 session.open(DVDPlayer)
615 def menu(menuid, **kwargs):
616 if menuid == "mainmenu":
617 return [(_("DVD Player"), main, "dvd_player", 46)]
620 from Plugins.Plugin import PluginDescriptor
622 def filescan_open(list, session, **kwargs):
623 if len(list) == 1 and list[0].mimetype == "video/x-dvd":
624 splitted = list[0].path.split('/')
625 print "splitted", splitted
626 if len(splitted) > 2:
627 if splitted[1] == 'autofs':
628 session.open(DVDPlayer, dvd_device="/dev/%s" %(splitted[2]))
631 print "splitted[0]", splitted[1]
635 if x.mimetype == "video/x-dvd-iso":
636 dvd_filelist.append(x.path)
637 if x.mimetype == "video/x-dvd":
638 dvd_filelist.append(x.path.rsplit('/',1)[0])
639 session.open(DVDPlayer, dvd_filelist=dvd_filelist)
641 def filescan(**kwargs):
642 from Components.Scanner import Scanner, ScanPath
644 # Overwrite checkFile to only detect local
645 class LocalScanner(Scanner):
646 def checkFile(self, file):
647 return fileExists(file.path)
650 LocalScanner(mimetypes = ["video/x-dvd","video/x-dvd-iso"],
653 ScanPath(path = "video_ts", with_subdirs = False),
654 ScanPath(path = "", with_subdirs = False),
657 description = "Play DVD",
658 openfnc = filescan_open,
661 def Plugins(**kwargs):
662 return [PluginDescriptor(name = "DVDPlayer", description = "Play DVDs", where = PluginDescriptor.WHERE_MENU, fnc = menu),
663 PluginDescriptor(where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)]