small optimizations and cleanups by Moritz Venn
[enigma2.git] / lib / python / Plugins / Extensions / MediaPlayer / plugin.py
1 from os import path as os_path, remove as os_remove, listdir as os_listdir
2 from time import strftime
3 from enigma import iPlayableService, eTimer, eServiceCenter, iServiceInformation, ePicLoad
4 from ServiceReference import ServiceReference
5 from Screens.Screen import Screen
6 from Screens.HelpMenu import HelpableScreen
7 from Screens.MessageBox import MessageBox
8 from Screens.InputBox import InputBox
9 from Screens.ChoiceBox import ChoiceBox
10 from Screens.InfoBarGenerics import InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSupport, InfoBarNotifications, InfoBarSubtitleSupport
11 from Components.ActionMap import NumberActionMap, HelpableActionMap
12 from Components.Label import Label
13 from Components.Pixmap import Pixmap,MultiPixmap
14 from Components.FileList import FileList
15 from Components.MediaPlayer import PlayList
16 from Components.ServicePosition import ServicePositionGauge
17 from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
18 from Components.Playlist import PlaylistIOInternal, PlaylistIOM3U, PlaylistIOPLS
19 from Components.AVSwitch import AVSwitch
20 from Components.Harddisk import harddiskmanager
21 from Components.config import config
22 from Tools.Directories import fileExists, pathExists, resolveFilename, SCOPE_CONFIG, SCOPE_PLAYLIST, SCOPE_SKIN_IMAGE
23 from settings import MediaPlayerSettings
24 from Plugins.SystemPlugins.Hotplug.plugin import hotplugNotifier
25 import random
26
27 class MyPlayList(PlayList):
28         def __init__(self):
29                 PlayList.__init__(self)
30
31         def PlayListShuffle(self):
32                 random.shuffle(self.list)
33                 self.l.setList(self.list)
34                 self.currPlaying = -1
35                 self.oldCurrPlaying = -1
36
37 class MediaPixmap(Pixmap):
38         def __init__(self):
39                 Pixmap.__init__(self)
40                 self.coverArtFileName = ""
41                 self.picload = ePicLoad()
42                 self.picload.PictureData.get().append(self.paintCoverArtPixmapCB)
43                 self.coverFileNames = ["folder.png", "folder.jpg"]
44
45         def applySkin(self, desktop, screen):
46                 from Tools.LoadPixmap import LoadPixmap
47                 noCoverFile = None
48                 if self.skinAttributes is not None:
49                         for (attrib, value) in self.skinAttributes:
50                                 if attrib == "pixmap":
51                                         noCoverFile = value
52                                         break
53                 if noCoverFile is None:
54                         noCoverFile = resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/no_coverArt.png")
55                 self.noCoverPixmap = LoadPixmap(noCoverFile)
56                 return Pixmap.applySkin(self, desktop, screen)
57
58         def onShow(self):
59                 Pixmap.onShow(self)
60                 sc = AVSwitch().getFramebufferScale()
61                 #0=Width 1=Height 2=Aspect 3=use_cache 4=resize_type 5=Background(#AARRGGBB)
62                 self.picload.setPara((self.instance.size().width(), self.instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
63
64         def paintCoverArtPixmapCB(self, picInfo=None):
65                 ptr = self.picload.getData()
66                 if ptr != None:
67                         self.instance.setPixmap(ptr.__deref__())
68
69         def updateCoverArt(self, path):
70                 while not path.endswith("/"):
71                         path = path[:-1]
72                 new_coverArtFileName = None
73                 for filename in self.coverFileNames:
74                         if fileExists(path + filename):
75                                 new_coverArtFileName = path + filename
76                 if self.coverArtFileName != new_coverArtFileName:
77                         self.coverArtFileName = new_coverArtFileName
78                         if new_coverArtFileName:
79                                 self.picload.startDecode(self.coverArtFileName)
80                         else:
81                                 self.showDefaultCover()
82
83         def showDefaultCover(self):
84                 self.instance.setPixmap(self.noCoverPixmap)
85
86         def embeddedCoverArt(self):
87                 print "[embeddedCoverArt] found"
88                 self.coverArtFileName = "/tmp/.id3coverart"
89                 self.picload.startDecode(self.coverArtFileName)
90
91 class MediaPlayer(Screen, InfoBarBase, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSupport, InfoBarNotifications, InfoBarSubtitleSupport, HelpableScreen):
92         ALLOW_SUSPEND = True
93         ENABLE_RESUME_SUPPORT = True
94
95         def __init__(self, session, args = None):
96                 Screen.__init__(self, session)
97                 InfoBarAudioSelection.__init__(self)
98                 InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions")
99                 InfoBarNotifications.__init__(self)
100                 InfoBarBase.__init__(self)
101                 InfoBarSubtitleSupport.__init__(self)
102                 HelpableScreen.__init__(self)
103                 self.summary = None
104                 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
105                 self.session.nav.stopService()
106
107                 self.playlistparsers = {}
108                 self.addPlaylistParser(PlaylistIOM3U, "m3u")
109                 self.addPlaylistParser(PlaylistIOPLS, "pls")
110                 self.addPlaylistParser(PlaylistIOInternal, "e2pls")
111
112                 # 'None' is magic to start at the list of mountpoints
113                 defaultDir = config.mediaplayer.defaultDir.getValue()
114                 self.filelist = FileList(defaultDir, matchingPattern = "(?i)^.*\.(mp2|mp3|ogg|ts|wav|wave|m3u|pls|e2pls|mpg|vob|avi|divx|mkv|mp4|m4a|dat|flac)", useServiceRef = True, additionalExtensions = "4098:m3u 4098:e2pls 4098:pls")
115                 self["filelist"] = self.filelist
116
117                 self.playlist = MyPlayList()
118                 self.is_closing = False
119                 self.delname = ""
120                 self["playlist"] = self.playlist
121
122                 self["PositionGauge"] = ServicePositionGauge(self.session.nav)
123
124                 self["currenttext"] = Label("")
125
126                 self["artisttext"] = Label(_("Artist")+':')
127                 self["artist"] = Label("")
128                 self["titletext"] = Label(_("Title")+':')
129                 self["title"] = Label("")
130                 self["albumtext"] = Label(_("Album")+':')
131                 self["album"] = Label("")
132                 self["yeartext"] = Label(_("Year")+':')
133                 self["year"] = Label("")
134                 self["genretext"] = Label(_("Genre")+':')
135                 self["genre"] = Label("")
136                 self["coverArt"] = MediaPixmap()
137                 self["repeat"] = MultiPixmap()
138
139                 self.seek_target = None
140                 hotplugNotifier.append(self.hotplugCB)
141
142                 class MoviePlayerActionMap(NumberActionMap):
143                         def __init__(self, player, contexts = [ ], actions = { }, prio=0):
144                                 NumberActionMap.__init__(self, contexts, actions, prio)
145                                 self.player = player
146
147                         def action(self, contexts, action):
148                                 self.player.show()
149                                 return NumberActionMap.action(self, contexts, action)
150
151
152                 self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions", 
153                         {
154                                 "ok": (self.ok, _("add file to playlist")),
155                                 "cancel": (self.exit, _("exit mediaplayer")),
156                         }, -2)
157
158                 self["MediaPlayerActions"] = HelpableActionMap(self, "MediaPlayerActions", 
159                         {
160                                 "play": (self.xplayEntry, _("play entry")),
161                                 "pause": (self.pauseEntry, _("pause")),
162                                 "stop": (self.stopEntry, _("stop entry")),
163                                 "previous": (self.previousMarkOrEntry, _("play from previous mark or playlist entry")),
164                                 "next": (self.nextMarkOrEntry, _("play from next mark or playlist entry")),
165                                 "menu": (self.showMenu, _("menu")),
166                                 "skipListbegin": (self.skip_listbegin, _("jump to listbegin")),
167                                 "skipListend": (self.skip_listend, _("jump to listend")),
168                                 "prevBouquet": (self.switchToPlayList, _("switch to playlist")),
169                                 "nextBouquet": (self.switchToFileList, _("switch to filelist")),
170                                 "delete": (self.deletePlaylistEntry, _("delete playlist entry")),
171                                 "shift_stop": (self.clear_playlist, _("clear playlist")),
172                                 "shift_record": (self.playlist.PlayListShuffle, _("shuffle playlist")),
173                                 "subtitles": (self.subtitleSelection, _("Subtitle selection")),
174                         }, -2)
175
176                 self["InfobarEPGActions"] = HelpableActionMap(self, "InfobarEPGActions", 
177                         {
178                                 "showEventInfo": (self.showEventInformation, _("show event details")),
179                         })
180
181                 self["actions"] = MoviePlayerActionMap(self, ["DirectionActions"], 
182                 {
183                         "right": self.rightDown,
184                         "rightRepeated": self.doNothing,
185                         "rightUp": self.rightUp,
186                         "left": self.leftDown,
187                         "leftRepeated": self.doNothing,
188                         "leftUp": self.leftUp,
189
190                         "up": self.up,
191                         "upRepeated": self.up,
192                         "upUp": self.doNothing,
193                         "down": self.down,
194                         "downRepeated": self.down,
195                         "downUp": self.doNothing,
196                 }, -2)
197
198                 InfoBarSeek.__init__(self, actionmap = "MediaPlayerSeekActions")
199
200                 self.onClose.append(self.delMPTimer)
201                 self.onClose.append(self.__onClose)
202
203                 self.righttimer = False
204                 self.rightKeyTimer = eTimer()
205                 self.rightKeyTimer.callback.append(self.rightTimerFire)
206
207                 self.lefttimer = False
208                 self.leftKeyTimer = eTimer()
209                 self.leftKeyTimer.callback.append(self.leftTimerFire)
210
211                 self.currList = "filelist"
212                 self.isAudioCD = False
213                 self.AudioCD_albuminfo = {}
214                 self.cdAudioTrackFiles = []
215                 self.applySettings()
216
217                 self.playlistIOInternal = PlaylistIOInternal()
218                 list = self.playlistIOInternal.open(resolveFilename(SCOPE_CONFIG, "playlist.e2pls"))
219                 if list:
220                         for x in list:
221                                 self.playlist.addFile(x.ref)
222                         self.playlist.updateList()
223
224                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
225                         {
226                                 iPlayableService.evUpdatedInfo: self.__evUpdatedInfo,
227                                 iPlayableService.evUser+10: self.__evAudioDecodeError,
228                                 iPlayableService.evUser+11: self.__evVideoDecodeError,
229                                 iPlayableService.evUser+12: self.__evPluginError,
230                                 iPlayableService.evUser+13: self["coverArt"].embeddedCoverArt
231                         })
232
233         def doNothing(self):
234                 pass
235
236         def createSummary(self):
237                 return MediaPlayerLCDScreen
238
239         def exit(self):
240                 self.playlistIOInternal.clear()
241                 for x in self.playlist.list:
242                         self.playlistIOInternal.addService(ServiceReference(x[0]))
243                 if self.savePlaylistOnExit:
244                         self.playlistIOInternal.save(resolveFilename(SCOPE_CONFIG, "playlist.e2pls"))
245                 if config.mediaplayer.saveDirOnExit.getValue():
246                         config.mediaplayer.defaultDir.setValue(self.filelist.getCurrentDirectory())
247                         config.mediaplayer.defaultDir.save()
248                 hotplugNotifier.remove(self.hotplugCB)
249                 del self["coverArt"].picload
250                 self.close()
251
252         def checkSkipShowHideLock(self):
253                 self.updatedSeekState()
254
255         def doEofInternal(self, playing):
256                 if playing:
257                         self.nextEntry()
258                 else:
259                         self.show()
260
261         def __onClose(self):
262                 self.session.nav.playService(self.oldService)
263
264         def __evUpdatedInfo(self):
265                 currPlay = self.session.nav.getCurrentService()
266                 currenttitle = currPlay.info().getInfo(iServiceInformation.sCurrentTitle)
267                 totaltitles = currPlay.info().getInfo(iServiceInformation.sTotalTitles)
268                 sTitle = currPlay.info().getInfoString(iServiceInformation.sTitle)
269                 print "[__evUpdatedInfo] title %d of %d (%s)" % (currenttitle, totaltitles, sTitle)
270                 self.readTitleInformation()
271
272         def __evAudioDecodeError(self):
273                 currPlay = self.session.nav.getCurrentService()
274                 sAudioType = currPlay.info().getInfoString(iServiceInformation.sUser+10)
275                 print "[__evAudioDecodeError] audio-codec %s can't be decoded by hardware" % (sAudioType)
276                 self.session.open(MessageBox, _("This Dreambox can't decode %s streams!") % sAudioType, type = MessageBox.TYPE_INFO,timeout = 20 )
277
278         def __evVideoDecodeError(self):
279                 currPlay = self.session.nav.getCurrentService()
280                 sVideoType = currPlay.info().getInfoString(iServiceInformation.sVideoType)
281                 print "[__evVideoDecodeError] video-codec %s can't be decoded by hardware" % (sVideoType)
282                 self.session.open(MessageBox, _("This Dreambox can't decode %s streams!") % sVideoType, type = MessageBox.TYPE_INFO,timeout = 20 )
283
284         def __evPluginError(self):
285                 currPlay = self.session.nav.getCurrentService()
286                 message = currPlay.info().getInfoString(iServiceInformation.sUser+12)
287                 print "[__evPluginError]" , message
288                 self.session.open(MessageBox, message, type = MessageBox.TYPE_INFO,timeout = 20 )
289
290         def delMPTimer(self):
291                 del self.rightKeyTimer
292                 del self.leftKeyTimer
293
294         def readTitleInformation(self):
295                 currPlay = self.session.nav.getCurrentService()
296                 if currPlay is not None:
297                         sTitle = currPlay.info().getInfoString(iServiceInformation.sTitle)
298                         sAlbum = currPlay.info().getInfoString(iServiceInformation.sAlbum)
299                         sGenre = currPlay.info().getInfoString(iServiceInformation.sGenre)
300                         sArtist = currPlay.info().getInfoString(iServiceInformation.sArtist)
301                         sYear = currPlay.info().getInfoString(iServiceInformation.sTimeCreate)
302
303                         if sTitle == "":
304                                 if not self.isAudioCD:
305                                         sTitle = currPlay.info().getName().split('/')[-1]
306                                 else:
307                                         sTitle = self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()].getName()
308
309                         if self.AudioCD_albuminfo:
310                                 if sAlbum == "" and "title" in self.AudioCD_albuminfo:
311                                         sAlbum = self.AudioCD_albuminfo["title"]
312                                 if sGenre == "" and "genre" in self.AudioCD_albuminfo:
313                                         sGenre = self.AudioCD_albuminfo["genre"]
314                                 if sArtist == "" and "artist" in self.AudioCD_albuminfo:
315                                         sArtist = self.AudioCD_albuminfo["artist"]
316                                 if "year" in self.AudioCD_albuminfo:
317                                         sYear = self.AudioCD_albuminfo["year"]
318
319                         self.updateMusicInformation( sArtist, sTitle, sAlbum, sYear, sGenre, clear = True )
320                 else:
321                         self.updateMusicInformation()
322
323         def updateMusicInformation(self, artist = "", title = "", album = "", year = "", genre = "", clear = False):
324                 self.updateSingleMusicInformation("artist", artist, clear)
325                 self.updateSingleMusicInformation("title", title, clear)
326                 self.updateSingleMusicInformation("album", album, clear)
327                 self.updateSingleMusicInformation("year", year, clear)
328                 self.updateSingleMusicInformation("genre", genre, clear)
329
330         def updateSingleMusicInformation(self, name, info, clear):
331                 if info != "" or clear:
332                         if self[name].getText() != info:
333                                 self[name].setText(info)
334
335         def leftDown(self):
336                 self.lefttimer = True
337                 self.leftKeyTimer.start(1000)
338
339         def rightDown(self):
340                 self.righttimer = True
341                 self.rightKeyTimer.start(1000)
342
343         def leftUp(self):
344                 if self.lefttimer:
345                         self.leftKeyTimer.stop()
346                         self.lefttimer = False
347                         self[self.currList].pageUp()
348                         self.updateCurrentInfo()
349
350         def rightUp(self):
351                 if self.righttimer:
352                         self.rightKeyTimer.stop()
353                         self.righttimer = False
354                         self[self.currList].pageDown()
355                         self.updateCurrentInfo()
356
357         def leftTimerFire(self):
358                 self.leftKeyTimer.stop()
359                 self.lefttimer = False
360                 self.switchToFileList()
361
362         def rightTimerFire(self):
363                 self.rightKeyTimer.stop()
364                 self.righttimer = False
365                 self.switchToPlayList()
366
367         def switchToFileList(self):
368                 self.currList = "filelist"
369                 self.filelist.selectionEnabled(1)
370                 self.playlist.selectionEnabled(0)
371                 self.updateCurrentInfo()
372
373         def switchToPlayList(self):
374                 if len(self.playlist) != 0:
375                         self.currList = "playlist"
376                         self.filelist.selectionEnabled(0)
377                         self.playlist.selectionEnabled(1)
378                         self.updateCurrentInfo()
379
380         def up(self):
381                 self[self.currList].up()
382                 self.updateCurrentInfo()
383
384         def down(self):
385                 self[self.currList].down()
386                 self.updateCurrentInfo()
387
388         def showAfterSeek(self):
389                 self.show()
390
391         def showAfterCuesheetOperation(self):
392                 self.show()
393
394         def hideAfterResume(self):
395                 self.hide()
396
397         def getIdentifier(self, ref):
398                 if self.isAudioCD:
399                         return ref.getName()
400                 else:
401                         text = ref.getPath()
402                         return text.split('/')[-1]
403
404         # FIXME: maybe this code can be optimized 
405         def updateCurrentInfo(self):
406                 text = ""
407                 if self.currList == "filelist":
408                         idx = self.filelist.getSelectionIndex()
409                         r = self.filelist.list[idx]
410                         text = r[1][7]
411                         if r[0][1] == True:
412                                 if len(text) < 2:
413                                         text += " "
414                                 if text[:2] != "..":
415                                         text = "/" + text
416                         self.summaries.setText(text,1)
417
418                         idx += 1
419                         if idx < len(self.filelist.list):
420                                 r = self.filelist.list[idx]
421                                 text = r[1][7]
422                                 if r[0][1] == True:
423                                         text = "/" + text
424                                 self.summaries.setText(text,3)
425                         else:
426                                 self.summaries.setText(" ",3)
427
428                         idx += 1
429                         if idx < len(self.filelist.list):
430                                 r = self.filelist.list[idx]
431                                 text = r[1][7]
432                                 if r[0][1] == True:
433                                         text = "/" + text
434                                 self.summaries.setText(text,4)
435                         else:
436                                 self.summaries.setText(" ",4)
437
438                         text = ""
439                         if not self.filelist.canDescent():
440                                 r = self.filelist.getServiceRef()
441                                 if r is None:
442                                         return
443                                 text = r.getPath()
444                                 self["currenttext"].setText(os_path.basename(text))
445
446                 if self.currList == "playlist":
447                         t = self.playlist.getSelection()
448                         if t is None:
449                                 return
450                         #display current selected entry on LCD
451                         text = self.getIdentifier(t)
452                         self.summaries.setText(text,1)
453                         self["currenttext"].setText(text)
454                         idx = self.playlist.getSelectionIndex()
455                         idx += 1
456                         if idx < len(self.playlist):
457                                 currref = self.playlist.getServiceRefList()[idx]
458                                 text = self.getIdentifier(currref)
459                                 self.summaries.setText(text,3)
460                         else:
461                                 self.summaries.setText(" ",3)
462
463                         idx += 1
464                         if idx < len(self.playlist):
465                                 currref = self.playlist.getServiceRefList()[idx]
466                                 text = self.getIdentifier(currref)
467                                 self.summaries.setText(text,4)
468                         else:
469                                 self.summaries.setText(" ",4)
470
471         def ok(self):
472                 if self.currList == "filelist":
473                         if self.filelist.canDescent():
474                                 self.filelist.descent()
475                                 self.updateCurrentInfo()
476                         else:
477                                 self.copyFile()
478
479                 if self.currList == "playlist":
480                         selection = self["playlist"].getSelection()
481                         self.changeEntry(self.playlist.getSelectionIndex())
482
483         def showMenu(self):
484                 menu = []
485                 if len(self.cdAudioTrackFiles):
486                         menu.insert(0,(_("Play Audio-CD..."), "audiocd"))
487                 if self.currList == "filelist":
488                         if self.filelist.canDescent():
489                                 menu.append((_("add directory to playlist"), "copydir"))
490                         else:
491                                 menu.append((_("add files to playlist"), "copyfiles"))
492                         menu.append((_("switch to playlist"), "playlist"))
493                         if config.usage.setup_level.index >= 1: # intermediate+
494                                 menu.append((_("delete file"), "deletefile"))
495                 else:
496                         menu.append((_("switch to filelist"), "filelist"))
497                         menu.append((_("clear playlist"), "clear"))
498                         menu.append((_("Delete entry"), "deleteentry"))
499                         if config.usage.setup_level.index >= 1: # intermediate+
500                                 menu.append((_("shuffle playlist"), "shuffle"))
501                 menu.append((_("hide player"), "hide"));
502                 menu.append((_("load playlist"), "loadplaylist"));
503                 if config.usage.setup_level.index >= 1: # intermediate+
504                         menu.append((_("save playlist"), "saveplaylist"));
505                         menu.append((_("delete saved playlist"), "deleteplaylist"));
506                         menu.append((_("Edit settings"), "settings"))
507                 self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu)
508
509         def menuCallback(self, choice):
510                 if choice is None:
511                         return
512
513                 if choice[1] == "copydir":
514                         self.copyDirectory(self.filelist.getSelection()[0])
515                 elif choice[1] == "copyfiles":
516                         self.stopEntry()
517                         self.playlist.clear()
518                         self.isAudioCD = False
519                         self.copyDirectory(os_path.dirname(self.filelist.getSelection()[0].getPath()) + "/", recursive = False)
520                         self.playServiceRefEntry(self.filelist.getServiceRef())
521                 elif choice[1] == "playlist":
522                         self.switchToPlayList()
523                 elif choice[1] == "filelist":
524                         self.switchToFileList()
525                 elif choice[1] == "deleteentry":
526                         if self.playlist.getSelectionIndex() == self.playlist.getCurrentIndex():
527                                 self.stopEntry()
528                         self.deleteEntry()
529                 elif choice[1] == "clear":
530                         self.clear_playlist()
531                 elif choice[1] == "hide":
532                         self.hide()
533                 elif choice[1] == "saveplaylist":
534                         self.save_playlist()
535                 elif choice[1] == "loadplaylist":
536                         self.load_playlist()
537                 elif choice[1] == "deleteplaylist":
538                         self.delete_saved_playlist()
539                 elif choice[1] == "shuffle":
540                         self.playlist.PlayListShuffle()
541                 elif choice[1] == "deletefile":
542                         self.deleteFile()
543                 elif choice[1] == "settings":
544                         self.session.openWithCallback(self.applySettings, MediaPlayerSettings, self)
545                 elif choice[1] == "audiocd":
546                         self.playAudioCD()
547
548         def playAudioCD(self):
549                 from enigma import eServiceReference
550                 from Plugins.Extensions.CDInfo.plugin import Query
551
552                 if len(self.cdAudioTrackFiles):
553                         self.playlist.clear()
554                         self.savePlaylistOnExit = False
555                         self.isAudioCD = True
556                         for file in self.cdAudioTrackFiles:
557                                 ref = eServiceReference(4097, 0, file)
558                                 self.playlist.addFile(ref)
559                         cdinfo = Query(self)
560                         cdinfo.scan()
561                         self.changeEntry(0)
562                         self.switchToPlayList()
563
564         def applySettings(self):
565                 self.savePlaylistOnExit = config.mediaplayer.savePlaylistOnExit.getValue()
566                 if config.mediaplayer.repeat.getValue() == True:
567                         self["repeat"].setPixmapNum(1)
568                 else:
569                         self["repeat"].setPixmapNum(0)
570
571         def showEventInformation(self):
572                 from Screens.EventView import EventViewSimple
573                 from ServiceReference import ServiceReference
574                 evt = self[self.currList].getCurrentEvent()
575                 if evt:
576                         self.session.open(EventViewSimple, evt, ServiceReference(self.getCurrent()))
577
578         # also works on filelist (?)
579         def getCurrent(self):
580                 return self["playlist"].getCurrent()
581
582         def deletePlaylistEntry(self):
583                 if self.currList == "playlist":
584                         if self.playlist.getSelectionIndex() == self.playlist.getCurrentIndex():
585                                 self.stopEntry()
586                         self.deleteEntry()
587
588         def skip_listbegin(self):
589                 if self.currList == "filelist":
590                         self.filelist.moveToIndex(0)
591                 else:
592                         self.playlist.moveToIndex(0)
593                 self.updateCurrentInfo()
594
595         def skip_listend(self):
596                 if self.currList == "filelist":
597                         idx = len(self.filelist.list)
598                         self.filelist.moveToIndex(idx - 1)
599                 else:
600                         self.playlist.moveToIndex(len(self.playlist)-1)
601                 self.updateCurrentInfo()
602
603         def save_playlist(self):
604                 self.session.openWithCallback(self.save_playlist2,InputBox, title=_("Please enter filename (empty = use current date)"),windowTitle = _("Save Playlist"))
605
606         def save_playlist2(self, name):
607                 if name is not None:
608                         name = name.strip()
609                         if name == "":
610                                 name = strftime("%y%m%d_%H%M%S")
611                         name += ".e2pls"
612                         self.playlistIOInternal.clear()
613                         for x in self.playlist.list:
614                                 self.playlistIOInternal.addService(ServiceReference(x[0]))
615                         self.playlistIOInternal.save(resolveFilename(SCOPE_PLAYLIST) + name)
616
617         def load_playlist(self):
618                 listpath = []
619                 playlistdir = resolveFilename(SCOPE_PLAYLIST)
620                 try:
621                         for i in os_listdir(playlistdir):
622                                 listpath.append((i,playlistdir + i))
623                 except IOError,e:
624                         print "Error while scanning subdirs ",e
625                 self.session.openWithCallback(self.PlaylistSelected, ChoiceBox, title=_("Please select a playlist..."), list = listpath)
626
627         def PlaylistSelected(self,path):
628                 if path is not None:
629                         self.clear_playlist()
630                         extension = path[0].rsplit('.',1)[-1]
631                         if self.playlistparsers.has_key(extension):
632                                 playlist = self.playlistparsers[extension]()
633                                 list = playlist.open(path[1])
634                                 for x in list:
635                                         self.playlist.addFile(x.ref)
636                         self.playlist.updateList()
637
638         def delete_saved_playlist(self):
639                 listpath = []
640                 playlistdir = resolveFilename(SCOPE_PLAYLIST)
641                 try:
642                         for i in os_listdir(playlistdir):
643                                 listpath.append((i,playlistdir + i))
644                 except IOError,e:
645                         print "Error while scanning subdirs ",e
646                 self.session.openWithCallback(self.DeletePlaylistSelected, ChoiceBox, title=_("Please select a playlist to delete..."), list = listpath)
647
648         def DeletePlaylistSelected(self,path):
649                 if path is not None:
650                         self.delname = path[1]
651                         self.session.openWithCallback(self.deleteConfirmed, MessageBox, _("Do you really want to delete %s?") % (path[1]))
652
653         def deleteConfirmed(self, confirmed):
654                 if confirmed:
655                         try:
656                                 os_remove(self.delname)
657                         except OSError,e:
658                                 print "delete failed:", e
659                                 self.session.open(MessageBox, _("Delete failed!"), MessageBox.TYPE_ERROR)
660
661         def clear_playlist(self):
662                 self.isAudioCD = False
663                 self.stopEntry()
664                 self.playlist.clear()
665                 self.switchToFileList()
666
667         def copyDirectory(self, directory, recursive = True):
668                 print "copyDirectory", directory
669                 if directory == '/':
670                         print "refusing to operate on /"
671                         return
672                 filelist = FileList(directory, useServiceRef = True, showMountpoints = False, isTop = True)
673
674                 for x in filelist.getFileList():
675                         if x[0][1] == True: #isDir
676                                 if recursive:
677                                         if x[0][0] != directory:
678                                                 self.copyDirectory(x[0][0])
679                         elif filelist.getServiceRef() and filelist.getServiceRef().type == 4097:
680                                 self.playlist.addFile(x[0][0])
681                 self.playlist.updateList()
682
683         def deleteFile(self):
684                 if self.currList == "filelist":
685                         self.service = self.filelist.getServiceRef()
686                 else:
687                         self.service = self.playlist.getSelection()
688                 if self.service is None:
689                         return
690                 if self.service.type != 4098 and self.session.nav.getCurrentlyPlayingServiceReference() is not None:
691                         if self.service == self.session.nav.getCurrentlyPlayingServiceReference():
692                                 self.stopEntry()
693
694                 serviceHandler = eServiceCenter.getInstance()
695                 offline = serviceHandler.offlineOperations(self.service)
696                 info = serviceHandler.info(self.service)
697                 name = info and info.getName(self.service)
698                 result = False
699                 if offline is not None:
700                         # simulate first
701                         if not offline.deleteFromDisk(1):
702                                 result = True
703                 if result == True:
704                         self.session.openWithCallback(self.deleteConfirmed_offline, MessageBox, _("Do you really want to delete %s?") % (name))
705                 else:
706                         self.session.openWithCallback(self.close, MessageBox, _("You cannot delete this!"), MessageBox.TYPE_ERROR)      
707
708         def deleteConfirmed_offline(self, confirmed):
709                 if confirmed:
710                         serviceHandler = eServiceCenter.getInstance()
711                         offline = serviceHandler.offlineOperations(self.service)
712                         result = False
713                         if offline is not None:
714                                 # really delete!
715                                 if not offline.deleteFromDisk(0):
716                                         result = True
717                         if result == False:
718                                 self.session.open(MessageBox, _("Delete failed!"), MessageBox.TYPE_ERROR)
719                         else:
720                                 self.removeListEntry()
721
722         def removeListEntry(self):
723                 currdir = self.filelist.getCurrentDirectory()
724                 self.filelist.changeDir(currdir)
725                 deleteend = False
726                 while not deleteend:
727                         index = 0
728                         deleteend = True
729                         if len(self.playlist) > 0:
730                                 for x in self.playlist.list:
731                                         if self.service == x[0]:
732                                                 self.playlist.deleteFile(index)
733                                                 deleteend = False
734                                                 break
735                                         index += 1
736                 self.playlist.updateList()
737                 if self.currList == "playlist":
738                         if len(self.playlist) == 0:
739                                 self.switchToFileList()
740
741         def copyFile(self):
742                 if self.filelist.getServiceRef().type == 4098: # playlist
743                         ServiceRef = self.filelist.getServiceRef()
744                         extension = ServiceRef.getPath()[ServiceRef.getPath().rfind('.') + 1:]
745                         if self.playlistparsers.has_key(extension):
746                                 playlist = self.playlistparsers[extension]()
747                                 list = playlist.open(ServiceRef.getPath())
748                                 for x in list:
749                                         self.playlist.addFile(x.ref)
750                         self.playlist.updateList()
751                 else:
752                         self.playlist.addFile(self.filelist.getServiceRef())
753                         self.playlist.updateList()
754                         if len(self.playlist) == 1:
755                                 self.changeEntry(0)
756
757         def addPlaylistParser(self, parser, extension):
758                 self.playlistparsers[extension] = parser
759
760         def nextEntry(self):
761                 next = self.playlist.getCurrentIndex() + 1
762                 if next < len(self.playlist):
763                         self.changeEntry(next)
764                 elif ( len(self.playlist) > 0 ) and ( config.mediaplayer.repeat.getValue() == True ):
765                         self.stopEntry()
766                         self.changeEntry(0)
767
768         def nextMarkOrEntry(self):
769                 if not self.jumpPreviousNextMark(lambda x: x):
770                         next = self.playlist.getCurrentIndex() + 1
771                         if next < len(self.playlist):
772                                 self.changeEntry(next)
773                         else:
774                                 self.doSeek(-1)
775
776         def previousMarkOrEntry(self):
777                 if not self.jumpPreviousNextMark(lambda x: -x-5*90000, start=True):
778                         next = self.playlist.getCurrentIndex() - 1
779                         if next >= 0:
780                                 self.changeEntry(next)
781
782         def deleteEntry(self):
783                 self.playlist.deleteFile(self.playlist.getSelectionIndex())
784                 self.playlist.updateList()
785                 if len(self.playlist) == 0:
786                         self.switchToFileList()
787
788         def changeEntry(self, index):
789                 self.playlist.setCurrentPlaying(index)
790                 self.playEntry()
791
792         def playServiceRefEntry(self, serviceref):
793                 serviceRefList = self.playlist.getServiceRefList()
794                 for count in range(len(serviceRefList)):
795                         if serviceRefList[count] == serviceref:
796                                 self.changeEntry(count)
797                                 break
798                         
799         def xplayEntry(self):
800                 if self.currList == "playlist":
801                         self.playEntry()
802                 else:
803                         self.stopEntry()
804                         self.playlist.clear()
805                         self.isAudioCD = False
806                         sel = self.filelist.getSelection()
807                         if sel:
808                                 if sel[1]: # can descent
809                                         # add directory to playlist
810                                         self.copyDirectory(sel[0])
811                                 else:
812                                         # add files to playlist
813                                         self.copyDirectory(os_path.dirname(sel[0].getPath()) + "/", recursive = False)
814                         if len(self.playlist) > 0:
815                                 self.changeEntry(0)
816         
817         def playEntry(self):
818                 if len(self.playlist.getServiceRefList()):
819                         audio_extensions = (".mp2", ".mp3", ".wav", ".ogg", "flac", "m4a")
820                         needsInfoUpdate = False
821                         currref = self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()]
822                         if self.session.nav.getCurrentlyPlayingServiceReference() is None or currref != self.session.nav.getCurrentlyPlayingServiceReference():
823                                 self.session.nav.playService(self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()])
824                                 info = eServiceCenter.getInstance().info(currref)
825                                 description = info and info.getInfoString(currref, iServiceInformation.sDescription) or ""
826                                 self["title"].setText(description)
827                                 # display just playing musik on LCD
828                                 idx = self.playlist.getCurrentIndex()
829                                 currref = self.playlist.getServiceRefList()[idx]
830                                 text = self.getIdentifier(currref)
831                                 text = ">"+text
832                                 ext = text[-4:].lower()
833
834                                 # FIXME: the information if the service contains video (and we should hide our window) should com from the service instead 
835                                 if ext not in audio_extensions and not self.isAudioCD:
836                                         self.hide()
837                                 else:
838                                         needsInfoUpdate = True
839                                 self.summaries.setText(text,1)
840
841                                 # get the next two entries
842                                 idx += 1
843                                 if idx < len(self.playlist):
844                                         currref = self.playlist.getServiceRefList()[idx]
845                                         text = self.getIdentifier(currref)
846                                         self.summaries.setText(text,3)
847                                 else:
848                                         self.summaries.setText(" ",3)
849
850                                 idx += 1
851                                 if idx < len(self.playlist):
852                                         currref = self.playlist.getServiceRefList()[idx]
853                                         text = self.getIdentifier(currref)
854                                         self.summaries.setText(text,4)
855                                 else:
856                                         self.summaries.setText(" ",4)
857                         else:
858                                 idx = self.playlist.getCurrentIndex()
859                                 currref = self.playlist.getServiceRefList()[idx]
860                                 text = currref.getPath()
861                                 ext = text[-4:].lower()
862                                 if ext not in audio_extensions and not self.isAudioCD:
863                                         self.hide()
864                                 else:
865                                         needsInfoUpdate = True
866
867                         self.unPauseService()
868                         if needsInfoUpdate == True:
869                                 path = self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()].getPath()
870                                 self["coverArt"].updateCoverArt(path)
871                         else:
872                                 self["coverArt"].showDefaultCover()
873                         self.readTitleInformation()
874
875         def updatedSeekState(self):
876                 if self.seekstate == self.SEEK_STATE_PAUSE:
877                         self.playlist.pauseFile()
878                 elif self.seekstate == self.SEEK_STATE_PLAY:
879                         self.playlist.playFile()
880                 elif self.isStateForward(self.seekstate):
881                         self.playlist.forwardFile()
882                 elif self.isStateBackward(self.seekstate):
883                         self.playlist.rewindFile()
884
885         def pauseEntry(self):
886                 self.pauseService()
887                 if self.seekstate == self.SEEK_STATE_PAUSE:
888                         self.show()
889                 else:
890                         self.hide()
891
892         def stopEntry(self):
893                 self.playlist.stopFile()
894                 self.session.nav.playService(None)
895                 self.updateMusicInformation(clear=True)
896                 self.show()
897
898         def unPauseService(self):
899                 self.setSeekState(self.SEEK_STATE_PLAY)
900                 
901         def subtitleSelection(self):
902                 from Screens.Subtitles import Subtitles
903                 self.session.open(Subtitles)
904         
905         def hotplugCB(self, dev, media_state):
906                 if dev == harddiskmanager.getCD():
907                         if media_state == "1":
908                                 from Components.Scanner import scanDevice
909                                 devpath = harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD())
910                                 self.cdAudioTrackFiles = []
911                                 res = scanDevice(devpath)
912                                 list = [ (r.description, r, res[r], self.session) for r in res ]
913                                 if list:
914                                         (desc, scanner, files, session) = list[0]
915                                         for file in files:
916                                                 if file.mimetype == "audio/x-cda":
917                                                         self.cdAudioTrackFiles.append(file.path)
918                         else:
919                                 self.cdAudioTrackFiles = []
920                                 if self.isAudioCD:
921                                         self.clear_playlist()
922
923 class MediaPlayerLCDScreen(Screen):
924         skin = """
925         <screen position="0,0" size="132,64" title="LCD Text">
926                 <widget name="text1" position="4,0" size="132,35" font="Regular;16"/>
927                 <widget name="text3" position="4,36" size="132,14" font="Regular;10"/>
928                 <widget name="text4" position="4,49" size="132,14" font="Regular;10"/>
929         </screen>"""
930
931         def __init__(self, session, parent):
932                 Screen.__init__(self, session)
933                 self["text1"] = Label("Mediaplayer")
934                 self["text3"] = Label("")
935                 self["text4"] = Label("")
936
937         def setText(self, text, line):
938                 if len(text) > 10:
939                         if text[-4:] == ".mp3":
940                                 text = text[:-4]
941                 textleer = "    "
942                 text = text + textleer*10
943                 if line == 1:
944                         self["text1"].setText(text)
945                 elif line == 3:
946                         self["text3"].setText(text)
947                 elif line == 4:
948                         self["text4"].setText(text)
949
950 def main(session, **kwargs):
951         session.open(MediaPlayer)
952
953 def menu(menuid, **kwargs):
954         if menuid == "mainmenu":
955                 return [(_("Media player"), main, "media_player", 45)]
956         return []
957
958 def filescan_open(list, session, **kwargs):
959         from enigma import eServiceReference
960
961         mp = session.open(MediaPlayer)
962         mp.playlist.clear()
963         mp.savePlaylistOnExit = False
964
965         for file in list:
966                 if file.mimetype == "video/MP2T":
967                         stype = 1
968                 else:
969                         stype = 4097
970                 ref = eServiceReference(stype, 0, file.path)
971                 mp.playlist.addFile(ref)
972
973         mp.changeEntry(0)
974         mp.switchToPlayList()
975
976 def audioCD_open(list, session, **kwargs):
977         from enigma import eServiceReference
978
979         mp = session.open(MediaPlayer)
980         mp.cdAudioTrackFiles = []
981         for file in list:
982                 mp.cdAudioTrackFiles.append(file.path)
983         mp.playAudioCD()
984
985 def filescan(**kwargs):
986         from Components.Scanner import Scanner, ScanPath
987         mediatypes = [
988                 Scanner(mimetypes = ["video/mpeg", "video/MP2T", "video/x-msvideo"],
989                         paths_to_scan =
990                                 [
991                                         ScanPath(path = "", with_subdirs = False),
992                                 ],
993                         name = "Movie",
994                         description = _("View Movies..."),
995                         openfnc = filescan_open,
996                 ),
997                 Scanner(mimetypes = ["video/x-vcd"],
998                         paths_to_scan =
999                                 [
1000                                         ScanPath(path = "mpegav", with_subdirs = False),
1001                                         ScanPath(path = "MPEGAV", with_subdirs = False),
1002                                 ],
1003                         name = "Video CD",
1004                         description = _("View Video CD..."),
1005                         openfnc = filescan_open,
1006                 ),
1007                 Scanner(mimetypes = ["audio/mpeg", "audio/x-wav", "application/ogg", "audio/x-flac"],
1008                         paths_to_scan =
1009                                 [
1010                                         ScanPath(path = "", with_subdirs = False),
1011                                 ],
1012                         name = "Music",
1013                         description = _("Play Music..."),
1014                         openfnc = filescan_open,
1015                 )]
1016         try:
1017                 from Plugins.Extensions.CDInfo.plugin import Query
1018                 mediatypes.append(
1019                 Scanner(mimetypes = ["audio/x-cda"],
1020                         paths_to_scan =
1021                                 [
1022                                         ScanPath(path = "", with_subdirs = False),
1023                                 ],
1024                         name = "Audio-CD",
1025                         description = _("Play Audio-CD..."),
1026                         openfnc = audioCD_open,
1027                 ))
1028                 return mediatypes
1029         except ImportError:
1030                 return mediatypes
1031
1032 from Plugins.Plugin import PluginDescriptor
1033 def Plugins(**kwargs):
1034         return [
1035                 PluginDescriptor(name = "MediaPlayer", description = "Play back media files", where = PluginDescriptor.WHERE_MENU, fnc = menu),
1036                 PluginDescriptor(name = "MediaPlayer", where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)
1037         ]