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