Merge branch '219_negative_ac3_pcm_delay'
[enigma2.git] / lib / python / Plugins / Extensions / MediaPlayer / plugin.py
index 03d7617306ada6c11c48d8de5758decdd1f9cf61..98bc060c2053da6cbe7e16bf0e96f59cc58db768 100644 (file)
@@ -1,23 +1,26 @@
 from os import path as os_path, remove as os_remove, listdir as os_listdir
 from time import strftime
-from enigma import eTimer, iPlayableService, eServiceCenter, iServiceInformation
+from enigma import iPlayableService, eTimer, eServiceCenter, iServiceInformation, ePicLoad
+from ServiceReference import ServiceReference
 from Screens.Screen import Screen
+from Screens.HelpMenu import HelpableScreen
 from Screens.MessageBox import MessageBox
 from Screens.InputBox import InputBox
+from Screens.ChoiceBox import ChoiceBox
+from Screens.InfoBarGenerics import InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSupport, InfoBarNotifications, InfoBarSubtitleSupport
 from Components.ActionMap import NumberActionMap, HelpableActionMap
 from Components.Label import Label
-from Components.Pixmap import Pixmap
-from Components.Label import Label
+from Components.Pixmap import Pixmap,MultiPixmap
 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
-from Screens.ChoiceBox import ChoiceBox
-from Screens.HelpMenu import HelpableScreen
+from Components.AVSwitch import AVSwitch
+from Components.Harddisk import harddiskmanager
+from Components.config import config
+from Tools.Directories import fileExists, pathExists, resolveFilename, SCOPE_CONFIG, SCOPE_PLAYLIST, SCOPE_SKIN_IMAGE
+from settings import MediaPlayerSettings
 import random
 
 class MyPlayList(PlayList):
@@ -31,18 +34,60 @@ class MyPlayList(PlayList):
                self.oldCurrPlaying = -1
 
 class MediaPixmap(Pixmap):
-       def applySkin(self, desktop):
-               self.default_pixmap = None
+       def __init__(self):
+               Pixmap.__init__(self)
+               self.coverArtFileName = ""
+               self.picload = ePicLoad()
+               self.picload.PictureData.get().append(self.paintCoverArtPixmapCB)
+               self.coverFileNames = ["folder.png", "folder.jpg"]
+
+       def applySkin(self, desktop, screen):
+               from Tools.LoadPixmap import LoadPixmap
+               noCoverFile = None
                if self.skinAttributes is not None:
                        for (attrib, value) in self.skinAttributes:
                                if attrib == "pixmap":
-                                       self.default_pixmap = value
+                                       noCoverFile = value
                                        break
-               if self.default_pixmap is None:
-                       self.default_pixmap = resolveFilename(SCOPE_SKIN_IMAGE, "no_coverArt.png")
-               return Pixmap.applySkin(self, desktop)
+               if noCoverFile is None:
+                       noCoverFile = resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/no_coverArt.png")
+               self.noCoverPixmap = LoadPixmap(noCoverFile)
+               return Pixmap.applySkin(self, desktop, screen)
+
+       def onShow(self):
+               Pixmap.onShow(self)
+               sc = AVSwitch().getFramebufferScale()
+               #0=Width 1=Height 2=Aspect 3=use_cache 4=resize_type 5=Background(#AARRGGBB)
+               self.picload.setPara((self.instance.size().width(), self.instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
+
+       def paintCoverArtPixmapCB(self, picInfo=None):
+               ptr = self.picload.getData()
+               if ptr != None:
+                       self.instance.setPixmap(ptr.__deref__())
+
+       def updateCoverArt(self, path):
+               while not path.endswith("/"):
+                       path = path[:-1]
+               new_coverArtFileName = None
+               for filename in self.coverFileNames:
+                       if fileExists(path + filename):
+                               new_coverArtFileName = path + filename
+               if self.coverArtFileName != new_coverArtFileName:
+                       self.coverArtFileName = new_coverArtFileName
+                       if new_coverArtFileName:
+                               self.picload.startDecode(self.coverArtFileName)
+                       else:
+                               self.showDefaultCover()
+
+       def showDefaultCover(self):
+               self.instance.setPixmap(self.noCoverPixmap)
 
-class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSupport, InfoBarNotifications, HelpableScreen):
+       def embeddedCoverArt(self):
+               print "[embeddedCoverArt] found"
+               self.coverArtFileName = "/tmp/.id3coverart"
+               self.picload.startDecode(self.coverArtFileName)
+
+class MediaPlayer(Screen, InfoBarBase, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSupport, InfoBarNotifications, InfoBarSubtitleSupport, HelpableScreen):
        ALLOW_SUSPEND = True
        ENABLE_RESUME_SUPPORT = True
 
@@ -51,6 +96,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()
@@ -62,11 +109,11 @@ 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)
+               defaultDir = config.mediaplayer.defaultDir.getValue()
+               self.filelist = FileList(defaultDir, matchingPattern = "(?i)^.*\.(mp2|mp3|ogg|ts|wav|wave|m3u|pls|e2pls|mpg|vob|avi|divx|m4v|mkv|mp4|m4a|dat|flac|mov)", useServiceRef = True, additionalExtensions = "4098:m3u 4098:e2pls 4098:pls")
                self["filelist"] = self.filelist
 
                self.playlist = MyPlayList()
