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