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