Display actual song names for Audio CDs with CD-Text feature (requires libcdio)
[enigma2.git] / lib / python / Plugins / Extensions / MediaPlayer / plugin.py
index fa7f164303ca295b0592c09bd6b23c1e66652b4b..f87978bd86ca05bb1564b276be80efbcf8c463ee 100644 (file)
@@ -1,6 +1,6 @@
-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
@@ -12,7 +12,7 @@ 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 ServiceReference import ServiceReference
@@ -31,7 +31,7 @@ class MyPlayList(PlayList):
                self.oldCurrPlaying = -1
 
 class MediaPixmap(Pixmap):
-       def applySkin(self, desktop):
+       def applySkin(self, desktop, screen):
                self.default_pixmap = None
                if self.skinAttributes is not None:
                        for (attrib, value) in self.skinAttributes:
@@ -39,10 +39,10 @@ class MediaPixmap(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, HelpableScreen):
        ALLOW_SUSPEND = True
        ENABLE_RESUME_SUPPORT = True
 
@@ -51,6 +51,7 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
                InfoBarAudioSelection.__init__(self)
                InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions")
                InfoBarNotifications.__init__(self)
+               InfoBarBase.__init__(self)
                HelpableScreen.__init__(self)
                self.summary = None
                self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
@@ -62,7 +63,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)", useServiceRef = True, additionalExtensions = "4098:m3u 4098:e2pls 4098:pls")
                self["filelist"] = self.filelist
 
                self.playlist = MyPlayList()
@@ -160,6 +161,8 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
                self.currList = "filelist"
 
                self.coverArtFileName = ""
+               self.isAudioCD = False
+               self.AudioCD_albuminfo = {}
 
                self.playlistIOInternal = PlaylistIOInternal()
                list = self.playlistIOInternal.open(resolveFilename(SCOPE_CONFIG, "playlist.e2pls"))
@@ -168,6 +171,11 @@ 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
+                       })
+
        def doNothing(self):
                pass
 
@@ -182,7 +190,8 @@ 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 not self.isAudioCD:
+                               self.playlistIOInternal.save(resolveFilename(SCOPE_CONFIG, "playlist.e2pls"))
                        self.close()
 
        def checkSkipShowHideLock(self):
@@ -197,6 +206,14 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
        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 delMPTimer(self):
                del self.rightKeyTimer
                del self.leftKeyTimer
@@ -204,15 +221,23 @@ 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)
+
+                       if sTitle == "":
+                               sTitle = currPlay.info().getName().split('/')[-1]
+
+                       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 "PERFORMER" in self.AudioCD_albuminfo:
+                                       sArtist = self.AudioCD_albuminfo["PERFORMER"]
+
+                       self.updateMusicInformation( artist = sArtist, title = sTitle, album = sAlbum, genre = sGenre, clear = True )
                else:
                        self.updateMusicInformation()
 
@@ -301,6 +326,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 = ""
@@ -348,16 +380,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)
@@ -365,8 +395,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)
@@ -625,13 +654,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()
 
                                # 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"] and not self.isAudioCD:
                                        self.hide()
                                else:
                                        needsInfoUpdate = True
@@ -641,8 +669,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)
@@ -650,8 +677,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)
@@ -660,7 +686,7 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
                                currref = self.playlist.getServiceRefList()[idx]
                                text = currref.getPath()
                                ext = text[-3:].lower()
-                               if ext not in ["mp3", "wav", "ogg"]:
+                               if ext not in ["mp3", "wav", "ogg"] and not self.isAudioCD:
                                        self.hide()
                                else:
                                        needsInfoUpdate = True
@@ -727,7 +753,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":
@@ -748,6 +774,39 @@ def filescan_open(list, session, **kwargs):
        mp.playServiceRefEntry(ref)
        mp.playlist.updateList()
 
+def audioCD_open(list, session, **kwargs):
+       from enigma import eServiceReference
+
+       mp = session.open(MediaPlayer)
+
+       mp.playlist.clear()
+       mp.isAudioCD = True
+
+       mp.switchToPlayList()
+       cdtext = popen('cdtextinfo -l').read()
+       tracklist = []
+       if cdtext is not "":
+               tracklist = cdtext.splitlines()
+               cdtext = popen('cdtextinfo -a').read()
+               if cdtext is not "":
+                       albumtags = cdtext.splitlines()
+                       for tag in albumtags:
+                               tag = tag.split(':',1)
+                               mp.AudioCD_albuminfo[tag[0]] = tag[1]
+                       print mp.AudioCD_albuminfo
+       idx = 0
+       for file in list:
+               ref = eServiceReference(4097, 0, file.path)
+               if idx < len(tracklist):
+                       track = tracklist[idx]
+                       ref.setName("%d - %s" % (int(track.split(':',1)[0]), track.split(':')[1]))
+                       idx += 1
+               mp.playlist.addFile(ref)
+
+       mp.changeEntry(0)
+       mp.playlist.updateList()
+       mp.switchToPlayList()
+
 def filescan(**kwargs):
        from Components.Scanner import Scanner, ScanPath
        return [
@@ -768,6 +827,15 @@ def filescan(**kwargs):
                        name = "Music",
                        description = "Play Music...",
                        openfnc = filescan_open,
+               ),
+               Scanner(mimetypes = ["audio/x-cda", "audio/x-wav"],
+                       paths_to_scan =
+                               [
+                                       ScanPath(path = "", with_subdirs = False),
+                               ],
+                       name = "Audio-CD",
+                       description = "Play Audio-CD...",
+                       openfnc = audioCD_open,
                )
        ]