-               #self.playlist = PlayList()
                self.is_closing = False
                self.delname = ""
                self["playlist"] = self.playlist
@@ -75,20 +122,24 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
 
                self["currenttext"] = Label("")
 
-               self["artisttext"] = Label(_("Artist:"))
+               self["artisttext"] = Label(_("Artist")+':')
                self["artist"] = Label("")
-               self["titletext"] = Label(_("Title:"))
+               self["titletext"] = Label(_("Title")+':')
                self["title"] = Label("")
-               self["albumtext"] = Label(_("Album:"))
+               self["albumtext"] = Label(_("Album")+':')
                self["album"] = Label("")
-               self["yeartext"] = Label(_("Year:"))
+               self["yeartext"] = Label(_("Year")+':')
                self["year"] = Label("")
-               self["genretext"] = Label(_("Genre:"))
+               self["genretext"] = Label(_("Genre")+':')
                self["genre"] = Label("")
                self["coverArt"] = MediaPixmap()
+               self["repeat"] = MultiPixmap()
 
                self.seek_target = None
 
+               from Plugins.SystemPlugins.Hotplug.plugin import hotplugNotifier
+               hotplugNotifier.append(self.hotplugCB)
+
                class MoviePlayerActionMap(NumberActionMap):
                        def __init__(self, player, contexts = [ ], actions = { }, prio=0):
                                NumberActionMap.__init__(self, contexts, actions, prio)
@@ -98,7 +149,6 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
                                self.player.show()
                                return NumberActionMap.action(self, contexts, action)
 
-
                self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions", 
                        {
                                "ok": (self.ok, _("add file to playlist")),
@@ -110,8 +160,8 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
                                "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")),
@@ -120,6 +170,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", 
@@ -146,14 +197,6 @@ 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)
 
@@ -166,8 +209,10 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
                self.leftKeyTimer.callback.append(self.leftTimerFire)
 
                self.currList = "filelist"
-
-               self.coverArtFileName = ""
+               self.isAudioCD = False
+               self.AudioCD_albuminfo = {}
+               self.cdAudioTrackFiles = []
+               self.onShown.append(self.applySettings)
 
                self.playlistIOInternal = PlaylistIOInternal()
                list = self.playlistIOInternal.open(resolveFilename(SCOPE_CONFIG, "playlist.e2pls"))
@@ -176,6 +221,15 @@ 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+10: self.__evAudioDecodeError,
+                               iPlayableService.evUser+11: self.__evVideoDecodeError,
+                               iPlayableService.evUser+12: self.__evPluginError,
+                               iPlayableService.evUser+13: self["coverArt"].embeddedCoverArt
+                       })
+
        def doNothing(self):
                pass
 
@@ -183,25 +237,60 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
                return MediaPlayerLCDScreen
 
        def exit(self):
