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