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.ServiceEventTracker import ServiceEventTracker, InfoBarBase
12 from Components.config import config
13 from Tools.Directories import pathExists, fileExists
15 import servicedvd # load c++ part of dvd player plugin
19 class FileBrowser(Screen):
21 <screen name="FileBrowser" position="100,100" size="520,376" title="DVD File Browser" >
22 <widget name="filelist" position="0,0" size="520,376" scrollbarMode="showOnDemand" />
24 def __init__(self, session):
25 Screen.__init__(self, session)
27 if lastpath is not None:
28 currDir = lastpath + "/"
30 currDir = "/media/dvd/"
31 if not pathExists(currDir):
34 #print system("mount "+currDir)
35 self.filelist = FileList(currDir, matchingPattern = "(?i)^.*\.(iso)", useServiceRef = True)
36 self["filelist"] = self.filelist
38 self["FilelistActions"] = ActionMap(["OkCancelActions"],
46 filename = self["filelist"].getFilename()
47 if filename is not None:
48 lastpath = filename[0:filename.rfind("/")]
49 if filename.upper().endswith("VIDEO_TS/"):
50 print "dvd structure found, trying to open..."
51 self.close(filename[0:-9])
52 if self["filelist"].canDescent(): # isDir
53 self["filelist"].descent()
54 pathname = self["filelist"].getCurrentDirectory() or ""
55 if fileExists(pathname+"VIDEO_TS.IFO"):
56 print "dvd structure found, trying to open..."
64 class DVDSummary(Screen):
66 <screen position="0,0" size="132,64">
67 <widget source="session.CurrentService" render="Label" position="5,4" size="120,28" font="Regular;12" transparent="1" >
68 <convert type="ServiceName">Name</convert>
70 <widget name="DVDPlayer" position="5,30" size="66,16" font="Regular;12" transparent="1" />
71 <widget name="Chapter" position="72,30" size="54,16" font="Regular;12" transparent="1" halign="right" />
72 <widget source="session.CurrentService" render="Label" position="66,46" size="60,18" font="Regular;16" transparent="1" halign="right" >
73 <convert type="ServicePosition">Position</convert>
75 <widget source="session.CurrentService" render="Progress" position="6,46" size="60,18" borderWidth="1" >
76 <convert type="ServicePosition">Position</convert>
80 def __init__(self, session, parent):
81 Screen.__init__(self, session, parent)
83 self["DVDPlayer"] = Label("DVD Player")
84 self["Title"] = Label("")
85 self["Time"] = Label("")
86 self["Chapter"] = Label("")
88 def updateChapter(self, chapter):
89 self["Chapter"].setText(chapter)
91 def setTitle(self, title):
92 self["Title"].setText(title)
94 class DVDOverlay(Screen):
95 skin = """<screen name="DVDOverlay" position="0,0" size="720,576" flags="wfNoBorder" zPosition="-1" backgroundColor="transparent" />"""
96 def __init__(self, session, args = None):
97 Screen.__init__(self, session)
99 class ChapterZap(Screen):
101 <screen name="ChapterZap" position="235,255" size="250,60" title="Chapter" >
102 <widget name="chapter" position="35,15" size="110,25" font="Regular;23" />
103 <widget name="number" position="145,15" size="80,25" halign="right" font="Regular;23" />
112 self.close(int(self["number"].getText()))
114 def keyNumberGlobal(self, number):
115 self.Timer.start(3000, True) #reset timer
116 self.field = self.field + str(number)
117 self["number"].setText(self.field)
118 if len(self.field) >= 4:
121 def __init__(self, session, number):
122 Screen.__init__(self, session)
123 self.field = str(number)
125 self["chapter"] = Label(_("Chapter:"))
127 self["number"] = Label(self.field)
129 self["actions"] = NumberActionMap( [ "SetupActions" ],
133 "1": self.keyNumberGlobal,
134 "2": self.keyNumberGlobal,
135 "3": self.keyNumberGlobal,
136 "4": self.keyNumberGlobal,
137 "5": self.keyNumberGlobal,
138 "6": self.keyNumberGlobal,
139 "7": self.keyNumberGlobal,
140 "8": self.keyNumberGlobal,
141 "9": self.keyNumberGlobal,
142 "0": self.keyNumberGlobal
145 self.Timer = eTimer()
146 self.Timer.callback.append(self.keyOK)
147 self.Timer.start(3000, True)
149 class DVDPlayer(Screen, InfoBarBase, InfoBarNotifications, InfoBarSeek, InfoBarPVRState, InfoBarShowHide, HelpableScreen):
150 #InfoBarCueSheetSupport,
151 # ALLOW_SUSPEND = True
152 # ENABLE_RESUME_SUPPORT = True
155 <screen name="DVDPlayer" flags="wfNoBorder" position="0,380" size="720,160" title="InfoBar" backgroundColor="transparent" >
157 <ePixmap position="0,0" zPosition="-2" size="720,160" pixmap="skin_default/info-bg_mp.png" alphatest="off" />
158 <ePixmap position="29,40" zPosition="0" size="665,104" pixmap="skin_default/screws_mp.png" alphatest="on" transparent="1" />
159 <!-- colorbuttons -->
160 <ePixmap position="48,70" zPosition="0" size="108,13" pixmap="skin_default/icons/mp_buttons.png" alphatest="on" />
162 <ePixmap pixmap="skin_default/icons/icon_event.png" position="207,78" zPosition="1" size="15,10" alphatest="on" />
163 <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">
164 <convert type="ServiceName">Name</convert>
166 <!-- Chapter info -->
167 <widget name="chapterLabel" position="230,96" size="360,22" font="Regular;20" foregroundColor="#c3c3c9" backgroundColor="#263c59" transparent="1" />
168 <!-- Audio track info -->
169 <ePixmap pixmap="skin_default/icons/icon_dolby.png" position="540,73" zPosition="1" size="26,16" alphatest="on"/>
170 <widget name="audioLabel" position="570,73" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
171 <!-- Subtitle track info -->
172 <widget source="session.CurrentService" render="Pixmap" pixmap="skin_default/icons/icon_txt.png" position="540,96" zPosition="1" size="26,16" alphatest="on" >
173 <convert type="ServiceInfo">HasTelext</convert>
174 <convert type="ConditionalShowHide" />
176 <widget name="subtitleLabel" position="570,96" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
177 <!-- Elapsed time -->
178 <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" >
179 <convert type="ServicePosition">Position,ShowHours</convert>
181 <!-- Progressbar (movie position)-->
182 <widget source="session.CurrentService" render="PositionGauge" position="300,133" size="270,10" zPosition="2" pointer="skin_default/position_pointer.png:540,0" transparent="1" >
183 <convert type="ServicePosition">Gauge</convert>
185 <!-- Remaining time -->
186 <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" >
187 <convert type="ServicePosition">Remaining,Negate,ShowHours</convert>
191 def save_infobar_seek_config(self):
192 self.saved_config_speeds_forward = config.seek.speeds_forward.value
193 self.saved_config_speeds_backward = config.seek.speeds_backward.value
194 self.saved_config_enter_forward = config.seek.enter_forward.value
195 self.saved_config_enter_backward = config.seek.enter_backward.value
196 self.saved_config_seek_stepwise_minspeed = config.seek.stepwise_minspeed.value
197 self.saved_config_seek_stepwise_repeat = config.seek.stepwise_repeat.value
198 self.saved_config_seek_on_pause = config.seek.on_pause.value
199 self.saved_config_seek_speeds_slowmotion = config.seek.speeds_slowmotion.value
201 def change_infobar_seek_config(self):
202 config.seek.speeds_forward.value = [2, 4, 8, 16, 32, 64]
203 config.seek.speeds_backward.value = [8, 16, 32, 64]
204 config.seek.speeds_slowmotion.value = [ ]
205 config.seek.enter_forward.value = "2"
206 config.seek.enter_backward.value = "2"
207 config.seek.stepwise_minspeed.value = "Never"
208 config.seek.stepwise_repeat.value = "3"
209 config.seek.on_pause.value = "play"
211 def restore_infobar_seek_config(self):
212 config.seek.speeds_forward.value = self.saved_config_speeds_forward
213 config.seek.speeds_backward.value = self.saved_config_speeds_backward
214 config.seek.speeds_slowmotion.value = self.saved_config_seek_speeds_slowmotion
215 config.seek.enter_forward.value = self.saved_config_enter_forward
216 config.seek.enter_backward.value = self.saved_config_enter_backward
217 config.seek.stepwise_minspeed.value = self.saved_config_seek_stepwise_minspeed
218 config.seek.stepwise_repeat.value = self.saved_config_seek_stepwise_repeat
219 config.seek.on_pause.value = self.saved_config_seek_on_pause
221 def __init__(self, session, dvd_device = None, args = None):
222 Screen.__init__(self, session)
223 InfoBarBase.__init__(self)
224 InfoBarNotifications.__init__(self)
225 # InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions")
226 InfoBarShowHide.__init__(self)
227 HelpableScreen.__init__(self)
228 self.save_infobar_seek_config()
229 self.change_infobar_seek_config()
230 InfoBarSeek.__init__(self, useSeekBackHack=False)
231 InfoBarPVRState.__init__(self)
232 self.dvdScreen = self.session.instantiateDialog(DVDOverlay)
234 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
235 self.session.nav.stopService()
236 self["audioLabel"] = Label("1")
237 self["subtitleLabel"] = Label("")
238 self["chapterLabel"] = Label("")
239 self.totalChapters = 0
240 self.currentChapter = 0
242 self.currentTitle = 0
244 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
246 iPlayableService.evStopped: self.__serviceStopped,
247 iPlayableService.evUser: self.__timeUpdated,
248 iPlayableService.evUser+1: self.__statePlay,
249 iPlayableService.evUser+2: self.__statePause,
250 iPlayableService.evUser+3: self.__osdFFwdInfoAvail,
251 iPlayableService.evUser+4: self.__osdFBwdInfoAvail,
252 iPlayableService.evUser+5: self.__osdStringAvail,
253 iPlayableService.evUser+6: self.__osdAudioInfoAvail,
254 iPlayableService.evUser+7: self.__osdSubtitleInfoAvail,
255 iPlayableService.evUser+8: self.__chapterUpdated,
256 iPlayableService.evUser+9: self.__titleUpdated,
257 #iPlayableService.evUser+10: self.__initializeDVDinfo,
258 iPlayableService.evUser+11: self.__menuOpened,
259 iPlayableService.evUser+12: self.__menuClosed
262 self["DVDPlayerDirectionActions"] = HelpableActionMap(self, "DirectionActions",
264 #MENU KEY DOWN ACTIONS
265 "left": (self.keyLeft, _("DVD left key")),
266 "right": (self.keyRight, _("DVD right key")),
267 "up": (self.keyUp, _("DVD up key")),
268 "down": (self.keyDown, _("DVD down key")),
270 #MENU KEY REPEATED ACTIONS
271 "leftRepeated": self.doNothing,
272 "rightRepeated": self.doNothing,
273 "upRepeated": self.doNothing,
274 "downRepeated": self.doNothing,
277 "leftUp": self.doNothing,
278 "rightUp": self.doNothing,
279 "upUp": self.doNothing,
280 "downUp": self.doNothing,
283 self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions",
285 "ok": (self.keyOk, _("DVD ENTER key")),
286 "cancel": self.keyCancel,
289 self["DVDPlayerPlaybackActions"] = HelpableActionMap(self, "DVDPlayerActions",
292 "dvdMenu": (self.enterDVDMenu, _("show DVD main menu")),
293 "toggleInfo": (self.toggleInfo, _("toggle time, chapter, audio, subtitle info")),
294 "nextChapter": (self.nextChapter, _("forward to the next chapter")),
295 "prevChapter": (self.prevChapter, _("rewind to the previous chapter")),
296 "nextTitle": (self.nextTitle, _("jump forward to the next title")),
297 "prevTitle": (self.prevTitle, _("jump back to the previous title")),
298 "tv": (self.askLeavePlayer, _("exit DVD player or return to file browser")),
299 "dvdAudioMenu": (self.enterDVDAudioMenu, _("(show optional DVD audio menu)")),
300 "nextAudioTrack": (self.nextAudioTrack, _("switch to the next audio track")),
301 "nextSubtitleTrack": (self.nextSubtitleTrack, _("switch to the next subtitle language")),
302 "seekBeginning": (self.seekBeginning, _("Jump to video title 1 (play movie from start)")),
305 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
307 "1": self.keyNumberGlobal,
308 "2": self.keyNumberGlobal,
309 "3": self.keyNumberGlobal,
310 "4": self.keyNumberGlobal,
311 "5": self.keyNumberGlobal,
312 "6": self.keyNumberGlobal,
313 "7": self.keyNumberGlobal,
314 "8": self.keyNumberGlobal,
315 "9": self.keyNumberGlobal,
316 "0": self.keyNumberGlobal,
319 self.onClose.append(self.__onClose)
322 self.dvd_device = dvd_device
323 self.physicalDVD = True
325 if fileExists("/dev/cdroms/cdrom0"):
326 print "physical dvd found (/dev/cdroms/cdrom0)"
327 self.dvd_device = "/dev/cdroms/cdrom0"
328 self.physicalDVD = True
330 self.dvd_device = None
331 self.physicalDVD = False
333 self.onFirstExecBegin.append(self.showFileBrowser)
336 self.old_aspect = open("/proc/stb/video/aspect", "r").read()
337 self.old_policy = open("/proc/stb/video/policy", "r").read()
338 self.old_wss = open("/proc/stb/denc/0/wss", "r").read()
340 def keyNumberGlobal(self, number):
341 print "You pressed number " + str(number)
342 self.session.openWithCallback(self.numberEntered, ChapterZap, number)
344 def numberEntered(self, retval):
345 # print self.servicelist
347 self.zapToNumber(retval)
349 def __serviceStopped(self):
350 self.dvdScreen.hide()
351 self.service.subtitle().disableSubtitles(self.session.current_dialog.instance)
353 def serviceStarted(self): #override InfoBarShowHide function
354 self.dvdScreen.show()
355 self.service.subtitle().enableSubtitles(self.dvdScreen.instance, None)
357 def doEofInternal(self, playing):
361 def __menuOpened(self):
364 self["NumberActions"].setEnabled(False)
366 def __menuClosed(self):
369 self["NumberActions"].setEnabled(True)
371 def setChapterLabel(self):
373 chapterOSD = "DVD Menu"
374 if self.currentTitle > 0:
375 chapterLCD = "%s %d" % (_("Chap."), self.currentChapter)
376 chapterOSD = "DVD %s %d/%d" % (_("Chapter"), self.currentChapter, self.totalChapters)
377 chapterOSD += " (%s %d/%d)" % (_("Title"), self.currentTitle, self.totalTitles)
378 self["chapterLabel"].setText(chapterOSD)
380 self.session.summary.updateChapter(chapterLCD)
387 def toggleInfo(self):
392 def __timeUpdated(self):
395 def __statePlay(self):
398 def __statePause(self):
401 def __osdFFwdInfoAvail(self):
402 self.setChapterLabel()
403 print "FFwdInfoAvail"
405 def __osdFBwdInfoAvail(self):
406 self.setChapterLabel()
407 print "FBwdInfoAvail"
409 def __osdStringAvail(self):
412 def __osdAudioInfoAvail(self):
413 audioString = self.service.info().getInfoString(iServiceInformation.sUser+6)
414 print "AudioInfoAvail "+audioString
415 self["audioLabel"].setText(audioString)
419 def __osdSubtitleInfoAvail(self):
420 subtitleString = self.service.info().getInfoString(iServiceInformation.sUser+7)
421 print "SubtitleInfoAvail "+subtitleString
422 self["subtitleLabel"].setText(subtitleString)
426 def __chapterUpdated(self):
427 self.currentChapter = self.service.info().getInfo(iServiceInformation.sUser+8)
428 self.totalChapters = self.service.info().getInfo(iServiceInformation.sUser+80)
429 self.setChapterLabel()
430 print "__chapterUpdated: %d/%d" % (self.currentChapter, self.totalChapters)
432 def __titleUpdated(self):
433 self.currentTitle = self.service.info().getInfo(iServiceInformation.sUser+9)
434 self.totalTitles = self.service.info().getInfo(iServiceInformation.sUser+90)
435 self.setChapterLabel()
436 print "__titleUpdated: %d/%d" % (self.currentTitle, self.totalTitles)
440 #def __initializeDVDinfo(self):
441 #self.__osdAudioInfoAvail()
442 #self.__osdSubtitleInfoAvail()
444 def askLeavePlayer(self):
446 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list=[(_("Continue playing"), "play"), (_("Exit"), "exit")])
448 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list=[(_("Continue playing"), "play"), (_("Return to file browser"), "browser"), (_("Exit"), "exit")])
450 def nextAudioTrack(self):
452 self.service.keys().keyPressed(iServiceKeys.keyUser)
454 def nextSubtitleTrack(self):
456 self.service.keys().keyPressed(iServiceKeys.keyUser+1)
458 def enterDVDAudioMenu(self):
460 self.service.keys().keyPressed(iServiceKeys.keyUser+2)
462 def nextChapter(self):
464 self.service.keys().keyPressed(iServiceKeys.keyUser+3)
466 def prevChapter(self):
468 self.service.keys().keyPressed(iServiceKeys.keyUser+4)
472 self.service.keys().keyPressed(iServiceKeys.keyUser+5)
476 self.service.keys().keyPressed(iServiceKeys.keyUser+6)
478 def enterDVDMenu(self):
480 self.service.keys().keyPressed(iServiceKeys.keyUser+7)
482 def seekBeginning(self):
484 seekable = self.getSeek()
485 if seekable is not None:
488 def zapToNumber(self, number):
490 seekable = self.getSeek()
491 if seekable is not None:
492 print "seek to chapter %d" % number
493 seekable.seekChapter(number)
498 self.service.keys().keyPressed(iServiceKeys.keyRight)
502 self.service.keys().keyPressed(iServiceKeys.keyLeft)
506 self.service.keys().keyPressed(iServiceKeys.keyUp)
510 self.service.keys().keyPressed(iServiceKeys.keyDown)
516 self.service.keys().keyPressed(iServiceKeys.keyOk)
519 self.askLeavePlayer()
521 def showFileBrowser(self):
523 if self.dvd_device == "/dev/cdroms/cdrom0":
524 self.session.openWithCallback(self.DVDdriveCB, MessageBox, text=_("Do you want to play DVD in drive?"), timeout=5 )
526 self.DVDdriveCB(True)
528 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
530 def DVDdriveCB(self, answer):
532 self.FileBrowserClosed(self.dvd_device)
534 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
536 def FileBrowserClosed(self, val):
537 curref = self.session.nav.getCurrentlyPlayingServiceReference()
538 print "FileBrowserClosed", val
540 self.askLeavePlayer()
542 newref = eServiceReference(4369, 0, val)
543 print "play", newref.toString()
544 if curref is None or curref != newref:
545 self.session.nav.playService(newref)
546 self.service = self.session.nav.getCurrentService()
547 print "self.service", self.service
548 print "cur_dlg", self.session.current_dialog
550 def exitCB(self, answer):
551 if answer is not None:
552 if answer[1] == "exit":
556 if answer[1] == "browser":
557 #TODO check here if a paused dvd playback is already running... then re-start it...
561 self.showFileBrowser()
566 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)):
568 open(i[0], "w").write(i[1])
570 print "restore", i[0], "failed"
571 self.restore_infobar_seek_config()
572 self.session.nav.playService(self.oldService)
574 # def playLastCB(self, answer): # overwrite infobar cuesheet function
575 # print "playLastCB", answer, self.resume_point
576 # pos = self.resume_point
577 # title = self.resume_point % 90000
579 # chapter = title % 256
581 # print "pos", pos, "title", title, "chapter", chapter
583 # seek = self.service.seek()
585 # seek.seekTitle(title)
586 # self.resume_state = 1
588 # seek.seekChapter(chapter)
589 # self.resume_state = 2
592 # self.hideAfterResume()
594 def showAfterCuesheetOperation(self):
598 def createSummary(self):
601 #override some InfoBarSeek functions
603 self.setSeekState(self.SEEK_STATE_PLAY)
605 def calcRemainingTime(self):
608 def main(session, **kwargs):
609 session.open(DVDPlayer)
611 def menu(menuid, **kwargs):
612 if menuid == "mainmenu":
613 return [(_("DVD Player"), main, "dvd_player", 46)]
616 from Plugins.Plugin import PluginDescriptor
618 #TODO add *.iso to filescanner and ask when more than one iso file is found
620 def filescan_open(list, session, **kwargs):
622 splitted = x.path.split('/')
623 print "splitted", splitted
624 if len(splitted) > 2:
625 if splitted[1] == 'autofs':
626 session.open(DVDPlayer, "/dev/%s" %(splitted[2]))
629 print "splitted[0]", splitted[1]
631 def filescan(**kwargs):
632 from Components.Scanner import Scanner, ScanPath
634 # Overwrite checkFile to only detect local
635 class LocalScanner(Scanner):
636 def checkFile(self, file):
637 return fileExists(file.path)
640 LocalScanner(mimetypes = None,
643 ScanPath(path = "video_ts", with_subdirs = False),
646 description = "Play DVD",
647 openfnc = filescan_open,
650 def Plugins(**kwargs):
651 return [PluginDescriptor(name = "DVDPlayer", description = "Play DVDs", where = PluginDescriptor.WHERE_MENU, fnc = menu),
652 PluginDescriptor(where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)]