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