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