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()
65 class DVDSummary(Screen):
67 <screen position="0,0" size="132,64">
68 <widget source="session.CurrentService" render="Label" position="5,4" size="120,28" font="Regular;12" transparent="1" >
69 <convert type="ServiceName">Name</convert>
71 <widget name="DVDPlayer" position="5,30" size="66,16" font="Regular;12" transparent="1" />
72 <widget name="Chapter" position="72,30" size="54,16" font="Regular;12" transparent="1" halign="right" />
73 <widget source="session.CurrentService" render="Label" position="66,46" size="60,18" font="Regular;16" transparent="1" halign="right" >
74 <convert type="ServicePosition">Position</convert>
76 <widget source="session.CurrentService" render="Progress" position="6,46" size="60,18" borderWidth="1" >
77 <convert type="ServicePosition">Position</convert>
81 def __init__(self, session, parent):
82 Screen.__init__(self, session, parent)
84 self["DVDPlayer"] = Label("DVD Player")
85 self["Title"] = Label("")
86 self["Time"] = Label("")
87 self["Chapter"] = Label("")
89 def updateChapter(self, chapter):
90 self["Chapter"].setText(chapter)
92 def setTitle(self, title):
93 self["Title"].setText(title)
95 class DVDOverlay(Screen):
96 skin = """<screen name="DVDOverlay" position="0,0" size="720,576" flags="wfNoBorder" zPosition="-1" backgroundColor="transparent" />"""
97 def __init__(self, session, args = None):
98 Screen.__init__(self, session)
100 class ChapterZap(Screen):
102 <screen name="ChapterZap" position="235,255" size="250,60" title="Chapter" >
103 <widget name="chapter" position="35,15" size="110,25" font="Regular;23" />
104 <widget name="number" position="145,15" size="80,25" halign="right" font="Regular;23" />
113 self.close(int(self["number"].getText()))
115 def keyNumberGlobal(self, number):
116 self.Timer.start(3000, True) #reset timer
117 self.field = self.field + str(number)
118 self["number"].setText(self.field)
119 if len(self.field) >= 4:
122 def __init__(self, session, number):
123 Screen.__init__(self, session)
124 self.field = str(number)
126 self["chapter"] = Label(_("Chapter:"))
128 self["number"] = Label(self.field)
130 self["actions"] = NumberActionMap( [ "SetupActions" ],
134 "1": self.keyNumberGlobal,
135 "2": self.keyNumberGlobal,
136 "3": self.keyNumberGlobal,
137 "4": self.keyNumberGlobal,
138 "5": self.keyNumberGlobal,
139 "6": self.keyNumberGlobal,
140 "7": self.keyNumberGlobal,
141 "8": self.keyNumberGlobal,
142 "9": self.keyNumberGlobal,
143 "0": self.keyNumberGlobal
146 self.Timer = eTimer()
147 self.Timer.callback.append(self.keyOK)
148 self.Timer.start(3000, True)
150 class DVDPlayer(Screen, InfoBarBase, InfoBarNotifications, InfoBarSeek, InfoBarPVRState, InfoBarShowHide, HelpableScreen):
151 #InfoBarCueSheetSupport,
152 # ALLOW_SUSPEND = True
153 # ENABLE_RESUME_SUPPORT = True
156 <screen name="DVDPlayer" flags="wfNoBorder" position="0,380" size="720,160" title="InfoBar" backgroundColor="transparent" >
158 <ePixmap position="0,0" zPosition="-2" size="720,160" pixmap="skin_default/info-bg_mp.png" alphatest="off" />
159 <ePixmap position="29,40" zPosition="0" size="665,104" pixmap="skin_default/screws_mp.png" alphatest="on" transparent="1" />
160 <!-- colorbuttons -->
161 <ePixmap position="48,70" zPosition="0" size="108,13" pixmap="skin_default/icons/mp_buttons.png" alphatest="on" />
163 <ePixmap pixmap="skin_default/icons/icon_event.png" position="207,78" zPosition="1" size="15,10" alphatest="on" />
164 <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">
165 <convert type="ServiceName">Name</convert>
167 <!-- Chapter info -->
168 <widget name="chapterLabel" position="230,96" size="360,22" font="Regular;20" foregroundColor="#c3c3c9" backgroundColor="#263c59" transparent="1" />
169 <!-- Audio track info -->
170 <ePixmap pixmap="skin_default/icons/icon_dolby.png" position="540,73" zPosition="1" size="26,16" alphatest="on"/>
171 <widget name="audioLabel" position="570,73" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
172 <!-- Subtitle track info -->
173 <widget source="session.CurrentService" render="Pixmap" pixmap="skin_default/icons/icon_txt.png" position="540,96" zPosition="1" size="26,16" alphatest="on" >
174 <convert type="ServiceInfo">HasTelext</convert>
175 <convert type="ConditionalShowHide" />
177 <widget name="subtitleLabel" position="570,96" size="130,22" font="Regular;18" backgroundColor="#263c59" shadowColor="#1d354c" shadowOffset="-1,-1" transparent="1" />
178 <!-- Elapsed time -->
179 <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" >
180 <convert type="ServicePosition">Position,ShowHours</convert>
182 <!-- Progressbar (movie position)-->
183 <widget source="session.CurrentService" render="PositionGauge" position="300,133" size="270,10" zPosition="2" pointer="skin_default/position_pointer.png:540,0" transparent="1" >
184 <convert type="ServicePosition">Gauge</convert>
186 <!-- Remaining time -->
187 <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" >
188 <convert type="ServicePosition">Remaining,Negate,ShowHours</convert>
192 def save_infobar_seek_config(self):
193 self.saved_config_speeds_forward = config.seek.speeds_forward.value
194 self.saved_config_speeds_backward = config.seek.speeds_backward.value
195 self.saved_config_enter_forward = config.seek.enter_forward.value
196 self.saved_config_enter_backward = config.seek.enter_backward.value
197 self.saved_config_seek_stepwise_minspeed = config.seek.stepwise_minspeed.value
198 self.saved_config_seek_stepwise_repeat = config.seek.stepwise_repeat.value
199 self.saved_config_seek_on_pause = config.seek.on_pause.value
200 self.saved_config_seek_speeds_slowmotion = config.seek.speeds_slowmotion.value
202 def change_infobar_seek_config(self):
203 config.seek.speeds_forward.value = [2, 4, 8, 16, 32, 64]
204 config.seek.speeds_backward.value = [8, 16, 32, 64]
205 config.seek.speeds_slowmotion.value = [ ]
206 config.seek.enter_forward.value = "2"
207 config.seek.enter_backward.value = "2"
208 config.seek.stepwise_minspeed.value = "Never"
209 config.seek.stepwise_repeat.value = "3"
210 config.seek.on_pause.value = "play"
212 def restore_infobar_seek_config(self):
213 config.seek.speeds_forward.value = self.saved_config_speeds_forward
214 config.seek.speeds_backward.value = self.saved_config_speeds_backward
215 config.seek.speeds_slowmotion.value = self.saved_config_seek_speeds_slowmotion
216 config.seek.enter_forward.value = self.saved_config_enter_forward
217 config.seek.enter_backward.value = self.saved_config_enter_backward
218 config.seek.stepwise_minspeed.value = self.saved_config_seek_stepwise_minspeed
219 config.seek.stepwise_repeat.value = self.saved_config_seek_stepwise_repeat
220 config.seek.on_pause.value = self.saved_config_seek_on_pause
222 def __init__(self, session, args = None):
223 Screen.__init__(self, session)
224 InfoBarBase.__init__(self)
225 InfoBarNotifications.__init__(self)
226 # InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions")
227 InfoBarShowHide.__init__(self)
228 HelpableScreen.__init__(self)
229 self.save_infobar_seek_config()
230 self.change_infobar_seek_config()
231 InfoBarSeek.__init__(self)
232 InfoBarPVRState.__init__(self)
233 self.dvdScreen = self.session.instantiateDialog(DVDOverlay)
235 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
236 self.session.nav.stopService()
237 self["audioLabel"] = Label("1")
238 self["subtitleLabel"] = Label("")
239 self["chapterLabel"] = Label("")
240 self.totalChapters = 0
241 self.currentChapter = 0
243 self.currentTitle = 0
245 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
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)
320 self.onFirstExecBegin.append(self.showFileBrowser)
324 def keyNumberGlobal(self, number):
325 print "You pressed number " + str(number)
326 self.session.openWithCallback(self.numberEntered, ChapterZap, number)
328 def numberEntered(self, retval):
329 # print self.servicelist
331 self.zapToNumber(retval)
333 def serviceStarted(self): #override InfoBarShowHide function
336 def doEofInternal(self, playing):
340 def __menuOpened(self):
343 self["NumberActions"].setEnabled(False)
345 def __menuClosed(self):
348 self["NumberActions"].setEnabled(True)
350 def setChapterLabel(self):
352 chapterOSD = "DVD Menu"
353 if self.currentTitle > 0:
354 chapterLCD = "%s %d" % (_("Chap."), self.currentChapter)
355 chapterOSD = "DVD %s %d/%d" % (_("Chapter"), self.currentChapter, self.totalChapters)
356 chapterOSD += " (%s %d/%d)" % (_("Title"), self.currentTitle, self.totalTitles)
357 self["chapterLabel"].setText(chapterOSD)
359 self.session.summary.updateChapter(chapterLCD)
366 def toggleInfo(self):
371 def __timeUpdated(self):
374 def __statePlay(self):
377 def __statePause(self):
380 def __osdFFwdInfoAvail(self):
381 self.setChapterLabel()
382 print "FFwdInfoAvail"
384 def __osdFBwdInfoAvail(self):
385 self.setChapterLabel()
386 print "FBwdInfoAvail"
388 def __osdStringAvail(self):
391 def __osdAudioInfoAvail(self):
392 audioString = self.service.info().getInfoString(iPlayableService.evUser+6)
393 print "AudioInfoAvail "+audioString
394 self["audioLabel"].setText(audioString)
398 def __osdSubtitleInfoAvail(self):
399 subtitleString = self.service.info().getInfoString(iPlayableService.evUser+7)
400 print "SubtitleInfoAvail "+subtitleString
401 self["subtitleLabel"].setText(subtitleString)
405 def __chapterUpdated(self):
406 self.currentChapter = self.service.info().getInfo(iPlayableService.evUser+8)
407 self.totalChapters = self.service.info().getInfo(iPlayableService.evUser+80)
408 self.setChapterLabel()
409 print "__chapterUpdated: %d/%d" % (self.currentChapter, self.totalChapters)
411 def __titleUpdated(self):
412 self.currentTitle = self.service.info().getInfo(iPlayableService.evUser+9)
413 self.totalTitles = self.service.info().getInfo(iPlayableService.evUser+90)
414 self.setChapterLabel()
415 print "__titleUpdated: %d/%d" % (self.currentTitle, self.totalTitles)
419 #def __initializeDVDinfo(self):
420 #self.__osdAudioInfoAvail()
421 #self.__osdSubtitleInfoAvail()
423 def askLeavePlayer(self):
424 self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list=[(_("Exit"), "exit"), (_("Return to file browser"), "browser"), (_("Continue playing"), "play")])
426 def nextAudioTrack(self):
428 self.service.keys().keyPressed(iServiceKeys.keyUser)
430 def nextSubtitleTrack(self):
432 self.service.keys().keyPressed(iServiceKeys.keyUser+1)
434 def enterDVDAudioMenu(self):
436 self.service.keys().keyPressed(iServiceKeys.keyUser+2)
438 def nextChapter(self):
440 self.service.keys().keyPressed(iServiceKeys.keyUser+3)
442 def prevChapter(self):
444 self.service.keys().keyPressed(iServiceKeys.keyUser+4)
448 self.service.keys().keyPressed(iServiceKeys.keyUser+5)
452 self.service.keys().keyPressed(iServiceKeys.keyUser+6)
454 def enterDVDMenu(self):
456 self.service.keys().keyPressed(iServiceKeys.keyUser+7)
458 def seekBeginning(self):
460 seekable = self.getSeek()
461 if seekable is not None:
464 def zapToNumber(self, number):
466 seekable = self.getSeek()
467 if seekable is not None:
468 print "seek to chapter %d" % number
469 seekable.seekChapter(number)
474 self.service.keys().keyPressed(iServiceKeys.keyRight)
478 self.service.keys().keyPressed(iServiceKeys.keyLeft)
482 self.service.keys().keyPressed(iServiceKeys.keyUp)
486 self.service.keys().keyPressed(iServiceKeys.keyDown)
492 self.service.keys().keyPressed(iServiceKeys.keyOk)
495 self.askLeavePlayer()
497 def showFileBrowser(self):
498 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser)
500 def FileBrowserClosed(self, val):
501 curref = self.session.nav.getCurrentlyPlayingServiceReference()
502 print "FileBrowserClosed", val
504 self.askLeavePlayer()
506 newref = eServiceReference(4369, 0, val)
507 print "play", newref.toString()
508 if curref is None or curref != newref:
509 self.session.nav.playService(newref)
510 self.service = self.session.nav.getCurrentService()
511 print "self.service", self.service
512 print "cur_dlg", self.session.current_dialog
513 self.dvdScreen.show()
514 self.service.subtitle().enableSubtitles(self.dvdScreen.instance, None)
516 def exitCB(self, answer):
517 if answer is not None:
518 if answer[1] == "exit":
520 self.dvdScreen.hide()
521 self.service.subtitle().disableSubtitles(self.session.current_dialog.instance)
524 if answer[1] == "browser":
525 #TODO check here if a paused dvd playback is already running... then re-start it...
527 self.showFileBrowser()
532 self.restore_infobar_seek_config()
533 self.session.nav.playService(self.oldService)
535 # def playLastCB(self, answer): # overwrite infobar cuesheet function
536 # print "playLastCB", answer, self.resume_point
537 # pos = self.resume_point
538 # title = self.resume_point % 90000
540 # chapter = title % 256
542 # print "pos", pos, "title", title, "chapter", chapter
544 # seek = self.service.seek()
546 # seek.seekTitle(title)
547 # self.resume_state = 1
549 # seek.seekChapter(chapter)
550 # self.resume_state = 2
553 # self.hideAfterResume()
555 def showAfterCuesheetOperation(self):
559 def createSummary(self):
560 print "DVDCreateSummary"
563 #override some InfoBarSeek functions
565 self.setSeekState(self.SEEK_STATE_PLAY)
567 def calcRemainingTime(self):
570 def main(session, **kwargs):
571 session.open(DVDPlayer)
573 def menu(menuid, **kwargs):
574 if menuid == "mainmenu":
575 return [(_("DVD Player"), main, "dvd_player", 46)]
578 from Plugins.Plugin import PluginDescriptor
579 def Plugins(**kwargs):
580 return [PluginDescriptor(name = "DVDPlayer", description = "Play DVDs", where = PluginDescriptor.WHERE_MENU, fnc = menu)]