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