add .mp2 as supported filetype
[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                         self.playlistIOInternal = PlaylistIOInternal()
596                         list = self.playlistIOInternal.open(path[1])
597                         if list:
598                                 for x in list:
599                                         self.playlist.addFile(x.ref)
600                                 self.playlist.updateList()
601
602         def delete_saved_playlist(self):
603                 listpath = []
604                 playlistdir = resolveFilename(SCOPE_PLAYLIST)
605                 try:
606                         for i in os_listdir(playlistdir):
607                                 listpath.append((i,playlistdir + i))
608                 except IOError,e:
609                         print "Error while scanning subdirs ",e
610                 self.session.openWithCallback(self.DeletePlaylistSelected, ChoiceBox, title=_("Please select a playlist to delete..."), list = listpath)
611
612         def DeletePlaylistSelected(self,path):
613                 if path is not None:
614                         self.delname = path[1]
615                         self.session.openWithCallback(self.deleteConfirmed, MessageBox, _("Do you really want to delete %s?") % (path[1]))
616
617         def deleteConfirmed(self, confirmed):
618                 if confirmed:
619                         os_remove(self.delname)
620
621         def clear_playlist(self):
622                 self.stopEntry()
623                 self.playlist.clear()
624                 self.switchToFileList()
625
626         def copyDirectory(self, directory, recursive = True):
627                 print "copyDirectory", directory
628                 filelist = FileList(directory, useServiceRef = True, isTop = True)
629
630                 for x in filelist.getFileList():
631                         if x[0][1] == True: #isDir
632                                 if recursive:
633                                         self.copyDirectory(x[0][0])
634                         else:
635                                 self.playlist.addFile(x[0][0])
636                 self.playlist.updateList()
637
638         def copyFile(self):
639                 if self.filelist.getServiceRef().type == 4098: # playlist
640                         ServiceRef = self.filelist.getServiceRef()
641                         extension = ServiceRef.getPath()[ServiceRef.getPath().rfind('.') + 1:]
642                         print "extension:", extension
643                         if self.playlistparsers.has_key(extension):
644                                 playlist = self.playlistparsers[extension]()
645                                 list = playlist.open(ServiceRef.getPath())
646                                 for x in list:
647                                         self.playlist.addFile(x.ref)
648                 else:
649                         self.playlist.addFile(self.filelist.getServiceRef())
650                         self.playlist.updateList()
651                         if len(self.playlist) == 1:
652                                 self.changeEntry(0)
653
654         def addPlaylistParser(self, parser, extension):
655                 self.playlistparsers[extension] = parser
656
657         def nextEntry(self):
658                 next = self.playlist.getCurrentIndex() + 1
659                 if next < len(self.playlist):
660                         self.changeEntry(next)
661                 elif ( len(self.playlist) > 0 ) and ( self.repeat == True ):
662                         self.stopEntry()
663                         self.changeEntry(0)
664
665         def nextMarkOrEntry(self):
666                 if not self.jumpPreviousNextMark(lambda x: x):
667                         next = self.playlist.getCurrentIndex() + 1
668                         if next < len(self.playlist):
669                                 self.changeEntry(next)
670                         else:
671                                 self.doSeek(-1)
672
673         def previousMarkOrEntry(self):
674                 if not self.jumpPreviousNextMark(lambda x: -x-5*90000, start=True):
675                         next = self.playlist.getCurrentIndex() - 1
676                         if next >= 0:
677                                 self.changeEntry(next)
678
679         def deleteEntry(self):
680                 self.playlist.deleteFile(self.playlist.getSelectionIndex())
681                 self.playlist.updateList()
682                 if len(self.playlist) == 0:
683                         self.switchToFileList()
684
685         def changeEntry(self, index):
686                 self.playlist.setCurrentPlaying(index)
687                 self.playEntry()
688
689         def playServiceRefEntry(self, serviceref):
690                 serviceRefList = self.playlist.getServiceRefList()
691                 for count in range(len(serviceRefList)):
692                         if serviceRefList[count] == serviceref:
693                                 self.changeEntry(count)
694                                 break
695                         
696         def xplayEntry(self):
697                 if self.currList == "playlist":
698                         self.playEntry()
699                 else:
700                         self.stopEntry()
701                         self.playlist.clear()
702                         sel = self.filelist.getSelection()
703                         if sel:
704                                 if sel[1]: # can descent
705                                         # add directory to playlist
706                                         self.copyDirectory(sel[0])
707                                 else:
708                                         # add files to playlist
709                                         self.copyDirectory(os_path.dirname(sel[0].getPath()) + "/", recursive = False)
710                         if len(self.playlist) > 0:
711                                 self.changeEntry(0)
712         
713         def playEntry(self):
714                 if len(self.playlist.getServiceRefList()):
715                         needsInfoUpdate = False
716                         currref = self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()]
717                         if self.session.nav.getCurrentlyPlayingServiceReference() is None or currref != self.session.nav.getCurrentlyPlayingServiceReference():
718                                 self.session.nav.playService(self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()])
719                                 info = eServiceCenter.getInstance().info(currref)
720                                 description = info and info.getInfoString(currref, iServiceInformation.sDescription) or ""
721                                 self["title"].setText(description)
722                                 # display just playing musik on LCD
723                                 idx = self.playlist.getCurrentIndex()
724                                 currref = self.playlist.getServiceRefList()[idx]
725                                 text = self.getIdentifier(currref)
726                                 text = ">"+text
727                                 ext = text[-4:].lower()
728
729                                 # FIXME: the information if the service contains video (and we should hide our window) should com from the service instead 
730                                 if ext not in [".mp2", ".mp3", ".wav", ".ogg", "flac"] and not self.isAudioCD:
731                                         self.hide()
732                                 else:
733                                         needsInfoUpdate = True
734                                 self.summaries.setText(text,1)
735
736                                 # get the next two entries
737                                 idx += 1
738                                 if idx < len(self.playlist):
739                                         currref = self.playlist.getServiceRefList()[idx]
740                                         text = self.getIdentifier(currref)
741                                         self.summaries.setText(text,3)
742                                 else:
743                                         self.summaries.setText(" ",3)
744
745                                 idx += 1
746                                 if idx < len(self.playlist):
747                                         currref = self.playlist.getServiceRefList()[idx]
748                                         text = self.getIdentifier(currref)
749                                         self.summaries.setText(text,4)
750                                 else:
751                                         self.summaries.setText(" ",4)
752                         else:
753                                 idx = self.playlist.getCurrentIndex()
754                                 currref = self.playlist.getServiceRefList()[idx]
755                                 text = currref.getPath()
756                                 ext = text[-4:].lower()
757                                 if ext not in [".mp2", ".mp3", ".wav", ".ogg", "flac"] and not self.isAudioCD:
758                                         self.hide()
759                                 else:
760                                         needsInfoUpdate = True
761
762                         self.unPauseService()
763                         if needsInfoUpdate == True:
764                                 self.updateCoverArtPixmap(currref.getPath())
765                         else:
766                                 pngname = self["coverArt"].default_pixmap
767                                 self.coverArtFileName = pngname
768                                 self["coverArt"].instance.setPixmapFromFile(self.coverArtFileName)
769                         self.readTitleInformation()
770
771         def updatedSeekState(self):
772                 if self.seekstate == self.SEEK_STATE_PAUSE:
773                         self.playlist.pauseFile()
774                 elif self.seekstate == self.SEEK_STATE_PLAY:
775                         self.playlist.playFile()
776                 elif self.isStateForward(self.seekstate):
777                         self.playlist.forwardFile()
778                 elif self.isStateBackward(self.seekstate):
779                         self.playlist.rewindFile()
780
781         def pauseEntry(self):
782                 self.pauseService()
783                 if self.seekstate == self.SEEK_STATE_PAUSE:
784                         self.show()
785                 else:
786                         self.hide()
787
788         def stopEntry(self):
789                 self.playlist.stopFile()
790                 self.session.nav.playService(None)
791                 self.updateMusicInformation(clear=True)
792                 self.show()
793
794         def unPauseService(self):
795                 self.setSeekState(self.SEEK_STATE_PLAY)
796                 
797         def subtitleSelection(self):
798                 from Screens.Subtitles import Subtitles
799                 self.session.open(Subtitles)            
800
801 class MediaPlayerLCDScreen(Screen):
802         skin = """
803         <screen position="0,0" size="132,64" title="LCD Text">
804                 <widget name="text1" position="4,0" size="132,35" font="Regular;16"/>
805                 <widget name="text3" position="4,36" size="132,14" font="Regular;10"/>
806                 <widget name="text4" position="4,49" size="132,14" font="Regular;10"/>
807         </screen>"""
808
809         def __init__(self, session, parent):
810                 Screen.__init__(self, session)
811                 self["text1"] = Label("Mediaplayer")
812                 self["text3"] = Label("")
813                 self["text4"] = Label("")
814
815         def setText(self, text, line):
816                 print "lcd set text:", text, line
817                 if len(text) > 10:
818                         if text[-4:] == ".mp3":
819                                 text = text[:-4]
820                 textleer = "    "
821                 text = text + textleer*10
822                 if line == 1:
823                         self["text1"].setText(text)
824                 elif line == 3:
825                         self["text3"].setText(text)
826                 elif line == 4:
827                         self["text4"].setText(text)
828
829 def main(session, **kwargs):
830         session.open(MediaPlayer)
831
832 def menu(menuid, **kwargs):
833         if menuid == "mainmenu":
834                 return [(_("Media player"), main, "media_player", 45)]
835         return []
836
837 def filescan_open(list, session, **kwargs):
838         from enigma import eServiceReference
839
840         mp = session.open(MediaPlayer)
841         mp.playlist.clear()
842         mp.savePlaylistOnExit = False
843
844         for file in list:
845                 if file.mimetype == "video/MP2T":
846                         stype = 1
847                 else:
848                         stype = 4097
849                 ref = eServiceReference(stype, 0, file.path)
850                 mp.playlist.addFile(ref)
851
852         mp.changeEntry(0)
853         mp.switchToPlayList()
854
855 def audioCD_open(list, session, **kwargs):
856         from enigma import eServiceReference
857
858         mp = session.open(MediaPlayer)
859         mp.cdAudioTrackFiles = []
860         for file in list:
861                 mp.cdAudioTrackFiles.append(file.path)
862         mp.playAudioCD()
863
864 def filescan(**kwargs):
865         from Components.Scanner import Scanner, ScanPath
866         mediatypes = [
867                 Scanner(mimetypes = ["video/mpeg", "video/MP2T", "video/x-msvideo"],
868                         paths_to_scan =
869                                 [
870                                         ScanPath(path = "", with_subdirs = False),
871                                 ],
872                         name = "Movie",
873                         description = "View Movies...",
874                         openfnc = filescan_open,
875                 ),
876                 Scanner(mimetypes = ["video/x-vcd"],
877                         paths_to_scan =
878                                 [
879                                         ScanPath(path = "mpegav", with_subdirs = False),
880                                         ScanPath(path = "MPEGAV", with_subdirs = False),
881                                 ],
882                         name = "Video CD",
883                         description = "View Video CD...",
884                         openfnc = filescan_open,
885                 ),
886                 Scanner(mimetypes = ["audio/mpeg", "audio/x-wav", "application/ogg", "audio/x-flac"],
887                         paths_to_scan =
888                                 [
889                                         ScanPath(path = "", with_subdirs = False),
890                                 ],
891                         name = "Music",
892                         description = "Play Music...",
893                         openfnc = filescan_open,
894                 )]
895         try:
896                 from Plugins.Extensions.CDInfo.plugin import Query
897                 mediatypes.append(
898                 Scanner(mimetypes = ["audio/x-cda"],
899                         paths_to_scan =
900                                 [
901                                         ScanPath(path = "", with_subdirs = False),
902                                 ],
903                         name = "Audio-CD",
904                         description = "Play Audio-CD...",
905                         openfnc = audioCD_open,
906                 ))
907                 return mediatypes
908         except ImportError:
909                 return mediatypes
910
911 from Plugins.Plugin import PluginDescriptor
912 def Plugins(**kwargs):
913         return [
914                 PluginDescriptor(name = "MediaPlayer", description = "Play back media files", where = PluginDescriptor.WHERE_MENU, fnc = menu),
915                 PluginDescriptor(name = "MediaPlayer", where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)
916         ]