-               self.session.openWithCallback(self.exitCB, MessageBox, _("Do you really want to exit?"), timeout=5)
-
-       def exitCB(self, answer):
-               if answer == True:
-                       self.playlistIOInternal.clear()
-                       for x in self.playlist.list:
-                               self.playlistIOInternal.addService(ServiceReference(x[0]))
-                       self.playlistIOInternal.save(resolveFilename(SCOPE_CONFIG, "playlist.e2pls"))
-                       self.close()
+               self.playlistIOInternal.clear()
+               for x in self.playlist.list:
+                       self.playlistIOInternal.addService(ServiceReference(x[0]))
+               if self.savePlaylistOnExit:
+                       try:
+                               self.playlistIOInternal.save(resolveFilename(SCOPE_CONFIG, "playlist.e2pls"))
+                       except IOError:
+                               print "couldn't save playlist.e2pls"
+               if config.mediaplayer.saveDirOnExit.getValue():
+                       config.mediaplayer.defaultDir.setValue(self.filelist.getCurrentDirectory())
+                       config.mediaplayer.defaultDir.save()
+               from Plugins.SystemPlugins.Hotplug.plugin import hotplugNotifier
+               hotplugNotifier.remove(self.hotplugCB)
+               del self["coverArt"].picload
+               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()
+               sTagTrackNumber = currPlay.info().getInfo(iServiceInformation.sTagTrackNumber)
+               sTagTrackCount = currPlay.info().getInfo(iServiceInformation.sTagTrackCount)
+               sTagTitle = currPlay.info().getInfoString(iServiceInformation.sTagTitle)
+               print "[__evUpdatedInfo] title %d of %d (%s)" % (sTagTrackNumber, sTagTrackCount, sTagTitle)
+               self.readTitleInformation()
+
+       def __evAudioDecodeError(self):
+               currPlay = self.session.nav.getCurrentService()
+               sTagAudioCodec = currPlay.info().getInfoString(iServiceInformation.sTagAudioCodec)
+               print "[__evAudioDecodeError] audio-codec %s can't be decoded by hardware" % (sTagAudioCodec)
+               self.session.open(MessageBox, _("This Dreambox can't decode %s streams!") % sTagAudioCodec, type = MessageBox.TYPE_INFO,timeout = 20 )
+
+       def __evVideoDecodeError(self):
+               currPlay = self.session.nav.getCurrentService()
+               sTagVideoCodec = currPlay.info().getInfoString(iServiceInformation.sTagVideoCodec)
+               print "[__evVideoDecodeError] video-codec %s can't be decoded by hardware" % (sTagVideoCodec)
+               self.session.open(MessageBox, _("This Dreambox can't decode %s streams!") % sTagVideoCodec, 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, message, type = MessageBox.TYPE_INFO,timeout = 20 )
+
        def delMPTimer(self):
                del self.rightKeyTimer
                del self.leftKeyTimer
@@ -209,15 +298,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.sTagTitle)
+                       sAlbum = currPlay.info().getInfoString(iServiceInformation.sTagAlbum)
+                       sGenre = currPlay.info().getInfoString(iServiceInformation.sTagGenre)
+                       sArtist = currPlay.info().getInfoString(iServiceInformation.sTagArtist)
+                       sYear = currPlay.info().getInfoString(iServiceInformation.sTagDate)
+
+                       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()
 
@@ -233,17 +336,6 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
                        if self[name].getText() != info:
                                self[name].setText(info)
 
-       def updateCoverArtPixmap(self, path):
-               while not path.endswith("/"):
-                       path = path[:-1]
-               pngname = path + "folder.png"
-               
-               if not os_path.exists(pngname):
-                       pngname = self["coverArt"].default_pixmap
-               if self.coverArtFileName != pngname:
-                       self.coverArtFileName = pngname
-                       self["coverArt"].instance.setPixmapFromFile(self.coverArtFileName)
-
        def leftDown(self):
                self.lefttimer = True
                self.leftKeyTimer.start(1000)
@@ -298,7 +390,7 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
                self.updateCurrentInfo()
 
        def showAfterSeek(self):
-               self.show()
+               pass
 
        def showAfterCuesheetOperation(self):
                self.show()
@@ -306,6 +398,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 = ""
@@ -353,16 +452,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)
@@ -370,8 +467,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)
@@ -390,23 +486,28 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
 
        def showMenu(self):
                menu = []
+               if len(self.cdAudioTrackFiles):
+                       menu.insert(0,(_("Play Audio-CD..."), "audiocd"))
                if self.currList == "filelist":
                        if self.filelist.canDescent():
                                menu.append((_("add directory to playlist"), "copydir"))
                        else:
                                menu.append((_("add files to playlist"), "copyfiles"))
                        menu.append((_("switch to playlist"), "playlist"))
