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()
60 print self["filelist"].getFilename()
61 if fileExists(pathname+"VIDEO_TS.IFO"):
62 print "dvd structure found, trying to open..."
70 class DVDSummary(Screen):
72 <screen position="0,0" size="132,64">
73 <widget source="session.CurrentService" render="Label" position="5,4" size="120,28" font="Regular;12" transparent="1" >
74 <convert type="ServiceName">Name</convert>
76 <widget name="DVDPlayer" position="5,30" size="66,16" font="Regular;12" transparent="1" />
77 <widget name="Chapter" position="72,30" size="54,16" font="Regular;12" transparent="1" halign="right" />
78 <widget source="session.CurrentService" render="Label" position="66,46" size="60,18" font="Regular;16" transparent="1" halign="right" >
79 <convert type="ServicePosition">Position</convert>
81 <widget source="session.CurrentService" render="Progress" position="6,46" size="60,18" borderWidth="1" >
82 <convert type="ServicePosition">Position</convert>
86 def __init__(self, session, parent):
87 Screen.__init__(self, session, parent)
89 self["DVDPlayer"] = Label("DVD Player")
90 self["Title"] = Label("")
91 self["Time"] = Label("")
92 self["Chapter"] = Label("")
94 def updateChapter(self, chapter):
95 self["Chapter"].setText(chapter)
97 def setTitle(self, title):
98 self["Title"].setText(title)
100 class DVDOverlay(Screen):
101 skin = """<screen name="DVDOverlay" position="0,0" size="720,576" flags="wfNoBorder" zPosition="-1" backgroundColor="transparent" />"""
102 def __init__(self, session, args = None):
103 Screen.__init__(self, session)
105 class ChapterZap(Screen):
107 <screen name="ChapterZap" position="235,255" size="250,60" title="Chapter" >
108 <widget name="chapter" position="35,15" size="110,25" font="Regular;23" />
109 <widget name="number" position="145,15" size="80,25" halign="right" font="Regular;23" />
118 self.close(int(self["number"].getText()))
120 def keyNumberGlobal(self, number):
121 self.Timer.start(3000, True) #reset timer
122 self.field = self.field + str(number)
123 self["number"].setText(self.field)
124 if len(self.field) >= 4:
127 def __init__(self, session, number):
128 Screen.__init__(self, session)
129 self.field = str(number)
131 self["chapter"] = Label(_("Chapter:"))
133 self["number"] = Label(self.field)
135 self["actions"] = NumberActionMap( [ "SetupActions" ],
139 "1": self.keyNumberGlobal,
140 "2": self.keyNumberGlobal,
141 "3": self.keyNumberGlobal,
142 "4": self.keyNumberGlobal,
143 "5": self.keyNumberGlobal,
144 "6": self.keyNumberGlobal,
145 "7": self.keyNumberGlobal,
146 "8": self.keyNumberGlobal,
147 "9": self.keyNumberGlobal,
148 "0": self.keyNumberGlobal
151 self.Timer = eTimer()
152 self.Timer.callback.append(self.keyOK)
153 self.Timer.start(3000, True)
155 class DVDPlayer(Screen, InfoBarBase, InfoBarNotifications, InfoBarSeek, InfoBarPVRState, InfoBarShowHide, HelpableScreen):
156 #InfoBarCueSheetSupport,
157 # ALLOW_SUSPEND = True
158 # ENABLE_RESUME_SUPPORT = True
161 <screen name="DVDPlayer" flags="wfNoBorder" position="0,380" size="720,160" title="InfoBar" backgroundColor="transparent" >
163 <ePixmap position="0,0" zPosition="-2" size="720,160" pixmap="skin_default/info-bg_mp.png" alphatest="off" />
164 <ePixmap position="29,40" zPosition="0" size="665,104" pixmap="skin_default/screws_mp.png" alphatest="on" transparent="1" />
165 <!-- colorbuttons -->
166 <ePixmap position="48,70" zPosition="0" size="108,13" pixmap="skin_default/icons/mp_buttons.png" alphatest="on" />
168 <ePixmap pixmap="skin_default/icons/icon_event.png" position="207,78" zPosition="1" size="15,10" alphatest="on" />
169 <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">
170 <convert type="ServiceName">Name</convert>
172 <!-- Chapter info -->
173 <widget name="chapterLabel" position="230,96" size="360,22" font="Regular;20" foregroundColor="#c3c3c9" backgroundColor="#263c59" transparent="1" />
174 <!-- Audio track info -->
175 <ePixmap pixmap="skin_default/icons/icon_dolby.png" position="540,73" zPosition="1" size="26,16" alphatest="on"/>
176 <widget name="audioLabel" position="570,73" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
177 <!-- Subtitle track info -->
178 <widget source="session.CurrentService" render="Pixmap" pixmap="skin_default/icons/icon_txt.png" position="540,96" zPosition="1" size="26,16" alphatest="on" >
179 <convert type="ServiceInfo">HasTelext</convert>
180 <convert type="ConditionalShowHide" />
182 <widget name="subtitleLabel" position="570,96" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
183 <!-- Elapsed time -->
184 <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" >
185 <convert type="ServicePosition">Position,ShowHours</convert>
187 <!-- Progressbar (movie position)-->
188 <widget source="session.CurrentService" render="PositionGauge" position="300,133" size="270,10" zPosition="2" pointer="skin_default/position_pointer.png:540,0" transparent="1" >
189 <convert type="ServicePosition">Gauge</convert>
191 <!-- Remaining time -->
192 <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" >
193 <convert type="ServicePosition">Remaining,Negate,ShowHours</convert>
197 def save_infobar_seek_config(self):
198 self.saved_config_speeds_forward = config.seek.speeds_forward.value
199 self.saved_config_speeds_backward = config.seek.speeds_backward.value
200 self.saved_config_enter_forward = config.seek.enter_forward.value
201 self.saved_config_enter_backward = config.seek.enter_backward.value
202 self.saved_config_seek_stepwise_minspeed = config.seek.stepwise_minspeed.value
203 self.saved_config_seek_stepwise_repeat = config.seek.stepwise_repeat.value
204 self.saved_config_seek_on_pause = config.seek.on_pause.value
205 self.saved_config_seek_speeds_slowmotion = config.seek.speeds_slowmotion.value
207 def change_infobar_seek_config(self):
208 config.seek.speeds_forward.value = [2, 4, 8, 16, 32, 64]
209 config.seek.speeds_backward.value = [8, 16, 32, 64]
210 config.seek.speeds_slowmotion.value = [ ]
211 config.seek.enter_forward.value = "2"
212 config.seek.enter_backward.value = "2"
213 config.seek.stepwise_minspeed.value = "Never"
214 config.seek.stepwise_repeat.value = "3"
215 config.seek.on_pause.value = "play"
217 def restore_infobar_seek_config(self):
218 config.seek.speeds_forward.value = self.saved_config_speeds_forward
219 config.seek.speeds_backward.value = self.saved_config_speeds_backward
220 config.seek.speeds_slowmotion.value = self.saved_config_seek_speeds_slowmotion
221 config.seek.enter_forward.value = self.saved_config_enter_forward
222 config.seek.enter_backward.value = self.saved_config_enter_backward
223 config.seek.stepwise_minspeed.value = self.saved_config_seek_stepwise_minspeed
224 config.seek.stepwise_repeat.value = self.saved_config_seek_stepwise_repeat
225 config.seek.on_pause.value = self.saved_config_seek_on_pause
227 def __init__(self, session, dvd_device = None, args = None):
228 Screen.__init__(self, session)
229 InfoBarBase.__init__(self)
230 InfoBarNotifications.__init__(self)
231 # InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions")
232 InfoBarShowHide.__init__(self)
233 HelpableScreen.__init__(self)
234 self.save_infobar_seek_config()
235 self.change_infobar_seek_config()
236 InfoBarSeek.__init__(self, useSeekBackHack=False)
237 InfoBarPVRState.__init__(self)
238 self.dvdScreen = self.session.instantiateDialog(DVDOverlay)
240 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
241 self.session.nav.stopService()
242 self["audioLabel"] = Label("1")
243 self["subtitleLabel"] = Label("")
244 self["chapterLabel"] = Label("")
245 self.totalChapters = 0
246 self.currentChapter = 0
248 self.currentTitle = 0
250 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
252 iPlayableService.evStopped: self.__serviceStopped,
253 iPlayableService.evUser: self.__timeUpdated,
254 iPlayableService.evUser+1: self.__statePlay,
255 iPlayableService.evUser+2: self.__statePause,
256 iPlayableService.evUser+3: self.__osdFFwdInfoAvail,
257 iPlayableService.evUser+4: self.__osdFBwdInfoAvail,
258 iPlayableService.evUser+5: self.__osdStringAvail,
259 iPlayableService.evUser+6: self.__osdAudioInfoAvail,
260 iPlayableService.evUser+7: self.__osdSubtitleInfoAvail,
261 iPlayableService.evUser+8: self.__chapterUpdated,
262 iPlayableService.evUser+9: self.__titleUpdated,
263 #iPlayableService.evUser+10: self.__initializeDVDinfo,
264 iPlayableService.evUser+11: self.__menuOpened,
265 iPlayableService.evUser+12: self.__menuClosed
268 self["DVDPlayerDirectionActions"] = HelpableActionMap(self, "DirectionActions",
270 #MENU KEY DOWN ACTIONS
271 "left": (self.keyLeft, _("DVD left key")),
272 "right": (self.keyRight, _("DVD right key")),
273 "up": (self.keyUp, _("DVD up key")),
274 "down": (self.keyDown, _("DVD down key")),
276 #MENU KEY REPEATED ACTIONS
277 "leftRepeated": self.doNothing,
278 "rightRepeated": self.doNothing,
279 "upRepeated": self.doNothing,
280 "downRepeated": self.doNothing,
283 "leftUp": self.doNothing,
284 "rightUp": self.doNothing,
285 "upUp": self.doNothing,
286 "downUp": self.doNothing,
289 self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions",
291 "ok": (self.keyOk, _("DVD ENTER key")),
292 "cancel": self.keyCancel,
295 self["DVDPlayerPlaybackActions"] = HelpableActionMap(self, "DVDPlayerActions",
298 "dvdMenu": (self.enterDVDMenu, _("show DVD main menu")),
299 "toggleInfo": (self.toggleInfo, _("toggle time, chapter, audio, subtitle info")),
300 "nextChapter": (self.nextChapter, _("forward to the next chapter")),
301 "prevChapter": (self.prevChapter, _("rewind to the previous chapter")),
302 "nextTitle": (self.nextTitle, _("jump forward to the next title")),
303 "prevTitle": (self.prevTitle, _("jump back to the previous title")),
304 "tv": (self.askLeavePlayer, _("exit DVD player or return to file browser")),
305 "dvdAudioMenu": (self.enterDVDAudioMenu, _("(show optional DVD audio menu)")),
306 "nextAudioTrack": (self.nextAudioTrack, _("switch to the next audio track")),
307 "nextSubtitleTrack": (self.nextSubtitleTrack, _("switch to the next subtitle language")),
308 "seekBeginning": (self.seekBeginning, _("Jump to video title 1 (play movie from start)")),
311 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
313 "1": self.keyNumberGlobal,
314 "2": self.keyNumberGlobal,
315 "3": self.keyNumberGlobal,
316 "4": self.keyNumberGlobal,
317 "5": self.keyNumberGlobal,
318 "6": self.keyNumberGlobal,
319 "7": self.keyNumberGlobal,
320 "8": self.keyNumberGlobal,
321 "9": self.keyNumberGlobal,
322 "0": self.keyNumberGlobal,
325 self.onClose.append(self.__onClose)
328 self.dvd_device = dvd_device
329 self.physicalDVD = True
331 if fileExists("/dev/cdroms/cdrom0"):
332 print "physical dvd found (/dev/cdroms/cdrom0)"
333 self.dvd_device = "/dev/cdroms/cdrom0"
334 self.physicalDVD = True
336 self.dvd_device = None
337 self.physicalDVD = False
339 self.onFirstExecBegin.append(self.showFileBrowser)
342 self.old_aspect = open("/proc/stb/video/aspect", "r").read()
343 self.old_policy = open("/proc/stb/video/policy", "r").read()
344 self.old_wss = open("/proc/stb/denc/0/wss", "r").read()
346 def keyNumberGlobal(self, number):
347 print "You pressed number " + str(number)
348 self.session.openWithCallback(self.numberEntered, ChapterZap, number)
350 def numberEntered(self, retval):
351 # print self.servicelist
353 self.zapToNumber(retval)
355 def __serviceStopped(self):
356 self.dvdScreen.hide()
357 self.service.subtitle().disableSubtitles(self.session.current_dialog.instance)
359 def serviceStarted(self): #override InfoBarShowHide function
360 self.dvdScreen.show()
361 self.service.subtitle().enableSubtitles(self.dvdScreen.instance, None)
363 def doEofInternal(self, playing):
367 def __menuOpened(self):
370 self["NumberActions"].setEnabled(False)
372 def __menuClosed(self):
375 self["NumberActions"].setEnabled(True)
377 def setChapterLabel(self):
379 chapterOSD = "DVD Menu"
380 if self.currentTitle > 0:
381 chapterLCD = "%s %d" % (_("Chap."), self.currentChapter)
382 chapterOSD = "DVD %s %d/%d" % (_("Chapter"), self.currentChapter, self.totalChapters)
383 chapterOSD += " (%s %d/%d)" % (_("Title"), self.currentTitle, self.totalTitles)
384 self["chapterLabel"].setText(chapterOSD)
386 self.session.summary.updateChapter(chapterLCD)
393 def toggleInfo(self):
398 def __timeUpdated(self):
401 def __statePlay(self):
404 def __statePause(self):
407 def __osdFFwdInfoAvail(self):
408 self.setChapterLabel()
409 print "FFwdInfoAvail"
411 def __osdFBwdInfoAvail(self):
412 self.setChapterLabel()
413 print "FBwdInfoAvail"
415 def __osdStringAvail(self):
418 def __osdAudioInfoAvail(self):
419 audioString = self.service.info().getInfoString(iServiceInformation.sUser+6)
420 print "AudioInfoAvail "+audioString
421 self["audioLabel"].setText(audioString)
425 def __osdSubtitleInfoAvail(self):
426 subtitleString = self.service.info().getInfoString(iServiceInformation.sUser+7)
427 print "SubtitleInfoAvail "+subtitleString
428 self["subtitleLabel"].setText(subtitleString)
432 def __chapterUpdated(self):
433 self.currentChapter = self.service.info().getInfo(iServiceInformation.sUser+8)
434 self.totalChapters = self.service.info().getInfo(iServiceInformation.sUser+80)
435 self.setChapterLabel()
436 print "__chapterUpdated: %d/%d" % (self.currentChapter, self.totalChapters)
438 def __titleUpdated(self):
439 self.currentTitle = self.service.info().getInfo(iServiceInformation.sUser+9)
440 self.totalTitles = self.service.info().getInfo(iServiceInformation.sUser+90)
441 self.setChapterLabel()
442 print "__titleUpdated: %d/%d" % (self.currentTitle, self.totalTitles)
446 #def __initializeDVDinfo(self):
447 #self.__osdAudioInfoAvail()
448 #self.__osdSubtitleInfoAvail()
450 def askLeavePlayer(self):
452 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list=[(_("Continue playing"), "play"), (_("Exit"), "exit")])
454 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list=[(_("Continue playing"), "play"), (_("Return to file browser"), "browser"), (_("Exit"), "exit")])
456 def nextAudioTrack(self):
458 self.service.keys().keyPressed(iServiceKeys.keyUser)
460 def nextSubtitleTrack(self):
462 self.service.keys().keyPressed(iServiceKeys.keyUser+1)
464 def enterDVDAudioMenu(self):
466 self.service.keys().keyPressed(iServiceKeys.keyUser+2)
468 def nextChapter(self):
470 self.service.keys().keyPressed(iServiceKeys.keyUser+3)
472 def prevChapter(self):
474 self.service.keys().keyPressed(iServiceKeys.keyUser+4)
478 self.service.keys().keyPressed(iServiceKeys.keyUser+5)
482 self.service.keys().keyPressed(iServiceKeys.keyUser+6)
484 def enterDVDMenu(self):
486 self.service.keys().keyPressed(iServiceKeys.keyUser+7)
488 def seekBeginning(self):
490 seekable = self.getSeek()
491 if seekable is not None:
494 def zapToNumber(self, number):
496 seekable = self.getSeek()
497 if seekable is not None:
498 print "seek to chapter %d" % number
499 seekable.seekChapter(number)
504 self.service.keys().keyPressed(iServiceKeys.keyRight)
508 self.service.keys().keyPressed(iServiceKeys.keyLeft)
512 self.service.keys().keyPressed(iServiceKeys.keyUp)
516 self.service.keys().keyPressed(iServiceKeys.keyDown)
522 self.service.keys().keyPressed(iServiceKeys.keyOk)
525 self.askLeavePlayer()
527 def showFileBrowser(self):
529 if self.dvd_device == "/dev/cdroms/cdrom0":
530 self.session.openWithCallback(self.DVDdriveCB, MessageBox, text=_("Do you want to play DVD in drive?"), timeout=5 )
532 self.DVDdriveCB(True)
534 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
536 def DVDdriveCB(self, answer):
538 self.FileBrowserClosed(self.dvd_device)
540 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
542 def FileBrowserClosed(self, val):
543 curref = self.session.nav.getCurrentlyPlayingServiceReference()
544 print "FileBrowserClosed", val
546 self.askLeavePlayer()
548 newref = eServiceReference(4369, 0, val)
549 print "play", newref.toString()
550 if curref is None or curref != newref:
551 self.session.nav.playService(newref)
552 self.service = self.session.nav.getCurrentService()
553 print "self.service", self.service
554 print "cur_dlg", self.session.current_dialog
556 def exitCB(self, answer):
557 if answer is not None:
558 if answer[1] == "exit":
562 if answer[1] == "browser":
563 #TODO check here if a paused dvd playback is already running... then re-start it...
565 self.showFileBrowser()
570 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)):
572 open(i[0], "w").write(i[1])
574 print "restore", i[0], "failed"
575 self.restore_infobar_seek_config()
576 self.session.nav.playService(self.oldService)
578 # def playLastCB(self, answer): # overwrite infobar cuesheet function
579 # print "playLastCB", answer, self.resume_point
580 # pos = self.resume_point
581 # title = self.resume_point % 90000
583 # chapter = title % 256
585 # print "pos", pos, "title", title, "chapter", chapter
587 # seek = self.service.seek()
589 # seek.seekTitle(title)
590 # self.resume_state = 1
592 # seek.seekChapter(chapter)
593 # self.resume_state = 2
596 # self.hideAfterResume()
598 def showAfterCuesheetOperation(self):
602 def createSummary(self):
603 print "DVDCreateSummary"
606 #override some InfoBarSeek functions
608 self.setSeekState(self.SEEK_STATE_PLAY)
610 def calcRemainingTime(self):
613 def main(session, **kwargs):
614 session.open(DVDPlayer)
616 def menu(menuid, **kwargs):
617 if menuid == "mainmenu":
618 return [(_("DVD Player"), main, "dvd_player", 46)]
621 from Plugins.Plugin import PluginDescriptor
623 #TODO add *.iso to filescanner and ask when more than one iso file is found
625 def filescan_open(list, session, **kwargs):
627 splitted = x.path.split('/')
628 print "splitted", splitted
629 if len(splitted) > 2:
630 if splitted[1] == 'autofs':
631 session.open(DVDPlayer, "/dev/%s" %(splitted[2]))
634 print "splitted[0]", splitted[1]
636 def filescan(**kwargs):
637 from Components.Scanner import Scanner, ScanPath
639 # Overwrite checkFile to only detect local
640 class LocalScanner(Scanner):
641 def checkFile(self, file):
642 return fileExists(file.path)
645 LocalScanner(mimetypes = None,
648 ScanPath(path = "video_ts", with_subdirs = False),
651 description = "Play DVD",
652 openfnc = filescan_open,
655 def Plugins(**kwargs):
656 return [PluginDescriptor(name = "DVDPlayer", description = "Play DVDs", where = PluginDescriptor.WHERE_MENU, fnc = menu),
657 PluginDescriptor(where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)]