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):
161 #InfoBarCueSheetSupport,
162 # ALLOW_SUSPEND = True
163 # ENABLE_RESUME_SUPPORT = True
166 <screen name="DVDPlayer" flags="wfNoBorder" position="0,380" size="720,160" title="InfoBar" backgroundColor="transparent" >
168 <ePixmap position="0,0" zPosition="-2" size="720,160" pixmap="skin_default/info-bg_mp.png" alphatest="off" />
169 <ePixmap position="29,40" zPosition="0" size="665,104" pixmap="skin_default/screws_mp.png" alphatest="on" transparent="1" />
170 <!-- colorbuttons -->
171 <ePixmap position="48,70" zPosition="0" size="108,13" pixmap="skin_default/icons/mp_buttons.png" alphatest="on" />
173 <ePixmap pixmap="skin_default/icons/icon_event.png" position="207,78" zPosition="1" size="15,10" alphatest="on" />
174 <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">
175 <convert type="ServiceName">Name</convert>
177 <!-- Chapter info -->
178 <widget name="chapterLabel" position="230,96" size="360,22" font="Regular;20" foregroundColor="#c3c3c9" backgroundColor="#263c59" transparent="1" />
179 <!-- Audio track info -->
180 <ePixmap pixmap="skin_default/icons/icon_dolby.png" position="540,73" zPosition="1" size="26,16" alphatest="on"/>
181 <widget name="audioLabel" position="570,73" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
182 <!-- Subtitle track info -->
183 <widget source="session.CurrentService" render="Pixmap" pixmap="skin_default/icons/icon_txt.png" position="540,96" zPosition="1" size="26,16" alphatest="on" >
184 <convert type="ServiceInfo">HasTelext</convert>
185 <convert type="ConditionalShowHide" />
187 <widget name="subtitleLabel" position="570,96" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
188 <!-- Elapsed time -->
189 <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" >
190 <convert type="ServicePosition">Position,ShowHours</convert>
192 <!-- Progressbar (movie position)-->
193 <widget source="session.CurrentService" render="PositionGauge" position="300,133" size="270,10" zPosition="2" pointer="skin_default/position_pointer.png:540,0" transparent="1" >
194 <convert type="ServicePosition">Gauge</convert>
196 <!-- Remaining time -->
197 <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" >
198 <convert type="ServicePosition">Remaining,Negate,ShowHours</convert>
202 def save_infobar_seek_config(self):
203 self.saved_config_speeds_forward = config.seek.speeds_forward.value
204 self.saved_config_speeds_backward = config.seek.speeds_backward.value
205 self.saved_config_enter_forward = config.seek.enter_forward.value
206 self.saved_config_enter_backward = config.seek.enter_backward.value
207 self.saved_config_seek_stepwise_minspeed = config.seek.stepwise_minspeed.value
208 self.saved_config_seek_stepwise_repeat = config.seek.stepwise_repeat.value
209 self.saved_config_seek_on_pause = config.seek.on_pause.value
210 self.saved_config_seek_speeds_slowmotion = config.seek.speeds_slowmotion.value
212 def change_infobar_seek_config(self):
213 config.seek.speeds_forward.value = [2, 4, 8, 16, 32, 64]
214 config.seek.speeds_backward.value = [8, 16, 32, 64]
215 config.seek.speeds_slowmotion.value = [ ]
216 config.seek.enter_forward.value = "2"
217 config.seek.enter_backward.value = "2"
218 config.seek.stepwise_minspeed.value = "Never"
219 config.seek.stepwise_repeat.value = "3"
220 config.seek.on_pause.value = "play"
222 def restore_infobar_seek_config(self):
223 config.seek.speeds_forward.value = self.saved_config_speeds_forward
224 config.seek.speeds_backward.value = self.saved_config_speeds_backward
225 config.seek.speeds_slowmotion.value = self.saved_config_seek_speeds_slowmotion
226 config.seek.enter_forward.value = self.saved_config_enter_forward
227 config.seek.enter_backward.value = self.saved_config_enter_backward
228 config.seek.stepwise_minspeed.value = self.saved_config_seek_stepwise_minspeed
229 config.seek.stepwise_repeat.value = self.saved_config_seek_stepwise_repeat
230 config.seek.on_pause.value = self.saved_config_seek_on_pause
232 def __init__(self, session, dvd_device = None, dvd_filelist = None, args = None):
233 Screen.__init__(self, session)
234 InfoBarBase.__init__(self)
235 InfoBarNotifications.__init__(self)
236 # InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions")
237 InfoBarShowHide.__init__(self)
238 HelpableScreen.__init__(self)
239 self.save_infobar_seek_config()
240 self.change_infobar_seek_config()
241 InfoBarSeek.__init__(self, useSeekBackHack=False)
242 InfoBarPVRState.__init__(self)
243 self.dvdScreen = self.session.instantiateDialog(DVDOverlay)
245 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
246 self.session.nav.stopService()
247 self["audioLabel"] = Label("1")
248 self["subtitleLabel"] = Label("")
249 self["chapterLabel"] = Label("")
250 self.totalChapters = 0
251 self.currentChapter = 0
253 self.currentTitle = 0
255 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
257 iPlayableService.evStopped: self.__serviceStopped,
258 iPlayableService.evUser: self.__timeUpdated,
259 iPlayableService.evUser+1: self.__statePlay,
260 iPlayableService.evUser+2: self.__statePause,
261 iPlayableService.evUser+3: self.__osdFFwdInfoAvail,
262 iPlayableService.evUser+4: self.__osdFBwdInfoAvail,
263 iPlayableService.evUser+5: self.__osdStringAvail,
264 iPlayableService.evUser+6: self.__osdAudioInfoAvail,
265 iPlayableService.evUser+7: self.__osdSubtitleInfoAvail,
266 iPlayableService.evUser+8: self.__chapterUpdated,
267 iPlayableService.evUser+9: self.__titleUpdated,
268 #iPlayableService.evUser+10: self.__initializeDVDinfo,
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 audioString = self.service.info().getInfoString(iServiceInformation.sUser+6)
426 print "AudioInfoAvail "+audioString
427 self["audioLabel"].setText(audioString)
431 def __osdSubtitleInfoAvail(self):
432 subtitleString = self.service.info().getInfoString(iServiceInformation.sUser+7)
433 print "SubtitleInfoAvail "+subtitleString
434 self["subtitleLabel"].setText(subtitleString)
438 def __chapterUpdated(self):
439 self.currentChapter = self.service.info().getInfo(iServiceInformation.sCurrentChapter)
440 self.totalChapters = self.service.info().getInfo(iServiceInformation.sTotalChapters)
441 self.setChapterLabel()
442 print "__chapterUpdated: %d/%d" % (self.currentChapter, self.totalChapters)
444 def __titleUpdated(self):
445 self.currentTitle = self.service.info().getInfo(iServiceInformation.sCurrentTitle)
446 self.totalTitles = self.service.info().getInfo(iServiceInformation.sTotalTitles)
447 self.setChapterLabel()
448 print "__titleUpdated: %d/%d" % (self.currentTitle, self.totalTitles)
452 #def __initializeDVDinfo(self):
453 #self.__osdAudioInfoAvail()
454 #self.__osdSubtitleInfoAvail()
456 def askLeavePlayer(self):
458 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list=[(_("Continue playing"), "play"), (_("Exit"), "exit")])
460 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list=[(_("Continue playing"), "play"), (_("Return to file browser"), "browser"), (_("Exit"), "exit")])
462 def nextAudioTrack(self):
464 self.service.keys().keyPressed(iServiceKeys.keyUser)
466 def nextSubtitleTrack(self):
468 self.service.keys().keyPressed(iServiceKeys.keyUser+1)
470 def enterDVDAudioMenu(self):
472 self.service.keys().keyPressed(iServiceKeys.keyUser+2)
474 def nextChapter(self):
476 self.service.keys().keyPressed(iServiceKeys.keyUser+3)
478 def prevChapter(self):
480 self.service.keys().keyPressed(iServiceKeys.keyUser+4)
484 self.service.keys().keyPressed(iServiceKeys.keyUser+5)
488 self.service.keys().keyPressed(iServiceKeys.keyUser+6)
490 def enterDVDMenu(self):
492 self.service.keys().keyPressed(iServiceKeys.keyUser+7)
494 def seekBeginning(self):
496 seekable = self.getSeek()
497 if seekable is not None:
500 def zapToNumber(self, number):
502 seekable = self.getSeek()
503 if seekable is not None:
504 print "seek to chapter %d" % number
505 seekable.seekChapter(number)
510 self.service.keys().keyPressed(iServiceKeys.keyRight)
514 self.service.keys().keyPressed(iServiceKeys.keyLeft)
518 self.service.keys().keyPressed(iServiceKeys.keyUp)
522 self.service.keys().keyPressed(iServiceKeys.keyDown)
528 self.service.keys().keyPressed(iServiceKeys.keyOk)
531 self.askLeavePlayer()
533 def showFileBrowser(self):
535 if self.dvd_device == "/dev/cdroms/cdrom0":
536 self.session.openWithCallback(self.DVDdriveCB, MessageBox, text=_("Do you want to play DVD in drive?"), timeout=5 )
538 self.DVDdriveCB(True)
540 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser, self.dvd_filelist)
542 def DVDdriveCB(self, answer):
544 self.FileBrowserClosed(self.dvd_device)
546 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
548 def FileBrowserClosed(self, val):
549 curref = self.session.nav.getCurrentlyPlayingServiceReference()
550 print "FileBrowserClosed", val
552 self.askLeavePlayer()
554 newref = eServiceReference(4369, 0, val)
555 print "play", newref.toString()
556 if curref is None or curref != newref:
557 self.session.nav.playService(newref)
558 self.service = self.session.nav.getCurrentService()
559 print "self.service", self.service
560 print "cur_dlg", self.session.current_dialog
562 def exitCB(self, answer):
563 if answer is not None:
564 if answer[1] == "exit":
568 if answer[1] == "browser":
569 #TODO check here if a paused dvd playback is already running... then re-start it...
573 self.showFileBrowser()
578 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)):
580 open(i[0], "w").write(i[1])
582 print "restore", i[0], "failed"
583 self.restore_infobar_seek_config()
584 self.session.nav.playService(self.oldService)
586 # def playLastCB(self, answer): # overwrite infobar cuesheet function
587 # print "playLastCB", answer, self.resume_point
588 # pos = self.resume_point
589 # title = self.resume_point % 90000
591 # chapter = title % 256
593 # print "pos", pos, "title", title, "chapter", chapter
595 # seek = self.service.seek()
597 # seek.seekTitle(title)
598 # self.resume_state = 1
600 # seek.seekChapter(chapter)
601 # self.resume_state = 2
604 # self.hideAfterResume()
606 def showAfterCuesheetOperation(self):
610 def createSummary(self):
613 #override some InfoBarSeek functions
615 self.setSeekState(self.SEEK_STATE_PLAY)
617 def calcRemainingTime(self):
620 def main(session, **kwargs):
621 session.open(DVDPlayer)
623 def menu(menuid, **kwargs):
624 if menuid == "mainmenu":
625 return [(_("DVD Player"), main, "dvd_player", 46)]
628 from Plugins.Plugin import PluginDescriptor
630 def filescan_open(list, session, **kwargs):
631 if len(list) == 1 and list[0].mimetype == "video/x-dvd":
632 splitted = list[0].path.split('/')
633 print "splitted", splitted
634 if len(splitted) > 2:
635 if splitted[1] == 'autofs':
636 session.open(DVDPlayer, dvd_device="/dev/%s" %(splitted[2]))
639 print "splitted[0]", splitted[1]
643 if x.mimetype == "video/x-dvd-iso":
644 dvd_filelist.append(x.path)
645 if x.mimetype == "video/x-dvd":
646 dvd_filelist.append(x.path.rsplit('/',1)[0])
647 session.open(DVDPlayer, dvd_filelist=dvd_filelist)
649 def filescan(**kwargs):
650 from Components.Scanner import Scanner, ScanPath
652 # Overwrite checkFile to only detect local
653 class LocalScanner(Scanner):
654 def checkFile(self, file):
655 return fileExists(file.path)
658 LocalScanner(mimetypes = ["video/x-dvd","video/x-dvd-iso"],
661 ScanPath(path = "video_ts", with_subdirs = False),
662 ScanPath(path = "", with_subdirs = False),
665 description = "Play DVD",
666 openfnc = filescan_open,
669 def Plugins(**kwargs):
670 return [PluginDescriptor(name = "DVDPlayer", description = "Play DVDs", where = PluginDescriptor.WHERE_MENU, fnc = menu),
671 PluginDescriptor(where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)]