from os import path as os_path, remove as os_remove, listdir as os_listdir, system from enigma import eTimer, iPlayableService, iServiceInformation, eServiceReference, iServiceKeys, getDesktop from Screens.Screen import Screen from Screens.MessageBox import MessageBox from Screens.ChoiceBox import ChoiceBox from Screens.HelpMenu import HelpableScreen from Screens.InfoBarGenerics import InfoBarSeek, InfoBarPVRState, InfoBarCueSheetSupport, InfoBarShowHide, InfoBarNotifications from Components.ActionMap import ActionMap, NumberActionMap, HelpableActionMap from Components.Label import Label from Components.Sources.StaticText import StaticText from Components.Pixmap import Pixmap from Components.FileList import FileList from Components.MenuList import MenuList from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase from Components.config import config from Tools.Directories import pathExists, fileExists from Components.Harddisk import harddiskmanager import servicedvd # load c++ part of dvd player plugin lastpath = "" class FileBrowser(Screen): def __init__(self, session, dvd_filelist = [ ]): Screen.__init__(self, session) # for the skin: first try FileBrowser_DVDPlayer, then FileBrowser, this allows individual skinning self.skinName = ["FileBrowser_DVDPlayer", "FileBrowser" ] self.dvd_filelist = dvd_filelist if len(dvd_filelist): self["filelist"] = MenuList(self.dvd_filelist) else: global lastpath if lastpath is not None: currDir = lastpath + "/" else: currDir = "/media/dvd/" if not pathExists(currDir): currDir = "/" self.filelist = FileList(currDir, matchingPattern = "(?i)^.*\.(iso)", useServiceRef = True) self["filelist"] = self.filelist self["FilelistActions"] = ActionMap(["SetupActions"], { "save": self.ok, "ok": self.ok, "cancel": self.exit }) self["key_red"] = StaticText(_("Cancel")) self["key_green"] = StaticText(_("OK")) self.onLayoutFinish.append(self.layoutFinished) def layoutFinished(self): self.setTitle(_("DVD File Browser")) def ok(self): if len(self.dvd_filelist): print "OK " + self["filelist"].getCurrent() self.close(self["filelist"].getCurrent()) else: global lastpath filename = self["filelist"].getFilename() if filename is not None: if filename.upper().endswith("VIDEO_TS/"): print "dvd structure found, trying to open..." dvdpath = filename[0:-9] lastpath = (dvdpath.rstrip("/").rsplit("/",1))[0] print "lastpath video_ts/=", lastpath self.close(dvdpath) return if self["filelist"].canDescent(): # isDir self["filelist"].descent() pathname = self["filelist"].getCurrentDirectory() or "" if fileExists(pathname+"VIDEO_TS.IFO"): print "dvd structure found, trying to open..." lastpath = (pathname.rstrip("/").rsplit("/",1))[0] print "lastpath video_ts.ifo=", lastpath self.close(pathname) else: lastpath = filename[0:filename.rfind("/")] print "lastpath directory=", lastpath self.close(filename) def exit(self): self.close(None) class DVDSummary(Screen): skin = ( """ Name Position Position """, """ Name Position Position """) def __init__(self, session, parent): Screen.__init__(self, session, parent) self["DVDPlayer"] = Label("DVD Player") self["Title"] = Label("") self["Time"] = Label("") self["Chapter"] = Label("") def updateChapter(self, chapter): self["Chapter"].setText(chapter) def setTitle(self, title): self["Title"].setText(title) class DVDOverlay(Screen): def __init__(self, session, args = None): desktop_size = getDesktop(0).size() DVDOverlay.skin = """""" %(desktop_size.width(), desktop_size.height()) Screen.__init__(self, session) class ChapterZap(Screen): skin = """ """ def quit(self): self.Timer.stop() self.close(0) def keyOK(self): self.Timer.stop() self.close(int(self["number"].getText())) def keyNumberGlobal(self, number): self.Timer.start(3000, True) #reset timer self.field = self.field + str(number) self["number"].setText(self.field) if len(self.field) >= 4: self.keyOK() def __init__(self, session, number): Screen.__init__(self, session) self.field = str(number) self["chapter"] = Label(_("Chapter:")) self["number"] = Label(self.field) self["actions"] = NumberActionMap( [ "SetupActions" ], { "cancel": self.quit, "ok": self.keyOK, "1": self.keyNumberGlobal, "2": self.keyNumberGlobal, "3": self.keyNumberGlobal, "4": self.keyNumberGlobal, "5": self.keyNumberGlobal, "6": self.keyNumberGlobal, "7": self.keyNumberGlobal, "8": self.keyNumberGlobal, "9": self.keyNumberGlobal, "0": self.keyNumberGlobal }) self.Timer = eTimer() self.Timer.callback.append(self.keyOK) self.Timer.start(3000, True) class DVDPlayer(Screen, InfoBarBase, InfoBarNotifications, InfoBarSeek, InfoBarPVRState, InfoBarShowHide, HelpableScreen, InfoBarCueSheetSupport): ALLOW_SUSPEND = Screen.SUSPEND_PAUSES ENABLE_RESUME_SUPPORT = True skin = """ Name HasTelext Position,ShowHours Gauge Remaining,Negate,ShowHours """ def save_infobar_seek_config(self): self.saved_config_speeds_forward = config.seek.speeds_forward.value self.saved_config_speeds_backward = config.seek.speeds_backward.value self.saved_config_enter_forward = config.seek.enter_forward.value self.saved_config_enter_backward = config.seek.enter_backward.value self.saved_config_seek_stepwise_minspeed = config.seek.stepwise_minspeed.value self.saved_config_seek_stepwise_repeat = config.seek.stepwise_repeat.value self.saved_config_seek_on_pause = config.seek.on_pause.value self.saved_config_seek_speeds_slowmotion = config.seek.speeds_slowmotion.value def change_infobar_seek_config(self): config.seek.speeds_forward.value = [2, 4, 8, 16, 32, 64] config.seek.speeds_backward.value = [8, 16, 32, 64] config.seek.speeds_slowmotion.value = [ ] config.seek.enter_forward.value = "2" config.seek.enter_backward.value = "2" config.seek.stepwise_minspeed.value = "Never" config.seek.stepwise_repeat.value = "3" config.seek.on_pause.value = "play" def restore_infobar_seek_config(self): config.seek.speeds_forward.value = self.saved_config_speeds_forward config.seek.speeds_backward.value = self.saved_config_speeds_backward config.seek.speeds_slowmotion.value = self.saved_config_seek_speeds_slowmotion config.seek.enter_forward.value = self.saved_config_enter_forward config.seek.enter_backward.value = self.saved_config_enter_backward config.seek.stepwise_minspeed.value = self.saved_config_seek_stepwise_minspeed config.seek.stepwise_repeat.value = self.saved_config_seek_stepwise_repeat config.seek.on_pause.value = self.saved_config_seek_on_pause def __init__(self, session, dvd_device = None, dvd_filelist = [ ], args = None): Screen.__init__(self, session) InfoBarBase.__init__(self) InfoBarNotifications.__init__(self) InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions") InfoBarShowHide.__init__(self) HelpableScreen.__init__(self) self.save_infobar_seek_config() self.change_infobar_seek_config() InfoBarSeek.__init__(self, useSeekBackHack=False) InfoBarPVRState.__init__(self) self.dvdScreen = self.session.instantiateDialog(DVDOverlay) self.oldService = self.session.nav.getCurrentlyPlayingServiceReference() self.session.nav.stopService() self["audioLabel"] = Label("n/a") self["subtitleLabel"] = Label("") self["angleLabel"] = Label("") self["chapterLabel"] = Label("") self["anglePix"] = Pixmap() self["anglePix"].hide() self.last_audioTuple = None self.last_subtitleTuple = None self.last_angleTuple = None self.totalChapters = 0 self.currentChapter = 0 self.totalTitles = 0 self.currentTitle = 0 self.__event_tracker = ServiceEventTracker(screen=self, eventmap= { iPlayableService.evStopped: self.__serviceStopped, iPlayableService.evUser: self.__timeUpdated, iPlayableService.evUser+1: self.__statePlay, iPlayableService.evUser+2: self.__statePause, iPlayableService.evUser+3: self.__osdFFwdInfoAvail, iPlayableService.evUser+4: self.__osdFBwdInfoAvail, iPlayableService.evUser+5: self.__osdStringAvail, iPlayableService.evUser+6: self.__osdAudioInfoAvail, iPlayableService.evUser+7: self.__osdSubtitleInfoAvail, iPlayableService.evUser+8: self.__chapterUpdated, iPlayableService.evUser+9: self.__titleUpdated, iPlayableService.evUser+11: self.__menuOpened, iPlayableService.evUser+12: self.__menuClosed, iPlayableService.evUser+13: self.__osdAngleInfoAvail }) self["DVDPlayerDirectionActions"] = ActionMap(["DirectionActions"], { #MENU KEY DOWN ACTIONS "left": self.keyLeft, "right": self.keyRight, "up": self.keyUp, "down": self.keyDown, #MENU KEY REPEATED ACTIONS "leftRepeated": self.doNothing, "rightRepeated": self.doNothing, "upRepeated": self.doNothing, "downRepeated": self.doNothing, #MENU KEY UP ACTIONS "leftUp": self.doNothing, "rightUp": self.doNothing, "upUp": self.doNothing, "downUp": self.doNothing, }) self["OkCancelActions"] = ActionMap(["OkCancelActions"], { "ok": self.keyOk, "cancel": self.keyCancel, }) self["DVDPlayerPlaybackActions"] = HelpableActionMap(self, "DVDPlayerActions", { #PLAYER ACTIONS "dvdMenu": (self.enterDVDMenu, _("show DVD main menu")), "toggleInfo": (self.toggleInfo, _("toggle time, chapter, audio, subtitle info")), "nextChapter": (self.nextChapter, _("forward to the next chapter")), "prevChapter": (self.prevChapter, _("rewind to the previous chapter")), "nextTitle": (self.nextTitle, _("jump forward to the next title")), "prevTitle": (self.prevTitle, _("jump back to the previous title")), "tv": (self.askLeavePlayer, _("exit DVD player or return to file browser")), "dvdAudioMenu": (self.enterDVDAudioMenu, _("(show optional DVD audio menu)")), "nextAudioTrack": (self.nextAudioTrack, _("switch to the next audio track")), "nextSubtitleTrack": (self.nextSubtitleTrack, _("switch to the next subtitle language")), "nextAngle": (self.nextAngle, _("switch to the next angle")), "seekBeginning": self.seekBeginning, }, -2) self["NumberActions"] = NumberActionMap( [ "NumberActions"], { "1": self.keyNumberGlobal, "2": self.keyNumberGlobal, "3": self.keyNumberGlobal, "4": self.keyNumberGlobal, "5": self.keyNumberGlobal, "6": self.keyNumberGlobal, "7": self.keyNumberGlobal, "8": self.keyNumberGlobal, "9": self.keyNumberGlobal, "0": self.keyNumberGlobal, }) self.onClose.append(self.__onClose) from Plugins.SystemPlugins.Hotplug.plugin import hotplugNotifier hotplugNotifier.append(self.hotplugCB) self.autoplay = dvd_device or dvd_filelist if dvd_device: self.physicalDVD = True else: self.scanHotplug() self.dvd_filelist = dvd_filelist self.onFirstExecBegin.append(self.opened) self.service = None self.in_menu = False def keyNumberGlobal(self, number): print "You pressed number " + str(number) self.session.openWithCallback(self.numberEntered, ChapterZap, number) def numberEntered(self, retval): # print self.servicelist if retval > 0: self.zapToNumber(retval) def getServiceInterface(self, iface): service = self.service if service: attr = getattr(service, iface, None) if callable(attr): return attr() return None def __serviceStopped(self): self.dvdScreen.hide() subs = self.getServiceInterface("subtitle") if subs: subs.disableSubtitles(self.session.current_dialog.instance) def serviceStarted(self): #override InfoBarShowHide function self.dvdScreen.show() def doEofInternal(self, playing): if self.in_menu: self.hide() def __menuOpened(self): self.hide() self.in_menu = True self["NumberActions"].setEnabled(False) def __menuClosed(self): self.show() self.in_menu = False self["NumberActions"].setEnabled(True) def setChapterLabel(self): chapterLCD = "Menu" chapterOSD = "DVD Menu" if self.currentTitle > 0: chapterLCD = "%s %d" % (_("Chap."), self.currentChapter) chapterOSD = "DVD %s %d/%d" % (_("Chapter"), self.currentChapter, self.totalChapters) chapterOSD += " (%s %d/%d)" % (_("Title"), self.currentTitle, self.totalTitles) self["chapterLabel"].setText(chapterOSD) try: self.session.summary.updateChapter(chapterLCD) except: pass def doNothing(self): pass def toggleInfo(self): if not self.in_menu: self.toggleShow() print "toggleInfo" def __timeUpdated(self): print "timeUpdated" def __statePlay(self): print "statePlay" def __statePause(self): print "statePause" def __osdFFwdInfoAvail(self): self.setChapterLabel() print "FFwdInfoAvail" def __osdFBwdInfoAvail(self): self.setChapterLabel() print "FBwdInfoAvail" def __osdStringAvail(self): print "StringAvail" def __osdAudioInfoAvail(self): info = self.getServiceInterface("info") audioTuple = info and info.getInfoObject(iServiceInformation.sUser+6) print "AudioInfoAvail ", repr(audioTuple) if audioTuple: audioString = "%d: %s (%s)" % (audioTuple[0],audioTuple[1],audioTuple[2]) self["audioLabel"].setText(audioString) if audioTuple != self.last_audioTuple and not self.in_menu: self.doShow() self.last_audioTuple = audioTuple def __osdSubtitleInfoAvail(self): info = self.getServiceInterface("info") subtitleTuple = info and info.getInfoObject(iServiceInformation.sUser+7) print "SubtitleInfoAvail ", repr(subtitleTuple) if subtitleTuple: subtitleString = "" if subtitleTuple[0] is not 0: subtitleString = "%d: %s" % (subtitleTuple[0],subtitleTuple[1]) self["subtitleLabel"].setText(subtitleString) if subtitleTuple != self.last_subtitleTuple and not self.in_menu: self.doShow() self.last_subtitleTuple = subtitleTuple def __osdAngleInfoAvail(self): info = self.getServiceInterface("info") angleTuple = info and info.getInfoObject(iServiceInformation.sUser+8) print "AngleInfoAvail ", repr(angleTuple) if angleTuple: angleString = "" if angleTuple[1] > 1: angleString = "%d / %d" % (angleTuple[0],angleTuple[1]) self["anglePix"].show() else: self["anglePix"].hide() self["angleLabel"].setText(angleString) if angleTuple != self.last_angleTuple and not self.in_menu: self.doShow() self.last_angleTuple = angleTuple def __chapterUpdated(self): info = self.getServiceInterface("info") if info: self.currentChapter = info.getInfo(iServiceInformation.sCurrentChapter) self.totalChapters = info.getInfo(iServiceInformation.sTotalChapters) self.setChapterLabel() print "__chapterUpdated: %d/%d" % (self.currentChapter, self.totalChapters) def __titleUpdated(self): info = self.getServiceInterface("info") if info: self.currentTitle = info.getInfo(iServiceInformation.sCurrentTitle) self.totalTitles = info.getInfo(iServiceInformation.sTotalTitles) self.setChapterLabel() print "__titleUpdated: %d/%d" % (self.currentTitle, self.totalTitles) if not self.in_menu: self.doShow() def askLeavePlayer(self): choices = [(_("Exit"), "exit"), (_("Continue playing"), "play")] if True or not self.physicalDVD: choices.insert(1,(_("Return to file browser"), "browser")) if self.physicalDVD: cur = self.session.nav.getCurrentlyPlayingServiceReference() if cur and not cur.toString().endswith(harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD())): choices.insert(0,(_("Play DVD"), "playPhysical" )) self.session.openWithCallback(self.exitCB, ChoiceBox, title=_("Leave DVD Player?"), list = choices) def sendKey(self, key): keys = self.getServiceInterface("keys") if keys: keys.keyPressed(key) return keys def nextAudioTrack(self): self.sendKey(iServiceKeys.keyUser) def nextSubtitleTrack(self): self.sendKey(iServiceKeys.keyUser+1) def enterDVDAudioMenu(self): self.sendKey(iServiceKeys.keyUser+2) def nextChapter(self): self.sendKey(iServiceKeys.keyUser+3) def prevChapter(self): self.sendKey(iServiceKeys.keyUser+4) def nextTitle(self): self.sendKey(iServiceKeys.keyUser+5) def prevTitle(self): self.sendKey(iServiceKeys.keyUser+6) def enterDVDMenu(self): self.sendKey(iServiceKeys.keyUser+7) def nextAngle(self): self.sendKey(iServiceKeys.keyUser+8) def seekBeginning(self): if self.service: seekable = self.getSeek() if seekable: seekable.seekTo(0) def zapToNumber(self, number): if self.service: seekable = self.getSeek() if seekable: print "seek to chapter %d" % number seekable.seekChapter(number) # MENU ACTIONS def keyRight(self): self.sendKey(iServiceKeys.keyRight) def keyLeft(self): self.sendKey(iServiceKeys.keyLeft) def keyUp(self): self.sendKey(iServiceKeys.keyUp) def keyDown(self): self.sendKey(iServiceKeys.keyDown) def keyOk(self): if self.sendKey(iServiceKeys.keyOk) and not self.in_menu: self.toggleInfo() def keyCancel(self): self.askLeavePlayer() def opened(self): if self.autoplay and self.dvd_filelist: # opened via autoplay self.FileBrowserClosed(self.dvd_filelist[0]) elif self.autoplay and self.physicalDVD: self.playPhysicalCB(True) elif self.physicalDVD: # opened from menu with dvd in drive self.session.openWithCallback(self.playPhysicalCB, MessageBox, text=_("Do you want to play DVD in drive?"), timeout=5 ) else: # opened from menu without dvd in drive self.session.openWithCallback(self.FileBrowserClosed, FileBrowser, self.dvd_filelist) def playPhysicalCB(self, answer): if answer == True: self.FileBrowserClosed(harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD())) else: self.session.openWithCallback(self.FileBrowserClosed, FileBrowser) def FileBrowserClosed(self, val): curref = self.session.nav.getCurrentlyPlayingServiceReference() print "FileBrowserClosed", val if val is None: self.askLeavePlayer() else: newref = eServiceReference(4369, 0, val) print "play", newref.toString() if curref is None or curref != newref: self.session.nav.playService(newref) self.service = self.session.nav.getCurrentService() print "self.service", self.service print "cur_dlg", self.session.current_dialog subs = self.getServiceInterface("subtitle") if subs: subs.enableSubtitles(self.dvdScreen.instance, None) def exitCB(self, answer): if answer is not None: if answer[1] == "exit": if self.service: self.service = None self.close() if answer[1] == "browser": #TODO check here if a paused dvd playback is already running... then re-start it... #else if self.service: self.service = None self.session.openWithCallback(self.FileBrowserClosed, FileBrowser) if answer[1] == "playPhysical": if self.service: self.service = None self.playPhysicalCB(True) else: pass def __onClose(self): self.restore_infobar_seek_config() self.session.nav.playService(self.oldService) from Plugins.SystemPlugins.Hotplug.plugin import hotplugNotifier hotplugNotifier.remove(self.hotplugCB) def playLastCB(self, answer): # overwrite infobar cuesheet function print "playLastCB", answer, self.resume_point if self.service: if answer == True: seekable = self.getSeek() if seekable: seekable.seekTo(self.resume_point) pause = self.service.pause() pause.unpause() self.hideAfterResume() def showAfterCuesheetOperation(self): if not self.in_menu: self.show() def createSummary(self): return DVDSummary #override some InfoBarSeek functions def doEof(self): self.setSeekState(self.SEEK_STATE_PLAY) def calcRemainingTime(self): return 0 def hotplugCB(self, dev, media_state): print "[hotplugCB]", dev, media_state if dev == harddiskmanager.getCD(): if media_state == "1": self.scanHotplug() else: self.physicalDVD = False def scanHotplug(self): devicepath = harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD()) if pathExists(devicepath): from Components.Scanner import scanDevice res = scanDevice(devicepath) list = [ (r.description, r, res[r], self.session) for r in res ] if list: (desc, scanner, files, session) = list[0] for file in files: print file if file.mimetype == "video/x-dvd": print "physical dvd found:", devicepath self.physicalDVD = True return self.physicalDVD = False def main(session, **kwargs): session.open(DVDPlayer) def menu(menuid, **kwargs): if menuid == "mainmenu": return [(_("DVD Player"), main, "dvd_player", 46)] return [] from Plugins.Plugin import PluginDescriptor def filescan_open(list, session, **kwargs): if len(list) == 1 and list[0].mimetype == "video/x-dvd": splitted = list[0].path.split('/') print "splitted", splitted if len(splitted) > 2: if splitted[1] == 'autofs': session.open(DVDPlayer, dvd_device="/dev/%s" %(splitted[2])) return else: print "splitted[0]", splitted[1] else: dvd_filelist = [] for x in list: if x.mimetype == "video/x-dvd-iso": dvd_filelist.append(x.path) if x.mimetype == "video/x-dvd": dvd_filelist.append(x.path.rsplit('/',1)[0]) session.open(DVDPlayer, dvd_filelist=dvd_filelist) def filescan(**kwargs): from Components.Scanner import Scanner, ScanPath # Overwrite checkFile to only detect local class LocalScanner(Scanner): def checkFile(self, file): return fileExists(file.path) return [ LocalScanner(mimetypes = ["video/x-dvd","video/x-dvd-iso"], paths_to_scan = [ ScanPath(path = "video_ts", with_subdirs = False), ScanPath(path = "VIDEO_TS", with_subdirs = False), ScanPath(path = "", with_subdirs = False), ], name = "DVD", description = _("Play DVD"), openfnc = filescan_open, )] def Plugins(**kwargs): return [PluginDescriptor(name = "DVDPlayer", description = "Play DVDs", where = PluginDescriptor.WHERE_MENU, fnc = menu), PluginDescriptor(where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)]