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