Support turbo2.
[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                         isDir = x[0][1]
682                         data = x[0][0]
683                         if isDir == True:
684                                 if recursive:
685                                         if data != directory:
686                                                 self.copyDirectory(x[0][0])
687                         elif data and data.type in (2, 3, 4097):
688                                 self.playlist.addFile(data)
689                 self.playlist.updateList()
690
691         def deleteFile(self):
692                 if self.currList == "filelist":
693                         self.service = self.filelist.getServiceRef()
694                 else:
695                         self.service = self.playlist.getSelection()
696                 if self.service is None:
697                         return
698                 if self.service.type != 4098 and self.session.nav.getCurrentlyPlayingServiceReference() is not None:
699                         if self.service == self.session.nav.getCurrentlyPlayingServiceReference():
700                                 self.stopEntry()
701
702                 serviceHandler = eServiceCenter.getInstance()
703                 offline = serviceHandler.offlineOperations(self.service)
704                 info = serviceHandler.info(self.service)
705                 name = info and info.getName(self.service)
706                 result = False
707                 if offline is not None:
708                         # simulate first
709                         if not offline.deleteFromDisk(1):
710                                 result = True
711                 if result == True:
712                         self.session.openWithCallback(self.deleteConfirmed_offline, MessageBox, _("Do you really want to delete %s?") % (name))
713                 else:
714                         self.session.openWithCallback(self.close, MessageBox, _("You cannot delete this!"), MessageBox.TYPE_ERROR)      
715
716         def deleteConfirmed_offline(self, confirmed):
717                 if confirmed:
718                         serviceHandler = eServiceCenter.getInstance()
719                         offline = serviceHandler.offlineOperations(self.service)
720                         result = False
721                         if offline is not None:
722                                 # really delete!
723                                 if not offline.deleteFromDisk(0):
724                                         result = True
725                         if result == False:
726                                 self.session.open(MessageBox, _("Delete failed!"), MessageBox.TYPE_ERROR)
727                         else:
728                                 self.removeListEntry()
729
730         def removeListEntry(self):
731                 currdir = self.filelist.getCurrentDirectory()
732                 self.filelist.changeDir(currdir)
733                 deleteend = False
734                 while not deleteend:
735                         index = 0
736                         deleteend = True
737                         if len(self.playlist) > 0:
738                                 for x in self.playlist.list:
739                                         if self.service == x[0]:
740                                                 self.playlist.deleteFile(index)
741                                                 deleteend = False
742                                                 break
743                                         index += 1
744                 self.playlist.updateList()
745                 if self.currList == "playlist":
746                         if len(self.playlist) == 0:
747                                 self.switchToFileList()
748
749         def copyFile(self):
750                 if self.filelist.getServiceRef().type == 4098: # playlist
751                         ServiceRef = self.filelist.getServiceRef()
752                         extension = ServiceRef.getPath()[ServiceRef.getPath().rfind('.') + 1:]
753                         if self.playlistparsers.has_key(extension):
754                                 playlist = self.playlistparsers[extension]()
755                                 list = playlist.open(ServiceRef.getPath())
756                                 for x in list:
757                                         self.playlist.addFile(x.ref)
758                         self.playlist.updateList()
759                 else:
760                         self.playlist.addFile(self.filelist.getServiceRef())
761                         self.playlist.updateList()
762                         if len(self.playlist) == 1:
763                                 self.changeEntry(0)
764
765         def addPlaylistParser(self, parser, extension):
766                 self.playlistparsers[extension] = parser
767
768         def nextEntry(self):
769                 next = self.playlist.getCurrentIndex() + 1
770                 if next < len(self.playlist):
771                         self.changeEntry(next)
772                 elif ( len(self.playlist) > 0 ) and ( config.mediaplayer.repeat.getValue() == True ):
773                         self.stopEntry()
774                         self.changeEntry(0)
775
776         def nextMarkOrEntry(self):
777                 if not self.jumpPreviousNextMark(lambda x: x):
778                         next = self.playlist.getCurrentIndex() + 1
779                         if next < len(self.playlist):
780                                 self.changeEntry(next)
781                         else:
782                                 self.doSeek(-1)
783
784         def previousMarkOrEntry(self):
785                 if not self.jumpPreviousNextMark(lambda x: -x-5*90000, start=True):
786                         next = self.playlist.getCurrentIndex() - 1
787                         if next >= 0:
788                                 self.changeEntry(next)
789
790         def deleteEntry(self):
791                 self.playlist.deleteFile(self.playlist.getSelectionIndex())
792                 self.playlist.updateList()
793                 if len(self.playlist) == 0:
794                         self.switchToFileList()
795
796         def changeEntry(self, index):
797                 self.playlist.setCurrentPlaying(index)
798                 self.playEntry()
799
800         def playServiceRefEntry(self, serviceref):
801                 serviceRefList = self.playlist.getServiceRefList()
802                 for count in range(len(serviceRefList)):
803                         if serviceRefList[count] == serviceref:
804                                 self.changeEntry(count)
805                                 break
806                         
807         def xplayEntry(self):
808                 if self.currList == "playlist":
809                         self.playEntry()
810                 else:
811                         self.stopEntry()
812                         self.playlist.clear()
813                         self.isAudioCD = False
814                         sel = self.filelist.getSelection()
815                         if sel:
816                                 if sel[1]: # can descent
817                                         # add directory to playlist
818                                         self.copyDirectory(sel[0])
819                                 else:
820                                         # add files to playlist
821                                         self.copyDirectory(os_path.dirname(sel[0].getPath()) + "/", recursive = False)
822                         if len(self.playlist) > 0:
823                                 self.changeEntry(0)
824         
825         def playEntry(self):
826                 if len(self.playlist.getServiceRefList()):
827                         audio_extensions = (".mp2", ".mp3", ".wav", ".ogg", ".flac", ".m4a", ".dts")
828                         needsInfoUpdate = False
829                         currref = self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()]
830                         if self.session.nav.getCurrentlyPlayingServiceReference() is None or currref != self.session.nav.getCurrentlyPlayingServiceReference():
831                                 self.session.nav.playService(self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()])
832                                 info = eServiceCenter.getInstance().info(currref)
833                                 description = info and info.getInfoString(currref, iServiceInformation.sDescription) or ""
834                                 self["title"].setText(description)
835                                 # display just playing musik on LCD
836                                 idx = self.playlist.getCurrentIndex()
837                                 currref = self.playlist.getServiceRefList()[idx]
838                                 text = self.getIdentifier(currref)
839                                 text = ">"+text
840                                 try:
841                                         import os
842                                         nameext = os.path.splitext(text)
843                                         ext = nameext[1]
844                                 except: ext = text[-4:].lower()
845
846                                 # FIXME: the information if the service contains video (and we should hide our window) should com from the service instead 
847                                 if ext not in audio_extensions and not self.isAudioCD:
848                                         self.hide()
849                                 else:
850                                         needsInfoUpdate = True
851                                 self.summaries.setText(text,1)
852
853                                 # get the next two entries
854                                 idx += 1
855                                 if idx < len(self.playlist):
856                                         currref = self.playlist.getServiceRefList()[idx]
857                                         text = self.getIdentifier(currref)
858                                         self.summaries.setText(text,3)
859                                 else:
860                                         self.summaries.setText(" ",3)
861
862                                 idx += 1
863                                 if idx < len(self.playlist):
864                                         currref = self.playlist.getServiceRefList()[idx]
865                                         text = self.getIdentifier(currref)
866                                         self.summaries.setText(text,4)
867                                 else:
868                                         self.summaries.setText(" ",4)
869                         else:
870                                 idx = self.playlist.getCurrentIndex()
871                                 currref = self.playlist.getServiceRefList()[idx]
872                                 text = currref.getPath()
873                                 ext = text[-4:].lower()
874                                 if ext not in audio_extensions and not self.isAudioCD:
875                                         self.hide()
876                                 else:
877                                         needsInfoUpdate = True
878
879                         self.unPauseService()
880                         if needsInfoUpdate == True:
881                                 path = self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()].getPath()
882                                 self["coverArt"].updateCoverArt(path)
883                         else:
884                                 self["coverArt"].showDefaultCover()
885                         self.readTitleInformation()
886
887         def updatedSeekState(self):
888                 if self.seekstate == self.SEEK_STATE_PAUSE:
889                         self.playlist.pauseFile()
890                 elif self.seekstate == self.SEEK_STATE_PLAY:
891                         self.playlist.playFile()
892                 elif self.isStateForward(self.seekstate):
893                         self.playlist.forwardFile()
894                 elif self.isStateBackward(self.seekstate):
895                         self.playlist.rewindFile()
896
897         def pauseEntry(self):
898                 self.pauseService()
899                 if self.seekstate == self.SEEK_STATE_PAUSE:
900                         self.show()
901                 else:
902                         self.hide()
903
904         def stopEntry(self):
905                 self.playlist.stopFile()
906                 self.session.nav.playService(None)
907                 self.updateMusicInformation(clear=True)
908                 self.show()
909
910         def unPauseService(self):
911                 self.setSeekState(self.SEEK_STATE_PLAY)
912
913         def subtitleSelection(self):
914                 from Screens.AudioSelection import SubtitleSelection
915                 self.session.open(SubtitleSelection, self)
916
917         def hotplugCB(self, dev, media_state):
918                 if dev == harddiskmanager.getCD():
919                         if media_state == "1":
920                                 from Components.Scanner import scanDevice
921                                 devpath = harddiskmanager.getAutofsMountpoint(harddiskmanager.getCD())
922                                 self.cdAudioTrackFiles = []
923                                 res = scanDevice(devpath)
924                                 list = [ (r.description, r, res[r], self.session) for r in res ]
925                                 if list:
926                                         (desc, scanner, files, session) = list[0]
927                                         for file in files:
928                                                 if file.mimetype == "audio/x-cda":
929                                                         self.cdAudioTrackFiles.append(file.path)
930                         else:
931                                 self.cdAudioTrackFiles = []
932                                 if self.isAudioCD:
933                                         self.clear_playlist()
934
935 class MediaPlayerLCDScreen(Screen):
936         skin = (
937         """<screen name="MediaPlayerLCDScreen" position="0,0" size="132,64" id="1">
938                 <widget name="text1" position="4,0" size="132,35" font="Regular;16"/>
939                 <widget name="text3" position="4,36" size="132,14" font="Regular;10"/>
940                 <widget name="text4" position="4,49" size="132,14" font="Regular;10"/>
941         </screen>""",
942         """<screen name="MediaPlayerLCDScreen" position="0,0" size="96,64" id="2">
943                 <widget name="text1" position="0,0" size="96,35" font="Regular;14"/>
944                 <widget name="text3" position="0,36" size="96,14" font="Regular;10"/>
945                 <widget name="text4" position="0,49" size="96,14" font="Regular;10"/>
946         </screen>""")
947
948         def __init__(self, session, parent):
949                 Screen.__init__(self, session)
950                 self["text1"] = Label("Mediaplayer")
951                 self["text3"] = Label("")
952                 self["text4"] = Label("")
953
954         def setText(self, text, line):
955                 if len(text) > 10:
956                         if text[-4:] == ".mp3":
957                                 text = text[:-4]
958                 textleer = "    "
959                 text = text + textleer*10
960                 if line == 1:
961                         self["text1"].setText(text)
962                 elif line == 3:
963                         self["text3"].setText(text)
964                 elif line == 4:
965                         self["text4"].setText(text)
966
967 def main(session, **kwargs):
968         session.open(MediaPlayer)
969
970 def menu(menuid, **kwargs):
971         if menuid == "mainmenu":
972                 return [(_("Media player"), main, "media_player", 45)]
973         return []
974
975 def filescan_open(list, session, **kwargs):
976         from enigma import eServiceReference
977
978         mp = session.open(MediaPlayer)
979         mp.playlist.clear()
980         mp.savePlaylistOnExit = False
981
982         for file in list:
983                 if file.mimetype == "video/MP2T":
984                         stype = 1
985                 else:
986                         stype = 4097
987                 ref = eServiceReference(stype, 0, file.path)
988                 mp.playlist.addFile(ref)
989
990         mp.changeEntry(0)
991         mp.switchToPlayList()
992
993 def audioCD_open(list, session, **kwargs):
994         from enigma import eServiceReference
995
996         mp = session.open(MediaPlayer)
997         mp.cdAudioTrackFiles = []
998         for file in list:
999                 mp.cdAudioTrackFiles.append(file.path)
1000         mp.playAudioCD()
1001
1002 def filescan(**kwargs):
1003         from Components.Scanner import Scanner, ScanPath
1004         mediatypes = [
1005                 Scanner(mimetypes = ["video/mpeg", "video/MP2T", "video/x-msvideo"],
1006                         paths_to_scan =
1007                                 [
1008                                         ScanPath(path = "", with_subdirs = False),
1009                                 ],
1010                         name = "Movie",
1011                         description = _("View Movies..."),
1012                         openfnc = filescan_open,
1013                 ),
1014                 Scanner(mimetypes = ["video/x-vcd"],
1015                         paths_to_scan =
1016                                 [
1017                                         ScanPath(path = "mpegav", with_subdirs = False),
1018                                         ScanPath(path = "MPEGAV", with_subdirs = False),
1019                                 ],
1020                         name = "Video CD",
1021                         description = _("View Video CD..."),
1022                         openfnc = filescan_open,
1023                 ),
1024                 Scanner(mimetypes = ["audio/mpeg", "audio/x-wav", "application/ogg", "audio/x-flac"],
1025                         paths_to_scan =
1026                                 [
1027                                         ScanPath(path = "", with_subdirs = False),
1028                                 ],
1029                         name = "Music",
1030                         description = _("Play Music..."),
1031                         openfnc = filescan_open,
1032                 )]
1033         try:
1034                 from Plugins.Extensions.CDInfo.plugin import Query
1035                 mediatypes.append(
1036                 Scanner(mimetypes = ["audio/x-cda"],
1037                         paths_to_scan =
1038                                 [
1039                                         ScanPath(path = "", with_subdirs = False),
1040                                 ],
1041                         name = "Audio-CD",
1042                         description = _("Play Audio-CD..."),
1043                         openfnc = audioCD_open,
1044                 ))
1045                 return mediatypes
1046         except ImportError:
1047                 return mediatypes
1048
1049 from Plugins.Plugin import PluginDescriptor
1050 def Plugins(**kwargs):
1051         return [
1052                 PluginDescriptor(name = "MediaPlayer", description = "Play back media files", where = PluginDescriptor.WHERE_MENU, needsRestart = False, fnc = menu),
1053                 PluginDescriptor(name = "MediaPlayer", where = PluginDescriptor.WHERE_FILESCAN, needsRestart = False, fnc = filescan)
1054         ]