+                       if config.usage.setup_level.index >= 1: # intermediate+
+                               menu.append((_("delete file"), "deletefile"))
                else:
                        menu.append((_("switch to filelist"), "filelist"))
-
-                       menu.append((_("shuffle playlist"), "shuffle"))
-
-                       menu.append((_("delete"), "delete"))
                        menu.append((_("clear playlist"), "clear"))
+                       menu.append((_("Delete entry"), "deleteentry"))
+                       if config.usage.setup_level.index >= 1: # intermediate+
+                               menu.append((_("shuffle playlist"), "shuffle"))
                menu.append((_("hide player"), "hide"));
-               menu.append((_("save playlist"), "saveplaylist"));
                menu.append((_("load playlist"), "loadplaylist"));
-               menu.append((_("delete saved playlist"), "deleteplaylist"));
+               if config.usage.setup_level.index >= 1: # intermediate+
+                       menu.append((_("save playlist"), "saveplaylist"));
+                       menu.append((_("delete saved playlist"), "deleteplaylist"));
+                       menu.append((_("Edit settings"), "settings"))
                self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu)
 
        def menuCallback(self, choice):
@@ -418,20 +519,19 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
                elif choice[1] == "copyfiles":
                        self.stopEntry()
                        self.playlist.clear()
+                       self.isAudioCD = False
                        self.copyDirectory(os_path.dirname(self.filelist.getSelection()[0].getPath()) + "/", recursive = False)
                        self.playServiceRefEntry(self.filelist.getServiceRef())
                elif choice[1] == "playlist":
                        self.switchToPlayList()
                elif choice[1] == "filelist":
                        self.switchToFileList()
-               elif choice[1] == "delete":
+               elif choice[1] == "deleteentry":
                        if self.playlist.getSelectionIndex() == self.playlist.getCurrentIndex():
                                self.stopEntry()
                        self.deleteEntry()
                elif choice[1] == "clear":
-                       self.stopEntry()
-                       self.playlist.clear()
-                       self.switchToFileList()
+                       self.clear_playlist()
                elif choice[1] == "hide":
                        self.hide()
                elif choice[1] == "saveplaylist":
@@ -442,7 +542,35 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
                        self.delete_saved_playlist()
                elif choice[1] == "shuffle":
                        self.playlist.PlayListShuffle()
+               elif choice[1] == "deletefile":
+                       self.deleteFile()
+               elif choice[1] == "settings":
+                       self.session.openWithCallback(self.applySettings, MediaPlayerSettings, self)
+               elif choice[1] == "audiocd":
+                       self.playAudioCD()
+
+       def playAudioCD(self):
+               from enigma import eServiceReference
+               from Plugins.Extensions.CDInfo.plugin import Query
+
+               if len(self.cdAudioTrackFiles):
+                       self.playlist.clear()
+                       self.savePlaylistOnExit = False
+                       self.isAudioCD = True
+                       for file in self.cdAudioTrackFiles:
+                               ref = eServiceReference(4097, 0, file)
+                               self.playlist.addFile(ref)
+                       cdinfo = Query(self)
+                       cdinfo.scan()
+                       self.changeEntry(0)
+                       self.switchToPlayList()
 
+       def applySettings(self):
+               self.savePlaylistOnExit = config.mediaplayer.savePlaylistOnExit.getValue()
+               if config.mediaplayer.repeat.getValue() == True:
+                       self["repeat"].setPixmapNum(1)
+               else:
+                       self["repeat"].setPixmapNum(0)
 
        def showEventInformation(self):
                from Screens.EventView import EventViewSimple
@@ -503,12 +631,13 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
        def PlaylistSelected(self,path):
                if path is not None:
                        self.clear_playlist()
-                       self.playlistIOInternal = PlaylistIOInternal()
-                       list = self.playlistIOInternal.open(path[1])
-                       if list:
+                       extension = path[0].rsplit('.',1)[-1]
+                       if self.playlistparsers.has_key(extension):
+                               playlist = self.playlistparsers[extension]()
+                               list = playlist.open(path[1])
                                for x in list:
                                        self.playlist.addFile(x.ref)
-                               self.playlist.updateList()
+                       self.playlist.updateList()
 
        def delete_saved_playlist(self):
                listpath = []
