add a repeat playlist function to mediaplayer (on behalf of Nix_niX)
[vuplus_dvbapp] / 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)", 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                 
169                 self.playlistIOInternal = PlaylistIOInternal()
170                 list = self.playlistIOInternal.open(resolveFilename(SCOPE_CONFIG, "playlist.e2pls"))
171                 if list:
172                         for x in list:
173                                 self.playlist.addFile(x.ref)
174                         self.playlist.updateList()
175
176                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
177                         {
178                                 iPlayableService.evUpdatedInfo: self.__evUpdatedInfo
179                         })
180
181         def doNothing(self):
182                 pass
183
184         def createSummary(self):
185                 return MediaPlayerLCDScreen
186
187         def exit(self):
188                 self.session.openWithCallback(self.exitCB, MessageBox, _("Do you really want to exit?"), timeout=5)
189
190         def exitCB(self, answer):
191                 if answer == True:
192                         self.playlistIOInternal.clear()
193                         for x in self.playlist.list:
194                                 self.playlistIOInternal.addService(ServiceReference(x[0]))
195                         if not self.isAudioCD:
196                                 self.playlistIOInternal.save(resolveFilename(SCOPE_CONFIG, "playlist.e2pls"))
197                         self.close()
198
199         def checkSkipShowHideLock(self):
200                 self.updatedSeekState()
201
202         def doEofInternal(self, playing):
203                 if playing:
204                         self.nextEntry()
205                 else:
206                         self.show()
207
208         def __onClose(self):
209                 self.session.nav.playService(self.oldService)
210
211         def __evUpdatedInfo(self):
212                 currPlay = self.session.nav.getCurrentService()
213                 currenttitle = currPlay.info().getInfo(iServiceInformation.sCurrentTitle)
214                 totaltitles = currPlay.info().getInfo(iServiceInformation.sTotalTitles)
215                 sTitle = currPlay.info().getInfoString(iServiceInformation.sTitle)
216                 print "[__evUpdatedInfo] title %d of %d (%s)" % (currenttitle, totaltitles, sTitle)
217                 self.readTitleInformation()
218
219         def delMPTimer(self):
220                 del self.rightKeyTimer
221                 del self.leftKeyTimer
222
223         def readTitleInformation(self):
224                 currPlay = self.session.nav.getCurrentService()
225                 if currPlay is not None:
226                         sTitle = currPlay.info().getInfoString(iServiceInformation.sTitle)
227                         sAlbum = currPlay.info().getInfoString(iServiceInformation.sAlbum)
228                         sGenre = currPlay.info().getInfoString(iServiceInformation.sGenre)
229                         sArtist = currPlay.info().getInfoString(iServiceInformation.sArtist)
230                         sYear = ""
231
232                         if sTitle == "":
233                                 if not self.isAudioCD:
234                                         sTitle = currPlay.info().getName().split('/')[-1]
235                                 else:
236                                         sTitle = self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()].getName()
237
238                         if self.AudioCD_albuminfo:
239                                 if sAlbum == "" and "title" in self.AudioCD_albuminfo:
240                                         sAlbum = self.AudioCD_albuminfo["title"]
241                                 if sGenre == "" and "genre" in self.AudioCD_albuminfo:
242                                         sGenre = self.AudioCD_albuminfo["genre"]
243                                 if sArtist == "" and "artist" in self.AudioCD_albuminfo:
244                                         sArtist = self.AudioCD_albuminfo["artist"]
245                                 if "year" in self.AudioCD_albuminfo:
246                                         sYear = self.AudioCD_albuminfo["year"]
247
248                         self.updateMusicInformation( sArtist, sTitle, sAlbum, sYear, sGenre, clear = True )
249                 else:
250                         self.updateMusicInformation()
251
252         def updateMusicInformation(self, artist = "", title = "", album = "", year = "", genre = "", clear = False):
253                 self.updateSingleMusicInformation("artist", artist, clear)
254                 self.updateSingleMusicInformation("title", title, clear)
255                 self.updateSingleMusicInformation("album", album, clear)
256                 self.updateSingleMusicInformation("year", year, clear)
257                 self.updateSingleMusicInformation("genre", genre, clear)
258
259         def updateSingleMusicInformation(self, name, info, clear):
260                 if info != "" or clear:
261                         if self[name].getText() != info:
262                                 self[name].setText(info)
263
264         def updateCoverArtPixmap(self, path):
265                 while not path.endswith("/"):
266                         path = path[:-1]
267                 pngname = path + "folder.png"
268                 
269                 if not os_path.exists(pngname):
270                         pngname = self["coverArt"].default_pixmap
271                 if self.coverArtFileName != pngname:
272                         self.coverArtFileName = pngname
273                         self["coverArt"].instance.setPixmapFromFile(self.coverArtFileName)
274
275         def leftDown(self):
276                 self.lefttimer = True
277                 self.leftKeyTimer.start(1000)
278
279         def rightDown(self):
280                 self.righttimer = True
281                 self.rightKeyTimer.start(1000)
282
283         def leftUp(self):
284                 if self.lefttimer:
285                         self.leftKeyTimer.stop()
286                         self.lefttimer = False
287                         self[self.currList].pageUp()
288                         self.updateCurrentInfo()
289
290         def rightUp(self):
291                 if self.righttimer:
292                         self.rightKeyTimer.stop()
293                         self.righttimer = False
294                         self[self.currList].pageDown()
295                         self.updateCurrentInfo()
296
297         def leftTimerFire(self):
298                 self.leftKeyTimer.stop()
299                 self.lefttimer = False
300                 self.switchToFileList()
301
302         def rightTimerFire(self):
303                 self.rightKeyTimer.stop()
304                 self.righttimer = False
305                 self.switchToPlayList()
306
307         def switchToFileList(self):
308                 self.currList = "filelist"
309                 self.filelist.selectionEnabled(1)
310                 self.playlist.selectionEnabled(0)
311                 self.updateCurrentInfo()
312
313         def switchToPlayList(self):
314                 if len(self.playlist) != 0:
315                         self.currList = "playlist"
316                         self.filelist.selectionEnabled(0)
317                         self.playlist.selectionEnabled(1)
318                         self.updateCurrentInfo()
319
320         def up(self):
321                 self[self.currList].up()
322                 self.updateCurrentInfo()
323
324         def down(self):
325                 self[self.currList].down()
326                 self.updateCurrentInfo()
327
328         def showAfterSeek(self):
329                 self.show()
330
331         def showAfterCuesheetOperation(self):
332                 self.show()
333
334         def hideAfterResume(self):
335                 self.hide()
336
337         def getIdentifier(self, ref):
338                 if self.isAudioCD:
339                         return ref.getName()
340                 else:
341                         text = ref.getPath()
342                         return text.split('/')[-1]
343
344         # FIXME: maybe this code can be optimized 
345         def updateCurrentInfo(self):
346                 text = ""
347                 if self.currList == "filelist":
348                         idx = self.filelist.getSelectionIndex()
349                         r = self.filelist.list[idx]
350                         text = r[1][7]
351                         if r[0][1] == True:
352                                 if len(text) < 2:
353                                         text += " "
354                                 if text[:2] != "..":
355                                         text = "/" + text
356                         self.summaries.setText(text,1)
357
358                         idx += 1
359                         if idx < len(self.filelist.list):
360                                 r = self.filelist.list[idx]
361                                 text = r[1][7]
362                                 if r[0][1] == True:
363                                         text = "/" + text
364                                 self.summaries.setText(text,3)
365                         else:
366                                 self.summaries.setText(" ",3)
367
368                         idx += 1
369                         if idx < len(self.filelist.list):
370                                 r = self.filelist.list[idx]
371                                 text = r[1][7]
372                                 if r[0][1] == True:
373                                         text = "/" + text
374                                 self.summaries.setText(text,4)
375                         else:
376                                 self.summaries.setText(" ",4)
377
378                         text = ""
379                         if not self.filelist.canDescent():
380                                 r = self.filelist.getServiceRef()
381                                 if r is None:
382                                         return
383                                 text = r.getPath()
384                                 self["currenttext"].setText(os_path.basename(text))
385
386                 if self.currList == "playlist":
387                         t = self.playlist.getSelection()
388                         if t is None:
389                                 return
390                         #display current selected entry on LCD
391                         text = self.getIdentifier(t)
392                         self.summaries.setText(text,1)
393                         self["currenttext"].setText(text)
394                         idx = self.playlist.getSelectionIndex()
395                         idx += 1
396                         if idx < len(self.playlist):
397                                 currref = self.playlist.getServiceRefList()[idx]
398                                 text = self.getIdentifier(currref)
399                                 self.summaries.setText(text,3)
400                         else:
401                                 self.summaries.setText(" ",3)
402
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,4)
408                         else:
409                                 self.summaries.setText(" ",4)
410
411         def ok(self):
412                 if self.currList == "filelist":
413                         if self.filelist.canDescent():
414                                 self.filelist.descent()
415                                 self.updateCurrentInfo()
416                         else:
417                                 self.copyFile()
418
419                 if self.currList == "playlist":
420                         selection = self["playlist"].getSelection()
421                         self.changeEntry(self.playlist.getSelectionIndex())
422
423         def showMenu(self):
424                 menu = []
425                 if self.currList == "filelist":
426                         if self.filelist.canDescent():
427                                 menu.append((_("add directory to playlist"), "copydir"))
428                         else:
429                                 menu.append((_("add files to playlist"), "copyfiles"))
430                         menu.append((_("switch to playlist"), "playlist"))
431                 else:
432                         menu.append((_("switch to filelist"), "filelist"))
433
434                         menu.append((_("shuffle playlist"), "shuffle"))
435
436                         menu.append((_("delete"), "delete"))
437                         menu.append((_("clear playlist"), "clear"))
438                 menu.append((_("hide player"), "hide"));
439                 menu.append((_("save playlist"), "saveplaylist"));
440                 menu.append((_("load playlist"), "loadplaylist"));
441                 menu.append((_("delete saved playlist"), "deleteplaylist"));
442                 menu.append((_("repeat playlist"), "repeat"));
443                 self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu)
444
445         def menuCallback(self, choice):
446                 if choice is None:
447                         return
448
449                 if choice[1] == "copydir":
450                         self.copyDirectory(self.filelist.getSelection()[0])
451                 elif choice[1] == "copyfiles":
452                         self.stopEntry()
453                         self.playlist.clear()
454                         self.copyDirectory(os_path.dirname(self.filelist.getSelection()[0].getPath()) + "/", recursive = False)
455                         self.playServiceRefEntry(self.filelist.getServiceRef())
456                 elif choice[1] == "playlist":
457                         self.switchToPlayList()
458                 elif choice[1] == "filelist":
459                         self.switchToFileList()
460                 elif choice[1] == "delete":
461                         if self.playlist.getSelectionIndex() == self.playlist.getCurrentIndex():
462                                 self.stopEntry()
463                         self.deleteEntry()
464                 elif choice[1] == "clear":
465                         self.stopEntry()
466                         self.playlist.clear()
467                         self.switchToFileList()
468                 elif choice[1] == "hide":
469                         self.hide()
470                 elif choice[1] == "saveplaylist":
471                         self.save_playlist()
472                 elif choice[1] == "loadplaylist":
473                         self.load_playlist()
474                 elif choice[1] == "deleteplaylist":
475                         self.delete_saved_playlist()
476                 elif choice[1] == "shuffle":
477                         self.playlist.PlayListShuffle()
478                 elif choice[1] == "repeat":
479                         if self.repeat == True:
480                                 self.repeat = False
481                                 self["repeat"].setPixmapNum(0)
482                         else:
483                                 self.repeat = True
484                                 self["repeat"].setPixmapNum(1)
485
486         def showEventInformation(self):
487                 from Screens.EventView import EventViewSimple
488                 from ServiceReference import ServiceReference
489                 evt = self[self.currList].getCurrentEvent()
490                 if evt:
491                         self.session.open(EventViewSimple, evt, ServiceReference(self.getCurrent()))
492
493         # also works on filelist (?)
494         def getCurrent(self):
495                 return self["playlist"].getCurrent()
496
497         def deletePlaylistEntry(self):
498                 if self.currList == "playlist":
499                         if self.playlist.getSelectionIndex() == self.playlist.getCurrentIndex():
500                                 self.stopEntry()
501                         self.deleteEntry()
502
503         def skip_listbegin(self):
504                 if self.currList == "filelist":
505                         self.filelist.moveToIndex(0)
506                 else:
507                         self.playlist.moveToIndex(0)
508                 self.updateCurrentInfo()
509
510         def skip_listend(self):
511                 if self.currList == "filelist":
512                         idx = len(self.filelist.list)
513                         self.filelist.moveToIndex(idx - 1)
514                 else:
515                         self.playlist.moveToIndex(len(self.playlist)-1)
516                 self.updateCurrentInfo()
517
518         def save_playlist(self):
519                 self.session.openWithCallback(self.save_playlist2,InputBox, title=_("Please enter filename (empty = use current date)"),windowTitle = _("Save Playlist"))
520
521         def save_playlist2(self, name):
522                 if name is not None:
523                         name = name.strip()
524                         if name == "":
525                                 name = strftime("%y%m%d_%H%M%S")
526                         name += ".e2pls"
527                         self.playlistIOInternal.clear()
528                         for x in self.playlist.list:
529                                 self.playlistIOInternal.addService(ServiceReference(x[0]))
530                         self.playlistIOInternal.save(resolveFilename(SCOPE_PLAYLIST) + name)
531
532         def load_playlist(self):
533                 listpath = []
534                 playlistdir = resolveFilename(SCOPE_PLAYLIST)
535                 try:
536                         for i in os_listdir(playlistdir):
537                                 listpath.append((i,playlistdir + i))
538                 except IOError,e:
539                         print "Error while scanning subdirs ",e
540                 self.session.openWithCallback(self.PlaylistSelected, ChoiceBox, title=_("Please select a playlist..."), list = listpath)
541
542         def PlaylistSelected(self,path):
543                 if path is not None:
544                         self.clear_playlist()
545                         self.playlistIOInternal = PlaylistIOInternal()
546                         list = self.playlistIOInternal.open(path[1])
547                         if list:
548                                 for x in list:
549                                         self.playlist.addFile(x.ref)
550                                 self.playlist.updateList()
551
552         def delete_saved_playlist(self):
553                 listpath = []
554                 playlistdir = resolveFilename(SCOPE_PLAYLIST)
555                 try:
556                         for i in os_listdir(playlistdir):
557                                 listpath.append((i,playlistdir + i))
558                 except IOError,e:
559                         print "Error while scanning subdirs ",e
560                 self.session.openWithCallback(self.DeletePlaylistSelected, ChoiceBox, title=_("Please select a playlist to delete..."), list = listpath)
561
562         def DeletePlaylistSelected(self,path):
563                 if path is not None:
564                         self.delname = path[1]
565                         self.session.openWithCallback(self.deleteConfirmed, MessageBox, _("Do you really want to delete %s?") % (path[1]))
566
567         def deleteConfirmed(self, confirmed):
568                 if confirmed:
569                         os_remove(self.delname)
570
571         def clear_playlist(self):
572                 self.stopEntry()
573                 self.playlist.clear()
574                 self.switchToFileList()
575
576         def copyDirectory(self, directory, recursive = True):
577                 print "copyDirectory", directory
578                 filelist = FileList(directory, useServiceRef = True, isTop = True)
579
580                 for x in filelist.getFileList():
581                         if x[0][1] == True: #isDir
582                                 if recursive:
583                                         self.copyDirectory(x[0][0])
584                         else:
585                                 self.playlist.addFile(x[0][0])
586                 self.playlist.updateList()
587
588         def copyFile(self):
589                 if self.filelist.getServiceRef().type == 4098: # playlist
590                         ServiceRef = self.filelist.getServiceRef()
591                         extension = ServiceRef.getPath()[ServiceRef.getPath().rfind('.') + 1:]
592                         print "extension:", extension
593                         if self.playlistparsers.has_key(extension):
594                                 playlist = self.playlistparsers[extension]()
595                                 list = playlist.open(ServiceRef.getPath())
596                                 for x in list:
597                                         self.playlist.addFile(x.ref)
598                 else:
599                         self.playlist.addFile(self.filelist.getServiceRef())
600                         self.playlist.updateList()
601                         if len(self.playlist) == 1:
602                                 self.changeEntry(0)
603
604         def addPlaylistParser(self, parser, extension):
605                 self.playlistparsers[extension] = parser
606
607         def nextEntry(self):
608                 next = self.playlist.getCurrentIndex() + 1
609                 if next < len(self.playlist):
610                         self.changeEntry(next)
611                 elif ( len(self.playlist) > 0 ) and ( self.repeat == True ):
612                         self.stopEntry()
613                         self.changeEntry(0)
614
615         def nextMarkOrEntry(self):
616                 if not self.jumpPreviousNextMark(lambda x: x):
617                         next = self.playlist.getCurrentIndex() + 1
618                         if next < len(self.playlist):
619                                 self.changeEntry(next)
620                         else:
621                                 self.doSeek(-1)
622
623         def previousMarkOrEntry(self):
624                 if not self.jumpPreviousNextMark(lambda x: -x-5*90000, start=True):
625                         next = self.playlist.getCurrentIndex() - 1
626                         if next >= 0:
627                                 self.changeEntry(next)
628
629         def deleteEntry(self):
630                 self.playlist.deleteFile(self.playlist.getSelectionIndex())
631                 self.playlist.updateList()
632                 if len(self.playlist) == 0:
633                         self.switchToFileList()
634
635         def changeEntry(self, index):
636                 self.playlist.setCurrentPlaying(index)
637                 self.playEntry()
638
639         def playServiceRefEntry(self, serviceref):
640                 serviceRefList = self.playlist.getServiceRefList()
641                 for count in range(len(serviceRefList)):
642                         if serviceRefList[count] == serviceref:
643                                 self.changeEntry(count)
644                                 break
645                         
646         def xplayEntry(self):
647                 if self.currList == "playlist":
648                         self.playEntry()
649                 else:
650                         self.stopEntry()
651                         self.playlist.clear()
652                         sel = self.filelist.getSelection()
653                         if sel:
654                                 if sel[1]: # can descent
655                                         # add directory to playlist
656                                         self.copyDirectory(sel[0])
657                                 else:
658                                         # add files to playlist
659                                         self.copyDirectory(os_path.dirname(sel[0].getPath()) + "/", recursive = False)
660                         if len(self.playlist) > 0:
661                                 self.changeEntry(0)
662         
663         def playEntry(self):
664                 if len(self.playlist.getServiceRefList()):
665                         needsInfoUpdate = False
666                         currref = self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()]
667                         if self.session.nav.getCurrentlyPlayingServiceReference() is None or currref != self.session.nav.getCurrentlyPlayingServiceReference():
668                                 self.session.nav.playService(self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()])
669                                 info = eServiceCenter.getInstance().info(currref)
670                                 description = info and info.getInfoString(currref, iServiceInformation.sDescription) or ""
671                                 self["title"].setText(description)
672                                 # display just playing musik on LCD
673                                 idx = self.playlist.getCurrentIndex()
674                                 currref = self.playlist.getServiceRefList()[idx]
675                                 text = self.getIdentifier(currref)
676                                 text = ">"+text
677                                 ext = text[-3:].lower()
678
679                                 # FIXME: the information if the service contains video (and we should hide our window) should com from the service instead 
680                                 if ext not in ["mp3", "wav", "ogg"] and not self.isAudioCD:
681                                         self.hide()
682                                 else:
683                                         needsInfoUpdate = True
684                                 self.summaries.setText(text,1)
685
686                                 # get the next two entries
687                                 idx += 1
688                                 if idx < len(self.playlist):
689                                         currref = self.playlist.getServiceRefList()[idx]
690                                         text = self.getIdentifier(currref)
691                                         self.summaries.setText(text,3)
692                                 else:
693                                         self.summaries.setText(" ",3)
694
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,4)
700                                 else:
701                                         self.summaries.setText(" ",4)
702                         else:
703                                 idx = self.playlist.getCurrentIndex()
704                                 currref = self.playlist.getServiceRefList()[idx]
705                                 text = currref.getPath()
706                                 ext = text[-3:].lower()
707                                 if ext not in ["mp3", "wav", "ogg"] and not self.isAudioCD:
708                                         self.hide()
709                                 else:
710                                         needsInfoUpdate = True
711
712                         self.unPauseService()
713                         if needsInfoUpdate == True:
714                                 self.updateCoverArtPixmap(currref.getPath())
715                         else:
716                                 pngname = self["coverArt"].default_pixmap
717                                 self.coverArtFileName = pngname
718                                 self["coverArt"].instance.setPixmapFromFile(self.coverArtFileName)
719                         self.readTitleInformation()
720
721         def updatedSeekState(self):
722                 if self.seekstate == self.SEEK_STATE_PAUSE:
723                         self.playlist.pauseFile()
724                 elif self.seekstate == self.SEEK_STATE_PLAY:
725                         self.playlist.playFile()
726                 elif self.isStateForward(self.seekstate):
727                         self.playlist.forwardFile()
728                 elif self.isStateBackward(self.seekstate):
729                         self.playlist.rewindFile()
730
731         def pauseEntry(self):
732                 self.pauseService()
733                 self.show()
734
735         def stopEntry(self):
736                 self.playlist.stopFile()
737                 self.session.nav.playService(None)
738                 self.updateMusicInformation(clear=True)
739                 self.show()
740
741         def unPauseService(self):
742                 self.setSeekState(self.SEEK_STATE_PLAY)
743
744 class MediaPlayerLCDScreen(Screen):
745         skin = """
746         <screen position="0,0" size="132,64" title="LCD Text">
747                 <widget name="text1" position="4,0" size="132,35" font="Regular;16"/>
748                 <widget name="text3" position="4,36" size="132,14" font="Regular;10"/>
749                 <widget name="text4" position="4,49" size="132,14" font="Regular;10"/>
750         </screen>"""
751
752         def __init__(self, session, parent):
753                 Screen.__init__(self, session)
754                 self["text1"] = Label("Mediaplayer")
755                 self["text3"] = Label("")
756                 self["text4"] = Label("")
757
758         def setText(self, text, line):
759                 print "lcd set text:", text, line
760                 if len(text) > 10:
761                         if text[-4:] == ".mp3":
762                                 text = text[:-4]
763                 textleer = "    "
764                 text = text + textleer*10
765                 if line == 1:
766                         self["text1"].setText(text)
767                 elif line == 3:
768                         self["text3"].setText(text)
769                 elif line == 4:
770                         self["text4"].setText(text)
771
772 def main(session, **kwargs):
773         session.open(MediaPlayer)
774
775 def menu(menuid, **kwargs):
776         if menuid == "mainmenu":
777                 return [(_("Media player"), main, "media_player", 45)]
778         return []
779
780 def filescan_open(list, session, **kwargs):
781         from enigma import eServiceReference
782
783         mp = session.open(MediaPlayer)
784
785         mp.switchToPlayList()
786         for file in list:
787                 ref = eServiceReference(4097, 0, file.path)
788                 mp.playlist.addFile(ref)
789
790         # TODO: rather play first than last file?
791         mp.playServiceRefEntry(ref)
792         mp.playlist.updateList()
793
794 def audioCD_open(list, session, **kwargs):
795         from enigma import eServiceReference
796
797         mp = session.open(MediaPlayer)
798
799         mp.playlist.clear()
800         mp.isAudioCD = True
801
802         for file in list:
803                 ref = eServiceReference(4097, 0, file.path)
804                 mp.playlist.addFile(ref)
805         from Plugins.Extensions.CDInfo.plugin import Query
806         cdinfo = Query(mp)
807         cdinfo.scan()
808
809         mp.changeEntry(0)
810         mp.switchToPlayList()
811
812 def filescan(**kwargs):
813         from Components.Scanner import Scanner, ScanPath
814         mediatypes = [
815                 Scanner(mimetypes = ["video/mpeg"],
816                         paths_to_scan =
817                                 [
818                                         ScanPath(path = "", with_subdirs = False),
819                                 ],
820                         name = "Movie",
821                         description = "View Movies...",
822                         openfnc = filescan_open,
823                 ),
824                 Scanner(mimetypes = ["audio/mpeg", "audio/x-wav", "application/ogg"],
825                         paths_to_scan =
826                                 [
827                                         ScanPath(path = "", with_subdirs = False),
828                                 ],
829                         name = "Music",
830                         description = "Play Music...",
831                         openfnc = filescan_open,
832                 )]
833         try:
834                 from Plugins.Extensions.CDInfo.plugin import Query
835                 mediatypes.insert(0,Scanner(mimetypes = ["audio/x-cda", "audio/x-wav"],
836                         paths_to_scan =
837                                 [
838                                         ScanPath(path = "", with_subdirs = False),
839                                 ],
840                         name = "Audio-CD",
841                         description = "Play Audio-CD...",
842                         openfnc = audioCD_open,
843                 ))
844                 return mediatypes
845         except ImportError:
846                 return mediatypes
847
848 from Plugins.Plugin import PluginDescriptor
849 def Plugins(**kwargs):
850         return [
851                 PluginDescriptor(name = "MediaPlayer", description = "Play back media files", where = PluginDescriptor.WHERE_MENU, fnc = menu),
852                 PluginDescriptor(name = "MediaPlayer", where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)
853         ]