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