1 from enigma import eTimer, iPlayableService, eServiceCenter, iServiceInformation, eSize
2 from Screens.Screen import Screen
3 from Screens.MessageBox import MessageBox
4 from Components.ActionMap import NumberActionMap
5 from Components.Label import Label
6 from Components.Input import Input
7 from Components.GUIComponent import *
8 from Components.Pixmap import Pixmap
9 from Components.Label import Label
10 from Components.FileList import FileEntryComponent, FileList
11 from Components.MediaPlayer import PlayList, PlaylistEntryComponent
12 from Plugins.Plugin import PluginDescriptor
13 from Tools.Directories import resolveFilename, SCOPE_MEDIA, SCOPE_CONFIG, SCOPE_SKIN_IMAGE
14 from Components.ServicePosition import ServicePositionGauge
15 from Screens.ChoiceBox import ChoiceBox
16 from Components.ServiceEventTracker import ServiceEventTracker
17 from Components.Playlist import PlaylistIOInternal, PlaylistIOM3U, PlaylistIOPLS
18 from Screens.InfoBarGenerics import InfoBarSeek
19 from ServiceReference import ServiceReference
20 from Screens.ChoiceBox import ChoiceBox
24 class MediaPlayer(Screen, InfoBarSeek):
27 def __init__(self, session, args = None):
28 Screen.__init__(self, session)
29 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
30 self.session.nav.stopService()
32 self.playlistparsers = {}
33 self.addPlaylistParser(PlaylistIOM3U, "m3u")
34 self.addPlaylistParser(PlaylistIOPLS, "pls")
35 self.addPlaylistParser(PlaylistIOInternal, "e2pls")
37 self.filelist = FileList(resolveFilename(SCOPE_MEDIA), matchingPattern = "(?i)^.*\.(mp3|ogg|ts|wav|wave|m3u|pls|e2pls|mpg|vob)", useServiceRef = True)
38 self["filelist"] = self.filelist
40 self.playlist = PlayList()
41 self["playlist"] = self.playlist
43 self["PositionGauge"] = ServicePositionGauge(self.session.nav)
45 self["currenttext"] = Label("")
47 self["artisttext"] = Label(_("Artist:"))
48 self["artist"] = Label("")
49 self["titletext"] = Label(_("Title:"))
50 self["title"] = Label("")
51 self["albumtext"] = Label(_("Album:"))
52 self["album"] = Label("")
53 self["yeartext"] = Label(_("Year:"))
54 self["year"] = Label("")
55 self["genretext"] = Label(_("Genre:"))
56 self["genre"] = Label("")
57 self["coverArt"] = Pixmap()
59 self.seek_target = None
61 #self["text"] = Input("1234", maxSize=True, type=Input.NUMBER)
63 class MoviePlayerActionMap(NumberActionMap):
64 def __init__(self, player, contexts = [ ], actions = { }, prio=0):
65 NumberActionMap.__init__(self, contexts, actions, prio)
68 def action(self, contexts, action):
70 return NumberActionMap.action(self, contexts, action)
72 self["actions"] = MoviePlayerActionMap(self, ["OkCancelActions", "DirectionActions", "NumberActions", "MediaPlayerSeekActions"],
77 "right": self.rightDown,
78 "rightRepeated": self.doNothing,
79 "rightUp": self.rightUp,
80 "left": self.leftDown,
81 "leftRepeated": self.doNothing,
82 "leftUp": self.leftUp,
85 "upRepeated": self.up,
87 "downRepeated": self.down,
89 "play": self.playEntry,
90 "pause": self.pauseEntry,
91 "stop": self.stopEntry,
93 "previous": self.previousEntry,
94 "next": self.nextEntry,
96 "menu": self.showMenu,
98 "1": self.keyNumberGlobal,
99 "2": self.keyNumberGlobal,
100 "3": self.keyNumberGlobal,
101 "4": self.keyNumberGlobal,
102 "5": self.keyNumberGlobal,
103 "6": self.keyNumberGlobal,
104 "7": self.keyNumberGlobal,
105 "8": self.keyNumberGlobal,
106 "9": self.keyNumberGlobal,
107 "0": self.keyNumberGlobal
110 InfoBarSeek.__init__(self)
112 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
114 #iPlayableService.evStart: self.__serviceStarted,
115 #iPlayableService.evSeekableStatusChanged: InfoBarSeek.__seekableStatusChanged,
117 iPlayableService.evEOF: self.__evEOF,
118 # iPlayableService.evSOF: self.__evSOF,
121 self.onClose.append(self.delMPTimer)
122 self.onClose.append(self.__onClose)
124 self.righttimer = False
125 self.rightKeyTimer = eTimer()
126 self.rightKeyTimer.timeout.get().append(self.rightTimerFire)
128 self.lefttimer = False
129 self.leftKeyTimer = eTimer()
130 self.leftKeyTimer.timeout.get().append(self.leftTimerFire)
132 self.infoTimer = eTimer()
133 self.infoTimer.timeout.get().append(self.infoTimerFire)
134 self.infoTimer.start(500)
136 self.currList = "filelist"
138 self.coverArtFileName = ""
140 self.playlistIOInternal = PlaylistIOInternal()
141 list = self.playlistIOInternal.open(resolveFilename(SCOPE_CONFIG, "playlist.e2pls"))
144 self.playlist.addFile(x.ref)
145 self.playlist.updateList()
151 self.playlistIOInternal.clear()
152 for x in self.playlist.list:
153 self.playlistIOInternal.addService(ServiceReference(x[0]))
154 self.playlistIOInternal.save(resolveFilename(SCOPE_CONFIG, "playlist.e2pls"))
157 def checkSkipShowHideLock(self):
158 self.updatedSeekState()
164 self.session.nav.playService(self.oldService)
166 def delMPTimer(self):
167 del self.rightKeyTimer
168 del self.leftKeyTimer
171 def infoTimerFire(self):
172 currPlay = self.session.nav.getCurrentService()
173 if currPlay is not None:
174 self.updateMusicInformation( artist = currPlay.info().getInfoString(iServiceInformation.sArtist),
175 title = currPlay.info().getInfoString(iServiceInformation.sTitle),
176 album = currPlay.info().getInfoString(iServiceInformation.sAlbum),
177 genre = currPlay.info().getInfoString(iServiceInformation.sGenre),
179 self.updateCoverArtPixmap( currPlay.info().getName() )
181 self.updateMusicInformation()
182 self.updateCoverArtPixmap( "" )
184 def updateMusicInformation(self, artist = "", title = "", album = "", year = "", genre = "", clear = False):
185 self.updateSingleMusicInformation("artist", artist, clear)
186 self.updateSingleMusicInformation("title", title, clear)
187 self.updateSingleMusicInformation("album", album, clear)
188 self.updateSingleMusicInformation("year", year, clear)
189 self.updateSingleMusicInformation("genre", genre, clear)
191 def updateSingleMusicInformation(self, name, info, clear):
192 if info != "" or clear:
193 if self[name].getText() != info:
194 self[name].setText(info)
196 def updateCoverArtPixmap(self, currentServiceName):
197 filename = currentServiceName
198 # The "getName" usually adds something like "MP3 File:" infront of filename
199 # Get rid of this...by finding the first "/"
200 filename = filename[filename.find("/"):]
201 path = os.path.dirname(filename)
202 pngname = path + "/" + "folder.png"
203 if not os.path.exists(pngname):
204 pngname = resolveFilename(SCOPE_SKIN_IMAGE, "no_coverArt.png")
205 if self.coverArtFileName != pngname:
206 self.coverArtFileName = pngname
207 self["coverArt"].instance.setPixmapFromFile(self.coverArtFileName)
209 def fwdTimerFire(self):
210 self.fwdKeyTimer.stop()
211 self.fwdtimer = False
214 def rwdTimerFire(self):
215 self.rwdKeyTimer.stop()
216 self.rwdtimer = False
220 self.lefttimer = True
221 self.leftKeyTimer.start(1000)
224 self.righttimer = True
225 self.rightKeyTimer.start(1000)
229 self.leftKeyTimer.stop()
230 self.lefttimer = False
231 self[self.currList].pageUp()
235 self.rightKeyTimer.stop()
236 self.righttimer = False
237 self[self.currList].pageDown()
239 def leftTimerFire(self):
240 self.leftKeyTimer.stop()
241 self.lefttimer = False
242 self.switchToFileList()
244 def rightTimerFire(self):
245 self.rightKeyTimer.stop()
246 self.righttimer = False
247 self.switchToPlayList()
249 def switchToFileList(self):
250 self.currList = "filelist"
251 self.filelist.selectionEnabled(1)
252 self.playlist.selectionEnabled(0)
253 self.updateCurrentInfo()
255 def switchToPlayList(self):
256 if len(self.playlist) != 0:
257 self.currList = "playlist"
258 self.filelist.selectionEnabled(0)
259 self.playlist.selectionEnabled(1)
260 self.updateCurrentInfo()
263 self[self.currList].up()
264 self.updateCurrentInfo()
267 self[self.currList].down()
268 self.updateCurrentInfo()
270 def updateCurrentInfo(self):
272 if self.currList == "filelist":
273 if not self.filelist.canDescent():
274 text = self.filelist.getServiceRef().getPath()
275 if self.currList == "playlist":
276 text = self.playlist.getSelection().getPath()
278 self["currenttext"].setText(os.path.basename(text))
281 if self.currList == "filelist":
282 if self.filelist.canDescent():
283 self.filelist.descent()
284 self.updateCurrentInfo()
287 self.playlist.clear()
288 self.copyDirectory(os.path.dirname(self.filelist.getSelection()[0].getPath()) + "/", recursive = False)
289 self.playServiceRefEntry(self.filelist.getServiceRef())
291 if self.currList == "playlist":
292 selection = self["playlist"].getSelection()
293 self.changeEntry(self.playlist.getSelectionIndex())
295 def keyNumberGlobal(self, number):
296 if number == 5: # enable seeking
297 if self.seek_target is None:
298 (len, pos) = self["PositionGauge"].get()
300 if self.isSeekable() and len != 0:
301 self.seek_target = pos
303 self.seekAbsolute(self.seek_target)
304 self.seek_target = None
305 elif number == 2: # abort
306 self.seek_target = None
307 elif (number == 4 or number == 6) and self.seek_target is not None:
308 (len, pos) = self["PositionGauge"].get()
311 self.seek_target -= len / 10
313 self.seek_target += len / 10
315 if self.seek_target > len * 9 / 10:
316 self.seek_target = len * 9 / 10
318 if self.seek_target < 0:
321 print "seek target is now", self.seek_target
325 def updateSeek(self):
326 if self.seek_target is None:
327 self["PositionGauge"].seek_pointer = False
329 self["PositionGauge"].seek_pointer = True
330 self["PositionGauge"].seek_pointer_position = self.seek_target
335 if self.currList == "filelist":
336 menu.append((_("switch to playlist"), "playlist"))
337 if self.filelist.canDescent():
338 menu.append((_("add directory to playlist"), "copydir"))
340 menu.append((_("add file to playlist"), "copy"))
342 menu.append((_("switch to filelist"), "filelist"))
343 menu.append((_("delete"), "delete"))
344 menu.append((_("clear playlist"), "clear"))
345 menu.append((_("hide player"), "hide"));
346 self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu)
348 def menuCallback(self, choice):
352 if choice[1] == "copydir":
353 self.copyDirectory(self.filelist.getSelection()[0])
354 elif choice[1] == "copy":
356 elif choice[1] == "playlist":
357 self.switchToPlayList()
358 elif choice[1] == "filelist":
359 self.switchToFileList()
360 elif choice[1] == "delete":
361 if self.playlist.getSelectionIndex() == self.playlist.getCurrentIndex():
364 elif choice[1] == "clear":
366 self.playlist.clear()
367 self.switchToFileList()
368 elif choice[1] == "hide":
371 def copyDirectory(self, directory, recursive = True):
372 print "copyDirectory", directory
373 filelist = FileList(directory, useServiceRef = True, isTop = True)
375 for x in filelist.getFileList():
376 if x[0][1] == True: #isDir
378 self.copyDirectory(x[0][0])
380 self.playlist.addFile(x[0][0])
381 self.playlist.updateList()
387 if self.filelist.getServiceRef().type == 4098: # playlist
389 list.append((_("Add files to playlist"), (self.ADDPLAYLIST, self.filelist.getServiceRef())))
390 list.append((_("Replace current playlist"), (self.REPLACEPLAYLIST, self.filelist.getServiceRef())))
391 self.session.openWithCallback(self.playlistCallback, ChoiceBox, title=_("You selected a playlist"), list = list)
393 self.playlist.addFile(self.filelist.getServiceRef())
394 self.playlist.updateList()
395 if len(self.playlist) == 1:
398 def addPlaylistParser(self, parser, extension):
399 self.playlistparsers[extension] = parser
401 def playlistCallback(self, answer):
402 if answer is not None:
403 extension = answer[1][1].getPath()[answer[1][1].getPath().rfind('.') + 1:]
404 print "extension:", extension
405 if self.playlistparsers.has_key(extension):
406 playlist = self.playlistparsers[extension]()
407 if answer[1][0] == self.REPLACEPLAYLIST:
409 self.playlist.clear()
410 self.switchToFileList()
411 if answer[1][0] == self.REPLACEPLAYLIST or answer[1][0] == self.ADDPLAYLIST:
412 list = playlist.open(answer[1][1].getPath())
414 self.playlist.addFile(x.ref)
418 next = self.playlist.getCurrentIndex() + 1
419 if next < len(self.playlist):
420 self.changeEntry(next)
422 def previousEntry(self):
423 next = self.playlist.getCurrentIndex() - 1
425 self.changeEntry(next)
427 def deleteEntry(self):
428 self.playlist.deleteFile(self.playlist.getSelectionIndex())
429 self.playlist.updateList()
430 if len(self.playlist) == 0:
431 self.switchToFileList()
433 def changeEntry(self, index):
434 self.playlist.setCurrentPlaying(index)
437 def playServiceRefEntry(self, serviceref):
438 serviceRefList = self.playlist.getServiceRefList()
439 for count in range(len(serviceRefList)):
440 if serviceRefList[count] == serviceref:
441 self.changeEntry(count)
445 if len(self.playlist.getServiceRefList()):
446 currref = self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()]
447 if self.session.nav.getCurrentlyPlayingServiceReference() is None or currref != self.session.nav.getCurrentlyPlayingServiceReference():
448 self.session.nav.playService(self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()])
449 info = eServiceCenter.getInstance().info(currref)
450 description = info and info.getInfoString(currref, iServiceInformation.sDescription) or ""
451 self["title"].setText(description)
452 self.unPauseService()
454 def updatedSeekState(self):
455 if self.seekstate == self.SEEK_STATE_PAUSE:
456 self.playlist.pauseFile()
457 elif self.seekstate == self.SEEK_STATE_PLAY:
458 self.playlist.playFile()
459 elif self.seekstate in ( self.SEEK_STATE_FF_2X,
460 self.SEEK_STATE_FF_4X,
461 self.SEEK_STATE_FF_8X,
462 self.SEEK_STATE_FF_32X,
463 self.SEEK_STATE_FF_64X,
464 self.SEEK_STATE_FF_128X):
465 self.playlist.forwardFile()
466 elif self.seekstate in ( self.SEEK_STATE_BACK_16X,
467 self.SEEK_STATE_BACK_32X,
468 self.SEEK_STATE_BACK_64X,
469 self.SEEK_STATE_BACK_128X,):
470 self.playlist.rewindFile()
472 def pauseEntry(self):
476 self.playlist.stopFile()
477 self.session.nav.playService(None)
478 self.updateMusicInformation(clear=True)
480 def unPauseService(self):
481 self.setSeekState(self.SEEK_STATE_PLAY)