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