X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/be98c731e6b92060760fb0c5e8567dcf747235e5..8105da47caaa6e47246d73239d056491fa091ae5:/lib/python/Plugins/Extensions/MediaPlayer/plugin.py diff --git a/lib/python/Plugins/Extensions/MediaPlayer/plugin.py b/lib/python/Plugins/Extensions/MediaPlayer/plugin.py index 2c9097fb..afb8772e 100644 --- a/lib/python/Plugins/Extensions/MediaPlayer/plugin.py +++ b/lib/python/Plugins/Extensions/MediaPlayer/plugin.py @@ -1,20 +1,20 @@ -from os import path as os_path, remove as os_remove, listdir as os_listdir +from os import path as os_path, remove as os_remove, listdir as os_listdir, popen from time import strftime -from enigma import eTimer, iPlayableService, eServiceCenter, iServiceInformation +from enigma import iPlayableService, eTimer, eServiceCenter, iServiceInformation from Screens.Screen import Screen from Screens.MessageBox import MessageBox from Screens.InputBox import InputBox from Components.ActionMap import NumberActionMap, HelpableActionMap from Components.Label import Label -from Components.Pixmap import Pixmap +from Components.Pixmap import Pixmap,MultiPixmap from Components.Label import Label from Components.FileList import FileList from Components.MediaPlayer import PlayList from Tools.Directories import resolveFilename, SCOPE_CONFIG, SCOPE_PLAYLIST, SCOPE_SKIN_IMAGE from Components.ServicePosition import ServicePositionGauge -from Components.ServiceEventTracker import ServiceEventTracker +from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase from Components.Playlist import PlaylistIOInternal, PlaylistIOM3U, PlaylistIOPLS -from Screens.InfoBarGenerics import InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSupport, InfoBarNotifications +from Screens.InfoBarGenerics import InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSupport, InfoBarNotifications, InfoBarSubtitleSupport from ServiceReference import ServiceReference from Screens.ChoiceBox import ChoiceBox from Screens.HelpMenu import HelpableScreen @@ -31,17 +31,18 @@ class MyPlayList(PlayList): self.oldCurrPlaying = -1 class MediaPixmap(Pixmap): - def applySkin(self, desktop): + def applySkin(self, desktop, screen): self.default_pixmap = None - for (attrib, value) in self.skinAttributes: - if attrib == "pixmap": - self.default_pixmap = value - break + if self.skinAttributes is not None: + for (attrib, value) in self.skinAttributes: + if attrib == "pixmap": + self.default_pixmap = value + break if self.default_pixmap is None: - self.default_pixmap = resolveFilename(SCOPE_SKIN_IMAGE, "no_coverArt.png") - return Pixmap.applySkin(self, desktop) + self.default_pixmap = resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/no_coverArt.png") + return Pixmap.applySkin(self, desktop, screen) -class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSupport, InfoBarNotifications, HelpableScreen): +class MediaPlayer(Screen, InfoBarBase, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSupport, InfoBarNotifications, InfoBarSubtitleSupport, HelpableScreen): ALLOW_SUSPEND = True ENABLE_RESUME_SUPPORT = True @@ -50,6 +51,8 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup InfoBarAudioSelection.__init__(self) InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions") InfoBarNotifications.__init__(self) + InfoBarBase.__init__(self) + InfoBarSubtitleSupport.__init__(self) HelpableScreen.__init__(self) self.summary = None self.oldService = self.session.nav.getCurrentlyPlayingServiceReference() @@ -61,7 +64,7 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup self.addPlaylistParser(PlaylistIOInternal, "e2pls") # 'None' is magic to start at the list of mountpoints - self.filelist = FileList(None, matchingPattern = "(?i)^.*\.(mp3|ogg|ts|wav|wave|m3u|pls|e2pls|mpg|vob)", useServiceRef = True) + self.filelist = FileList(None, matchingPattern = "(?i)^.*\.(mp3|ogg|ts|wav|wave|m3u|pls|e2pls|mpg|vob|avi|mkv|dat|flac)", useServiceRef = True, additionalExtensions = "4098:m3u 4098:e2pls 4098:pls") self["filelist"] = self.filelist self.playlist = MyPlayList() @@ -85,7 +88,9 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup self["genretext"] = Label(_("Genre:")) self["genre"] = Label("") self["coverArt"] = MediaPixmap() + self["repeat"] = MultiPixmap() + self.repeat = False self.seek_target = None class MoviePlayerActionMap(NumberActionMap): @@ -106,11 +111,11 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup self["MediaPlayerActions"] = HelpableActionMap(self, "MediaPlayerActions", { - "play": (self.playEntry, _("play entry")), + "play": (self.xplayEntry, _("play entry")), "pause": (self.pauseEntry, _("pause")), "stop": (self.stopEntry, _("stop entry")), - "previous": (self.previousEntry, _("play previous playlist entry")), - "next": (self.nextEntry, _("play next playlist entry")), + "previous": (self.previousMarkOrEntry, _("play from previous mark or playlist entry")), + "next": (self.nextMarkOrEntry, _("play from next mark or playlist entry")), "menu": (self.showMenu, _("menu")), "skipListbegin": (self.skip_listbegin, _("jump to listbegin")), "skipListend": (self.skip_listend, _("jump to listend")), @@ -119,6 +124,7 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup "delete": (self.deletePlaylistEntry, _("delete playlist entry")), "shift_stop": (self.clear_playlist, _("clear playlist")), "shift_record": (self.playlist.PlayListShuffle, _("shuffle playlist")), + "subtitles": (self.subtitleSelection, _("Subtitle selection")), }, -2) self["InfobarEPGActions"] = HelpableActionMap(self, "InfobarEPGActions", @@ -145,28 +151,23 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup InfoBarSeek.__init__(self, actionmap = "MediaPlayerSeekActions") - self.__event_tracker = ServiceEventTracker(screen=self, eventmap= - { - #iPlayableService.evStart: self.__serviceStarted, - #iPlayableService.evSeekableStatusChanged: InfoBarSeek.__seekableStatusChanged, - - iPlayableService.evEOF: self.__evEOF, - }) - self.onClose.append(self.delMPTimer) self.onClose.append(self.__onClose) self.righttimer = False self.rightKeyTimer = eTimer() - self.rightKeyTimer.timeout.get().append(self.rightTimerFire) + self.rightKeyTimer.callback.append(self.rightTimerFire) self.lefttimer = False self.leftKeyTimer = eTimer() - self.leftKeyTimer.timeout.get().append(self.leftTimerFire) + self.leftKeyTimer.callback.append(self.leftTimerFire) self.currList = "filelist" self.coverArtFileName = "" + self.isAudioCD = False + self.AudioCD_albuminfo = {} + self.savePlaylistOnExit = True self.playlistIOInternal = PlaylistIOInternal() list = self.playlistIOInternal.open(resolveFilename(SCOPE_CONFIG, "playlist.e2pls")) @@ -175,6 +176,13 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup self.playlist.addFile(x.ref) self.playlist.updateList() + self.__event_tracker = ServiceEventTracker(screen=self, eventmap= + { + iPlayableService.evUpdatedInfo: self.__evUpdatedInfo, + iPlayableService.evUser+11: self.__evDecodeError, + iPlayableService.evUser+12: self.__evPluginError + }) + def doNothing(self): pass @@ -189,18 +197,42 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup self.playlistIOInternal.clear() for x in self.playlist.list: self.playlistIOInternal.addService(ServiceReference(x[0])) - self.playlistIOInternal.save(resolveFilename(SCOPE_CONFIG, "playlist.e2pls")) + if self.savePlaylistOnExit: + self.playlistIOInternal.save(resolveFilename(SCOPE_CONFIG, "playlist.e2pls")) self.close() def checkSkipShowHideLock(self): self.updatedSeekState() - def __evEOF(self): - self.nextEntry() + def doEofInternal(self, playing): + if playing: + self.nextEntry() + else: + self.show() def __onClose(self): self.session.nav.playService(self.oldService) + def __evUpdatedInfo(self): + currPlay = self.session.nav.getCurrentService() + currenttitle = currPlay.info().getInfo(iServiceInformation.sCurrentTitle) + totaltitles = currPlay.info().getInfo(iServiceInformation.sTotalTitles) + sTitle = currPlay.info().getInfoString(iServiceInformation.sTitle) + print "[__evUpdatedInfo] title %d of %d (%s)" % (currenttitle, totaltitles, sTitle) + self.readTitleInformation() + + def __evDecodeError(self): + currPlay = self.session.nav.getCurrentService() + sVideoType = currPlay.info().getInfoString(iServiceInformation.sVideoType) + print "[__evDecodeError] video-codec %s can't be decoded by hardware" % (sVideoType) + self.session.open(MessageBox, _("This Dreambox can't decode %s video streams!") % sVideoType, type = MessageBox.TYPE_INFO,timeout = 20 ) + + def __evPluginError(self): + currPlay = self.session.nav.getCurrentService() + message = currPlay.info().getInfoString(iServiceInformation.sUser+12) + print "[__evPluginError]" , message + self.session.open(MessageBox, ("GStreamer Error: missing %s") % message, type = MessageBox.TYPE_INFO,timeout = 20 ) + def delMPTimer(self): del self.rightKeyTimer del self.leftKeyTimer @@ -208,15 +240,29 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup def readTitleInformation(self): currPlay = self.session.nav.getCurrentService() if currPlay is not None: - stitle = currPlay.info().getInfoString(iServiceInformation.sTitle) - if stitle == "": - stitle = currPlay.info().getName().split('/')[-1] - - self.updateMusicInformation( artist = currPlay.info().getInfoString(iServiceInformation.sArtist), - title = stitle, - album = currPlay.info().getInfoString(iServiceInformation.sAlbum), - genre = currPlay.info().getInfoString(iServiceInformation.sGenre), - clear = True) + sTitle = currPlay.info().getInfoString(iServiceInformation.sTitle) + sAlbum = currPlay.info().getInfoString(iServiceInformation.sAlbum) + sGenre = currPlay.info().getInfoString(iServiceInformation.sGenre) + sArtist = currPlay.info().getInfoString(iServiceInformation.sArtist) + sYear = "" + + if sTitle == "": + if not self.isAudioCD: + sTitle = currPlay.info().getName().split('/')[-1] + else: + sTitle = self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()].getName() + + if self.AudioCD_albuminfo: + if sAlbum == "" and "title" in self.AudioCD_albuminfo: + sAlbum = self.AudioCD_albuminfo["title"] + if sGenre == "" and "genre" in self.AudioCD_albuminfo: + sGenre = self.AudioCD_albuminfo["genre"] + if sArtist == "" and "artist" in self.AudioCD_albuminfo: + sArtist = self.AudioCD_albuminfo["artist"] + if "year" in self.AudioCD_albuminfo: + sYear = self.AudioCD_albuminfo["year"] + + self.updateMusicInformation( sArtist, sTitle, sAlbum, sYear, sGenre, clear = True ) else: self.updateMusicInformation() @@ -305,6 +351,13 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup def hideAfterResume(self): self.hide() + def getIdentifier(self, ref): + if self.isAudioCD: + return ref.getName() + else: + text = ref.getPath() + return text.split('/')[-1] + # FIXME: maybe this code can be optimized def updateCurrentInfo(self): text = "" @@ -352,16 +405,14 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup if t is None: return #display current selected entry on LCD - text = t.getPath() - text = text.split('/')[-1] + text = self.getIdentifier(t) self.summaries.setText(text,1) self["currenttext"].setText(text) idx = self.playlist.getSelectionIndex() idx += 1 if idx < len(self.playlist): currref = self.playlist.getServiceRefList()[idx] - text = currref.getPath() - text = text.split('/')[-1] + text = self.getIdentifier(currref) self.summaries.setText(text,3) else: self.summaries.setText(" ",3) @@ -369,8 +420,7 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup idx += 1 if idx < len(self.playlist): currref = self.playlist.getServiceRefList()[idx] - text = currref.getPath() - text = text.split('/')[-1] + text = self.getIdentifier(currref) self.summaries.setText(text,4) else: self.summaries.setText(" ",4) @@ -406,6 +456,7 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup menu.append((_("save playlist"), "saveplaylist")); menu.append((_("load playlist"), "loadplaylist")); menu.append((_("delete saved playlist"), "deleteplaylist")); + menu.append((_("repeat playlist"), "repeat")); self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu) def menuCallback(self, choice): @@ -441,7 +492,13 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup self.delete_saved_playlist() elif choice[1] == "shuffle": self.playlist.PlayListShuffle() - + elif choice[1] == "repeat": + if self.repeat == True: + self.repeat = False + self["repeat"].setPixmapNum(0) + else: + self.repeat = True + self["repeat"].setPixmapNum(1) def showEventInformation(self): from Screens.EventView import EventViewSimple @@ -568,11 +625,23 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup next = self.playlist.getCurrentIndex() + 1 if next < len(self.playlist): self.changeEntry(next) + elif ( len(self.playlist) > 0 ) and ( self.repeat == True ): + self.stopEntry() + self.changeEntry(0) - def previousEntry(self): - next = self.playlist.getCurrentIndex() - 1 - if next >= 0: - self.changeEntry(next) + def nextMarkOrEntry(self): + if not self.jumpPreviousNextMark(lambda x: x): + next = self.playlist.getCurrentIndex() + 1 + if next < len(self.playlist): + self.changeEntry(next) + else: + self.doSeek(-1) + + def previousMarkOrEntry(self): + if not self.jumpPreviousNextMark(lambda x: -x-5*90000, start=True): + next = self.playlist.getCurrentIndex() - 1 + if next >= 0: + self.changeEntry(next) def deleteEntry(self): self.playlist.deleteFile(self.playlist.getSelectionIndex()) @@ -590,7 +659,24 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup if serviceRefList[count] == serviceref: self.changeEntry(count) break - + + def xplayEntry(self): + if self.currList == "playlist": + self.playEntry() + else: + self.stopEntry() + self.playlist.clear() + sel = self.filelist.getSelection() + if sel: + if sel[1]: # can descent + # add directory to playlist + self.copyDirectory(sel[0]) + else: + # add files to playlist + self.copyDirectory(os_path.dirname(sel[0].getPath()) + "/", recursive = False) + if len(self.playlist) > 0: + self.changeEntry(0) + def playEntry(self): if len(self.playlist.getServiceRefList()): needsInfoUpdate = False @@ -603,13 +689,12 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup # display just playing musik on LCD idx = self.playlist.getCurrentIndex() currref = self.playlist.getServiceRefList()[idx] - text = currref.getPath() - text = text.split('/')[-1] + text = self.getIdentifier(currref) text = ">"+text - ext = text[-3:].lower() + ext = text[-4:].lower() # FIXME: the information if the service contains video (and we should hide our window) should com from the service instead - if ext not in ["mp3", "wav", "ogg"]: + if ext not in [".mp3", ".wav", ".ogg", "flac"] and not self.isAudioCD: self.hide() else: needsInfoUpdate = True @@ -619,8 +704,7 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup idx += 1 if idx < len(self.playlist): currref = self.playlist.getServiceRefList()[idx] - text = currref.getPath() - text = text.split('/')[-1] + text = self.getIdentifier(currref) self.summaries.setText(text,3) else: self.summaries.setText(" ",3) @@ -628,8 +712,7 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup idx += 1 if idx < len(self.playlist): currref = self.playlist.getServiceRefList()[idx] - text = currref.getPath() - text = text.split('/')[-1] + text = self.getIdentifier(currref) self.summaries.setText(text,4) else: self.summaries.setText(" ",4) @@ -637,8 +720,8 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup idx = self.playlist.getCurrentIndex() currref = self.playlist.getServiceRefList()[idx] text = currref.getPath() - ext = text[-3:].lower() - if ext not in ["mp3", "wav", "ogg"]: + ext = text[-4:].lower() + if ext not in [".mp3", ".wav", ".ogg", "flac"] and not self.isAudioCD: self.hide() else: needsInfoUpdate = True @@ -657,26 +740,17 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup self.playlist.pauseFile() elif self.seekstate == self.SEEK_STATE_PLAY: self.playlist.playFile() - elif self.seekstate in ( self.SEEK_STATE_FF_2X, - self.SEEK_STATE_FF_4X, - self.SEEK_STATE_FF_8X, - self.SEEK_STATE_FF_16X, - self.SEEK_STATE_FF_32X, - self.SEEK_STATE_FF_48X, - self.SEEK_STATE_FF_64X, - self.SEEK_STATE_FF_128X): + elif self.isStateForward(self.seekstate): self.playlist.forwardFile() - elif self.seekstate in ( self.SEEK_STATE_BACK_8X, - self.SEEK_STATE_BACK_16X, - self.SEEK_STATE_BACK_32X, - self.SEEK_STATE_BACK_48X, - self.SEEK_STATE_BACK_64X, - self.SEEK_STATE_BACK_128X): + elif self.isStateBackward(self.seekstate): self.playlist.rewindFile() def pauseEntry(self): self.pauseService() - self.show() + if self.seekstate == self.SEEK_STATE_PAUSE: + self.show() + else: + self.hide() def stopEntry(self): self.playlist.stopFile() @@ -686,7 +760,10 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup def unPauseService(self): self.setSeekState(self.SEEK_STATE_PLAY) - + + def subtitleSelection(self): + from Screens.Subtitles import Subtitles + self.session.open(Subtitles) class MediaPlayerLCDScreen(Screen): skin = """ @@ -717,7 +794,7 @@ class MediaPlayerLCDScreen(Screen): self["text4"].setText(text) def main(session, **kwargs): - session.open(MediaPlayer) + session.open(MediaPlayer) def menu(menuid, **kwargs): if menuid == "mainmenu": @@ -728,20 +805,43 @@ def filescan_open(list, session, **kwargs): from enigma import eServiceReference mp = session.open(MediaPlayer) + mp.playlist.clear() + mp.savePlaylistOnExit = False + + for file in list: + if file.mimetype == "video/MP2T": + stype = 1 + else: + stype = 4097 + ref = eServiceReference(stype, 0, file.path) + mp.playlist.addFile(ref) + mp.changeEntry(0) mp.switchToPlayList() + +def audioCD_open(list, session, **kwargs): + from enigma import eServiceReference + + mp = session.open(MediaPlayer) + + mp.playlist.clear() + mp.savePlaylistOnExit = False + mp.isAudioCD = True + for file in list: ref = eServiceReference(4097, 0, file.path) mp.playlist.addFile(ref) + from Plugins.Extensions.CDInfo.plugin import Query + cdinfo = Query(mp) + cdinfo.scan() - # TODO: rather play first than last file? - mp.playServiceRefEntry(ref) - mp.playlist.updateList() + mp.changeEntry(0) + mp.switchToPlayList() def filescan(**kwargs): from Components.Scanner import Scanner, ScanPath - return [ - Scanner(mimetypes = ["video/mpeg"], + mediatypes = [ + Scanner(mimetypes = ["video/mpeg", "video/MP2T", "video/x-msvideo"], paths_to_scan = [ ScanPath(path = "", with_subdirs = False), @@ -750,7 +850,17 @@ def filescan(**kwargs): description = "View Movies...", openfnc = filescan_open, ), - Scanner(mimetypes = ["audio/mpeg", "audio/x-wav", "application/ogg"], + Scanner(mimetypes = ["video/x-vcd"], + paths_to_scan = + [ + ScanPath(path = "mpegav", with_subdirs = False), + ScanPath(path = "MPEGAV", with_subdirs = False), + ], + name = "Video CD", + description = "View Video CD...", + openfnc = filescan_open, + ), + Scanner(mimetypes = ["audio/mpeg", "audio/x-wav", "application/ogg", "audio/x-flac"], paths_to_scan = [ ScanPath(path = "", with_subdirs = False), @@ -758,8 +868,22 @@ def filescan(**kwargs): name = "Music", description = "Play Music...", openfnc = filescan_open, - ) - ] + )] + try: + from Plugins.Extensions.CDInfo.plugin import Query + mediatypes.append( + Scanner(mimetypes = ["audio/x-cda"], + paths_to_scan = + [ + ScanPath(path = "", with_subdirs = False), + ], + name = "Audio-CD", + description = "Play Audio-CD...", + openfnc = audioCD_open, + )) + return mediatypes + except ImportError: + return mediatypes from Plugins.Plugin import PluginDescriptor def Plugins(**kwargs):