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