@@ -527,35 +656,102 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
 
        def deleteConfirmed(self, confirmed):
                if confirmed:
-                       os_remove(self.delname)
+                       try:
+                               os_remove(self.delname)
+                       except OSError,e:
+                               print "delete failed:", e
+                               self.session.open(MessageBox, _("Delete failed!"), MessageBox.TYPE_ERROR)
 
        def clear_playlist(self):
+               self.isAudioCD = False
                self.stopEntry()
                self.playlist.clear()
                self.switchToFileList()
 
        def copyDirectory(self, directory, recursive = True):
                print "copyDirectory", directory
-               filelist = FileList(directory, useServiceRef = True, isTop = True)
+               if directory == '/':
+                       print "refusing to operate on /"
+                       return
+               filelist = FileList(directory, useServiceRef = True, showMountpoints = False, isTop = True)
 
                for x in filelist.getFileList():
                        if x[0][1] == True: #isDir
                                if recursive:
-                                       self.copyDirectory(x[0][0])
-                       else:
+                                       if x[0][0] != directory:
+                                               self.copyDirectory(x[0][0])
+                       elif filelist.getServiceRef() and filelist.getServiceRef().type == 4097:
                                self.playlist.addFile(x[0][0])
                self.playlist.updateList()
 
+       def deleteFile(self):
+               if self.currList == "filelist":
+                       self.service = self.filelist.getServiceRef()
+               else:
+                       self.service = self.playlist.getSelection()
+               if self.service is None:
+                       return
+               if self.service.type != 4098 and self.session.nav.getCurrentlyPlayingServiceReference() is not None:
+                       if self.service == self.session.nav.getCurrentlyPlayingServiceReference():
+                               self.stopEntry()
+
+               serviceHandler = eServiceCenter.getInstance()
+               offline = serviceHandler.offlineOperations(self.service)
+               info = serviceHandler.info(self.service)
+               name = info and info.getName(self.service)
+               result = False
+               if offline is not None:
+                       # simulate first
+                       if not offline.deleteFromDisk(1):
+                               result = True
+               if result == True:
+                       self.session.openWithCallback(self.deleteConfirmed_offline, MessageBox, _("Do you really want to delete %s?") % (name))
+               else:
+                       self.session.openWithCallback(self.close, MessageBox, _("You cannot delete this!"), MessageBox.TYPE_ERROR)      
+
+       def deleteConfirmed_offline(self, confirmed):
+               if confirmed:
+                       serviceHandler = eServiceCenter.getInstance()
+                       offline = serviceHandler.offlineOperations(self.service)
+                       result = False
+                       if offline is not None:
+                               # really delete!
+                               if not offline.deleteFromDisk(0):
+                                       result = True
+                       if result == False:
+                               self.session.open(MessageBox, _("Delete failed!"), MessageBox.TYPE_ERROR)
+                       else:
+                               self.removeListEntry()
+
+       def removeListEntry(self):
+               currdir = self.filelist.getCurrentDirectory()
+               self.filelist.changeDir(currdir)
+               deleteend = False
+               while not deleteend:
+                       index = 0
+                       deleteend = True
+                       if len(self.playlist) > 0:
+                               for x in self.playlist.list:
+                                       if self.service == x[0]:
+                                               self.playlist.deleteFile(index)
+                                               deleteend = False
+                                               break
+                                       index += 1
+               self.playlist.updateList()
+               if self.currList == "playlist":
+                       if len(self.playlist) == 0:
+                               self.switchToFileList()
+
        def copyFile(self):
                if self.filelist.getServiceRef().type == 4098: # playlist
                        ServiceRef = self.filelist.getServiceRef()
                        extension = ServiceRef.getPath()[ServiceRef.getPath().rfind('.') + 1:]
-                       print "extension:", extension
                        if self.playlistparsers.has_key(extension):
                                playlist = self.playlistparsers[extension]()
                                list = playlist.open(ServiceRef.getPath())
                                for x in list:
                                        self.playlist.addFile(x.ref)
+                       self.playlist.updateList()
                else:
                        self.playlist.addFile(self.filelist.getServiceRef())
                        self.playlist.updateList()
@@ -569,11 +765,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 ( config.mediaplayer.repeat.getValue() == 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())
@@ -598,6 +806,7 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
                else:
                        self.stopEntry()
                        self.playlist.clear()
