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()
59 pathname = self["filelist"].getCurrentDirectory() or ""
60 if fileExists(pathname+"VIDEO_TS.IFO"):
61 print "dvd structure found, trying to open..."
69 class DVDSummary(Screen):
71 <screen position="0,0" size="132,64">
72 <widget source="session.CurrentService" render="Label" position="5,4" size="120,28" font="Regular;12" transparent="1" >
73 <convert type="ServiceName">Name</convert>
75 <widget name="DVDPlayer" position="5,30" size="66,16" font="Regular;12" transparent="1" />
76 <widget name="Chapter" position="72,30" size="54,16" font="Regular;12" transparent="1" halign="right" />
77 <widget source="session.CurrentService" render="Label" position="66,46" size="60,18" font="Regular;16" transparent="1" halign="right" >
78 <convert type="ServicePosition">Position</convert>
80 <widget source="session.CurrentService" render="Progress" position="6,46" size="60,18" borderWidth="1" >
81 <convert type="ServicePosition">Position</convert>
85 def __init__(self, session, parent):
86 Screen.__init__(self, session, parent)
88 self["DVDPlayer"] = Label("DVD Player")
89 self["Title"] = Label("")
90 self["Time"] = Label("")
91 self["Chapter"] = Label("")
93 def updateChapter(self, chapter):
94 self["Chapter"].setText(chapter)
96 def setTitle(self, title):
97 self["Title"].setText(title)
99 class DVDOverlay(Screen):
100 skin = """<screen name="DVDOverlay" position="0,0" size="720,576" flags="wfNoBorder" zPosition="-1" backgroundColor="transparent" />"""
101 def __init__(self, session, args = None):
102 Screen.__init__(self, session)
104 class ChapterZap(Screen):
106 <screen name="ChapterZap" position="235,255" size="250,60" title="Chapter" >
107 <widget name="chapter" position="35,15" size="110,25" font="Regular;23" />
108 <widget name="number" position="145,15" size="80,25" halign="right" font="Regular;23" />
117 self.close(int(self["number"].getText()))
119 def keyNumberGlobal(self, number):
120 self.Timer.start(3000, True) #reset timer
121 self.field = self.field + str(number)
122 self["number"].setText(self.field)
123 if len(self.field) >= 4:
126 def __init__(self, session, number):
127 Screen.__init__(self, session)
128 self.field = str(number)
130 self["chapter"] = Label(_("Chapter:"))
132 self["number"] = Label(self.field)
134 self["actions"] = NumberActionMap( [ "SetupActions" ],
138 "1": self.keyNumberGlobal,
139 "2": self.keyNumberGlobal,
140 "3": self.keyNumberGlobal,
141 "4": self.keyNumberGlobal,
142 "5": self.keyNumberGlobal,
143 "6": self.keyNumberGlobal,
144 "7": self.keyNumberGlobal,
145 "8": self.keyNumberGlobal,
146 "9": self.keyNumberGlobal,
147 "0": self.keyNumberGlobal
150 self.Timer = eTimer()
151 self.Timer.callback.append(self.keyOK)
152 self.Timer.start(3000, True)
154 class DVDPlayer(Screen, InfoBarBase, InfoBarNotifications, InfoBarSeek, InfoBarPVRState, InfoBarShowHide, HelpableScreen):
155 #InfoBarCueSheetSupport,
156 # ALLOW_SUSPEND = True
157 # ENABLE_RESUME_SUPPORT = True
160 <screen name="DVDPlayer" flags="wfNoBorder" position="0,380" size="720,160" title="InfoBar" backgroundColor="transparent" >
162 <ePixmap position="0,0" zPosition="-2" size="720,160" pixmap="skin_default/info-bg_mp.png" alphatest="off" />
163 <ePixmap position="29,40" zPosition="0" size="665,104" pixmap="skin_default/screws_mp.png" alphatest="on" transparent="1" />
164 <!-- colorbuttons -->
165 <ePixmap position="48,70" zPosition="0" size="108,13" pixmap="skin_default/icons/mp_buttons.png" alphatest="on" />
167 <ePixmap pixmap="skin_default/icons/icon_event.png" position="207,78" zPosition="1" size="15,10" alphatest="on" />
168 <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">
169 <convert type="ServiceName">Name</convert>
171 <!-- Chapter info -->
172 <widget name="chapterLabel" position="230,96" size="360,22" font="Regular;20" foregroundColor="#c3c3c9" backgroundColor="#263c59" transparent="1" />
173 <!-- Audio track info -->
174 <ePixmap pixmap="skin_default/icons/icon_dolby.png" position="540,73" zPosition="1" size="26,16" alphatest="on"/>
175 <widget name="audioLabel" position="570,73" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
176 <!-- Subtitle track info -->
177 <widget source="session.CurrentService" render="Pixmap" pixmap="skin_default/icons/icon_txt.png" position="540,96" zPosition="1" size="26,16" alphatest="on" >
178 <convert type="ServiceInfo">HasTelext</convert>
179 <convert type="ConditionalShowHide" />
181 <widget name="subtitleLabel" position="570,96" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
182 <!-- Elapsed time -->
183 <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" >
184 <convert type="ServicePosition">Position,ShowHours</convert>
186 <!-- Progressbar (movie position)-->
187 <widget source="session.CurrentService" render="PositionGauge" position="300,133" size="270,10" zPosition="2" pointer="skin_default/position_pointer.png:540,0" transparent="1" >
188 <convert type="ServicePosition">Gauge</convert>
190 <!-- Remaining time -->
191 <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" >
192 <convert type="ServicePosition">Remaining,Negate,ShowHours</convert>
196 def save_infobar_seek_config(self):
197 self.saved_config_speeds_forward = config.seek.speeds_forward.value
198 self.saved_config_speeds_backward = config.seek.speeds_backward.value
199 self.saved_config_enter_forward = config.seek.enter_forward.value
200 self.saved_config_enter_backward = config.seek.enter_backward.value
201 self.saved_config_seek_stepwise_minspeed = config.seek.stepwise_minspeed.value
202 self.saved_config_seek_stepwise_repeat = config.seek.stepwise_repeat.value
203 self.saved_config_seek_on_pause = config.seek.on_pause.value
204 self.saved_config_seek_speeds_slowmotion = config.seek.speeds_slowmotion.value
206 def change_infobar_seek_config(self):
207 config.seek.speeds_forward.value = [2, 4, 8, 16, 32, 64]
208 config.seek.speeds_backward.value = [8, 16, 32, 64]
209 config.seek.speeds_slowmotion.value = [ ]
210 config.seek.enter_forward.value = "2"
211 config.seek.enter_backward.value = "2"
212 config.seek.stepwise_minspeed.value = "Never"
213 config.seek.stepwise_repeat.value = "3"
214 config.seek.on_pause.value = "play"
216 def restore_infobar_seek_config(self):
217 config.seek.speeds_forward.value = self.saved_config_speeds_forward
218 config.seek.speeds_backward.value = self.saved_config_speeds_backward
219 config.seek.speeds_slowmotion.value = self.saved_config_seek_speeds_slowmotion
220 config.seek.enter_forward.value = self.saved_config_enter_forward
221 config.seek.enter_backward.value = self.saved_config_enter_backward
222 config.seek.stepwise_minspeed.value = self.saved_config_seek_stepwise_minspeed
223 config.seek.stepwise_repeat.value = self.saved_config_seek_stepwise_repeat
224 config.seek.on_pause.value = self.saved_config_seek_on_pause
226 def __init__(self, session, dvd_device = None, args = None):
227 Screen.__init__(self, session)
228 InfoBarBase.__init__(self)
229 InfoBarNotifications.__init__(self)
230 # InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions")
231 InfoBarShowHide.__init__(self)
232 HelpableScreen.__init__(self)
233 self.save_infobar_seek_config()
234 self.change_infobar_seek_config()
235 InfoBarSeek.__init__(self, useSeekBackHack=False)
236 InfoBarPVRState.__init__(self)
237 self.dvdScreen = self.session.instantiateDialog(DVDOverlay)
239 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
240 self.session.nav.stopService()
241 self["audioLabel"] = Label("1")
242 self["subtitleLabel"] = Label("")
243 self["chapterLabel"] = Label("")
244 self.totalChapters = 0
245 self.currentChapter = 0
247 self.currentTitle = 0
249 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
251 iPlayableService.evStopped: self.__serviceStopped,
252 iPlayableService.evUser: self.__timeUpdated,
253 iPlayableService.evUser+1: self.__statePlay,
254 iPlayableService.evUser+2: self.__statePause,
255 iPlayableService.evUser+3: self.__osdFFwdInfoAvail,
256 iPlayableService.evUser+4: self.__osdFBwdInfoAvail,
257 iPlayableService.evUser+5: self.__osdStringAvail,
258 iPlayableService.evUser+6: self.__osdAudioInfoAvail,
259 iPlayableService.evUser+7: self.__osdSubtitleInfoAvail,
260 iPlayableService.evUser+8: self.__chapterUpdated,
261 iPlayableService.evUser+9: self.__titleUpdated,
262 #iPlayableService.evUser+10: self.__initializeDVDinfo,
263 iPlayableService.evUser+11: self.__menuOpened,
264 iPlayableService.evUser+12: self.__menuClosed
267 self["DVDPlayerDirectionActions"] = HelpableActionMap(self, "DirectionActions",
269 #MENU KEY DOWN ACTIONS
270 "left": (self.keyLeft, _("DVD left key")),
271 "right": (self.keyRight, _("DVD right key")),
272 "up": (self.keyUp, _("DVD up key")),
273 "down": (self.keyDown, _("DVD down key")),
275 #MENU KEY REPEATED ACTIONS
276 "leftRepeated": self.doNothing,
277 "rightRepeated": self.doNothing,
278 "upRepeated": self.doNothing,
279 "downRepeated": self.doNothing,
282 "leftUp": self.doNothing,
283 "rightUp": self.doNothing,
284 "upUp": self.doNothing,
285 "downUp": self.doNothing,
288 self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions",
290 "ok": (self.keyOk, _("DVD ENTER key")),
291 "cancel": self.keyCancel,
294 self["DVDPlayerPlaybackActions"] = HelpableActionMap(self, "DVDPlayerActions",
297 "dvdMenu": (self.enterDVDMenu, _("show DVD main menu")),
298 "toggleInfo": (self.toggleInfo, _("toggle time, chapter, audio, subtitle info")),
299 "nextChapter": (self.nextChapter, _("forward to the next chapter")),
300 "prevChapter": (self.prevChapter, _("rewind to the previous chapter")),
301 "nextTitle": (self.nextTitle, _("jump forward to the next title")),
302 "prevTitle": (self.prevTitle, _("jump back to the previous title")),
303 "tv": (self.askLeavePlayer, _("exit DVD player or return to file browser")),
304 "dvdAudioMenu": (self.enterDVDAudioMenu, _("(show optional DVD audio menu)")),
305 "nextAudioTrack": (self.nextAudioTrack, _("switch to the next audio track")),
306 "nextSubtitleTrack": (self.nextSubtitleTrack, _("switch to the next subtitle language")),
307 "seekBeginning": (self.seekBeginning, _("Jump to video title 1 (play movie from start)")),
310 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
312 "1": self.keyNumberGlobal,
313 "2": self.keyNumberGlobal,
314 "3": self.keyNumberGlobal,
315 "4": self.keyNumberGlobal,
316 "5": self.keyNumberGlobal,
317 "6": self.keyNumberGlobal,
318 "7": self.keyNumberGlobal,
319 "8": self.keyNumberGlobal,
320 "9": self.keyNumberGlobal,
321 "0": self.keyNumberGlobal,
324 self.onClose.append(self.__onClose)
327 self.dvd_device = dvd_device
328 self.physicalDVD = True
330 if fileExists("/dev/cdroms/cdrom0"):
331 print "physical dvd found (/dev/cdroms/cdrom0)"
332 self.dvd_device = "/dev/cdroms/cdrom0"
333 self.physicalDVD = True
335 self.dvd_device = None
336 self.physicalDVD = False
338 self.onFirstExecBegin.append(self.showFileBrowser)
341 self.old_aspect = open("/proc/stb/video/aspect", "r").read()
342 self.old_policy = open("/proc/stb/video/policy", "r").read()
343 self.old_wss = open("/proc/stb/denc/0/wss", "r").read()
345 def keyNumberGlobal(self, number):
346 print "You pressed number " + str(number)
347 self.session.openWithCallback(self.numberEntered, ChapterZap, number)
349 def numberEntered(self, retval):
350 # print self.servicelist
352 self.zapToNumber(retval)
354 def __serviceStopped(self):
355 self.dvdScreen.hide()
356 self.service.subtitle().disableSubtitles(self.session.current_dialog.instance)
358 def serviceStarted(self): #override InfoBarShowHide function
359 self.dvdScreen.show()
360 self.service.subtitle().enableSubtitles(self.dvdScreen.instance, None)
362 def doEofInternal(self, playing):
366 def __menuOpened(self):
369 self["NumberActions"].setEnabled(False)
371 def __menuClosed(self):
374 self["NumberActions"].setEnabled(True)
376 def setChapterLabel(self):
378 chapterOSD = "DVD Menu"
379 if self.currentTitle > 0:
380 chapterLCD = "%s %d" % (_("Chap."), self.currentChapter)
381 chapterOSD = "DVD %s %d/%d" % (_("Chapter"), self.currentChapter, self.totalChapters)
382 chapterOSD += " (%s %d/%d)" % (_("Title"), self.currentTitle, self.totalTitles)
383 self["chapterLabel"].setText(chapterOSD)
385 self.session.summary.updateChapter(chapterLCD)
392 def toggleInfo(self):
397 def __timeUpdated(self):
400 def __statePlay(self):
403 def __statePause(self):
406 def __osdFFwdInfoAvail(self):
407 self.setChapterLabel()
408 print "FFwdInfoAvail"
410 def __osdFBwdInfoAvail(self):
411 self.setChapterLabel()
412 print "FBwdInfoAvail"
414 def __osdStringAvail(self):
417 def __osdAudioInfoAvail(self):
418 audioString = self.service.info().getInfoString(iServiceInformation.sUser+6)
419 print "AudioInfoAvail "+audioString
420 self["audioLabel"].setText(audioString)
424 def __osdSubtitleInfoAvail(self):
425 subtitleString = self.service.info().getInfoString(iServiceInformation.sUser+7)
426 print "SubtitleInfoAvail "+subtitleString
427 self["subtitleLabel"].setText(subtitleString)
431 def __chapterUpdated(self):
432 self.currentChapter = self.service.info().getInfo(iServiceInformation.sUser+8)
433 self.totalChapters = self.service.info().getInfo(iServiceInformation.sUser+80)
434 self.setChapterLabel()
435 print "__chapterUpdated: %d/%d" % (self.currentChapter, self.totalChapters)
437 def __titleUpdated(self):
438 self.currentTitle = self.service.info().getInfo(iServiceInformation.sUser+9)
439 self.totalTitles = self.service.info().getInfo(iServiceInformation.sUser+90)
440 self.setChapterLabel()
441 print "__titleUpdated: %d/%d" % (self.currentTitle, self.totalTitles)
445 #def __initializeDVDinfo(self):
446 #self.__osdAudioInfoAvail()
447 #self.__osdSubtitleInfoAvail()
449 def askLeavePlayer(self):
451 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list=[(_("Continue playing"), "play"), (_("Exit"), "exit")])
453 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list=[(_("Continue playing"), "play"), (_("Return to file browser"), "browser"), (_("Exit"), "exit")])
455 def nextAudioTrack(self):
457 self.service.keys().keyPressed(iServiceKeys.keyUser)
459 def nextSubtitleTrack(self):
461 self.service.keys().keyPressed(iServiceKeys.keyUser+1)
463 def enterDVDAudioMenu(self):
465 self.service.keys().keyPressed(iServiceKeys.keyUser+2)
467 def nextChapter(self):
469 self.service.keys().keyPressed(iServiceKeys.keyUser+3)
471 def prevChapter(self):
473 self.service.keys().keyPressed(iServiceKeys.keyUser+4)
477 self.service.keys().keyPressed(iServiceKeys.keyUser+5)
481 self.service.keys().keyPressed(iServiceKeys.keyUser+6)
483 def enterDVDMenu(self):
485 self.service.keys().keyPressed(iServiceKeys.keyUser+7)
487 def seekBeginning(self):
489 seekable = self.getSeek()
490 if seekable is not None:
493 def zapToNumber(self, number):
495 seekable = self.getSeek()
496 if seekable is not None:
497 print "seek to chapter %d" % number
498 seekable.seekChapter(number)
503 self.service.keys().keyPressed(iServiceKeys.keyRight)
507 self.service.keys().keyPressed(iServiceKeys.keyLeft)
511 self.service.keys().keyPressed(iServiceKeys.keyUp)
515 self.service.keys().keyPressed(iServiceKeys.keyDown)
521 self.service.keys().keyPressed(iServiceKeys.keyOk)
524 self.askLeavePlayer()
526 def showFileBrowser(self):
528 if self.dvd_device == "/dev/cdroms/cdrom0":
529 self.session.openWithCallback(self.DVDdriveCB, MessageBox, text=_("Do you want to play DVD in drive?"), timeout=5 )
531 self.DVDdriveCB(True)
533 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
535 def DVDdriveCB(self, answer):
537 self.FileBrowserClosed(self.dvd_device)
539 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
541 def FileBrowserClosed(self, val):
542 curref = self.session.nav.getCurrentlyPlayingServiceReference()
543 print "FileBrowserClosed", val
545 self.askLeavePlayer()
547 newref = eServiceReference(4369, 0, val)
548 print "play", newref.toString()
549 if curref is None or curref != newref:
550 self.session.nav.playService(newref)
551 self.service = self.session.nav.getCurrentService()
552 print "self.service", self.service
553 print "cur_dlg", self.session.current_dialog
555 def exitCB(self, answer):
556 if answer is not None:
557 if answer[1] == "exit":
561 if answer[1] == "browser":
562 #TODO check here if a paused dvd playback is already running... then re-start it...
564 self.showFileBrowser()
569 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)):
571 open(i[0], "w").write(i[1])
573 print "restore", i[0], "failed"
574 self.restore_infobar_seek_config()
575 self.session.nav.playService(self.oldService)
577 # def playLastCB(self, answer): # overwrite infobar cuesheet function
578 # print "playLastCB", answer, self.resume_point
579 # pos = self.resume_point
580 # title = self.resume_point % 90000
582 # chapter = title % 256
584 # print "pos", pos, "title", title, "chapter", chapter
586 # seek = self.service.seek()
588 # seek.seekTitle(title)
589 # self.resume_state = 1
591 # seek.seekChapter(chapter)
592 # self.resume_state = 2
595 # self.hideAfterResume()
597 def showAfterCuesheetOperation(self):
601 def createSummary(self):
602 print "DVDCreateSummary"
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 #TODO add *.iso to filescanner and ask when more than one iso file is found
624 def filescan_open(list, session, **kwargs):
626 splitted = x.path.split('/')
627 print "splitted", splitted
628 if len(splitted) > 2:
629 if splitted[1] == 'autofs':
630 session.open(DVDPlayer, "/dev/%s" %(splitted[2]))
633 print "splitted[0]", splitted[1]
635 def filescan(**kwargs):
636 from Components.Scanner import Scanner, ScanPath
638 # Overwrite checkFile to only detect local
639 class LocalScanner(Scanner):
640 def checkFile(self, file):
641 return fileExists(file.path)
644 LocalScanner(mimetypes = None,
647 ScanPath(path = "video_ts", 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)]