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