+                       self.isAudioCD = False
                        sel = self.filelist.getSelection()
                        if sel:
                                if sel[1]: # can descent
@@ -611,6 +820,7 @@ class MediaPlayer(Screen, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSup
        
        def playEntry(self):
                if len(self.playlist.getServiceRefList()):
+                       audio_extensions = (".mp2", ".mp3", ".wav", ".ogg", "flac", "m4a")
                        needsInfoUpdate = False
                        currref = self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()]
                        if self.session.nav.getCurrentlyPlayingServiceReference() is None or currref != self.session.nav.getCurrentlyPlayingServiceReference():
@@ -621,13 +831,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 audio_extensions and not self.isAudioCD:
                                        self.hide()
                                else:
                                        needsInfoUpdate = True
@@ -637,8 +846,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)
@@ -646,8 +854,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)
@@ -655,19 +862,18 @@ 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 audio_extensions and not self.isAudioCD:
                                        self.hide()
                                else:
                                        needsInfoUpdate = True
 
                        self.unPauseService()
                        if needsInfoUpdate == True:
-                               self.updateCoverArtPixmap(currref.getPath())
+                               path = self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()].getPath()
+                               self["coverArt"].updateCoverArt(path)
                        else:
-                               pngname = self["coverArt"].default_pixmap
-                               self.coverArtFileName = pngname
-                               self["coverArt"].instance.setPixmapFromFile(self.coverArtFileName)
+                               self["coverArt"].showDefaultCover()
                        self.readTitleInformation()
 
        def updatedSeekState(self):
@@ -675,26 +881,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()
@@ -704,7 +901,28 @@ 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, self)
+       
+       def hotplugCB(self, dev, media_state):
+               if dev == harddiskmanager.getCD():
+                       if media_state == "1":
+                               from Components.Scanner import scanDevice
+                               devpath = harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD())
+                               self.cdAudioTrackFiles = []
+                               res = scanDevice(devpath)
+                               list = [ (r.description, r, res[r], self.session) for r in res ]
+                               if list:
+                                       (desc, scanner, files, session) = list[0]
+                                       for file in files:
+                                               if file.mimetype == "audio/x-cda":
+                                                       self.cdAudioTrackFiles.append(file.path)
+                       else:
+                               self.cdAudioTrackFiles = []
+                               if self.isAudioCD:
+                                       self.clear_playlist()
 
 class MediaPlayerLCDScreen(Screen):
        skin = """
@@ -721,7 +939,6 @@ class MediaPlayerLCDScreen(Screen):
                self["text4"] = Label("")
 
        def setText(self, text, line):
-               print "lcd set text:", text, line
                if len(text) > 10:
                        if text[-4:] == ".mp3":
                                text = text[:-4]
@@ -735,7 +952,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":
@@ -746,38 +963,75 @@ def filescan_open(list, session, **kwargs):
        from enigma import eServiceReference
 
        mp = session.open(MediaPlayer)
+       mp.playlist.clear()
+       mp.savePlaylistOnExit = False
 
-       mp.switchToPlayList()
        for file in list:
-               ref = eServiceReference(4097, 0, file.path)
+               if file.mimetype == "video/MP2T":
+                       stype = 1
+               else:
+                       stype = 4097
+               ref = eServiceReference(stype, 0, file.path)
                mp.playlist.addFile(ref)
 
-       # TODO: rather play first than last file?
-       mp.playServiceRefEntry(ref)
-       mp.playlist.updateList()
+       mp.changeEntry(0)
+       mp.switchToPlayList()
+
+def audioCD_open(list, session, **kwargs):
+       from enigma import eServiceReference
+
+       mp = session.open(MediaPlayer)
+       mp.cdAudioTrackFiles = []
+       for file in list:
+               mp.cdAudioTrackFiles.append(file.path)
+       mp.playAudioCD()
 
 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),
                                ],
                        name = "Movie",
-                       description = "View Movies...",
+                       description = _("View Movies..."),
+                       openfnc = filescan_open,
+               ),
+               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"],
+               Scanner(mimetypes = ["audio/mpeg", "audio/x-wav", "application/ogg", "audio/x-flac"],
                        paths_to_scan =
                                [
                                        ScanPath(path = "", with_subdirs = False),
                                ],
                        name = "Music",
-                       description = "Play 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):