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.Pixmap import Pixmap
8 from Components.Label import Label
9 from Components.FileList import FileEntryComponent, FileList
10 from Components.MediaPlayer import PlayList, PlaylistEntryComponent
11 from Plugins.Plugin import PluginDescriptor
12 from Tools.Directories import resolveFilename, SCOPE_MEDIA, SCOPE_CONFIG, SCOPE_SKIN_IMAGE
13 from Components.ServicePosition import ServicePositionGauge
14 from Screens.ChoiceBox import ChoiceBox
15 from Components.ServiceEventTracker import ServiceEventTracker
16 from Components.Playlist import PlaylistIOInternal, PlaylistIOM3U, PlaylistIOPLS
17 from Screens.InfoBarGenerics import InfoBarSeek
18 from ServiceReference import ServiceReference
19 from Screens.ChoiceBox import ChoiceBox
23 class MediaPlayer(Screen, InfoBarSeek):
26 def __init__(self, session, args = None):
27 Screen.__init__(self, session)
28 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
29 self.session.nav.stopService()
31 self.playlistparsers = {}
32 self.addPlaylistParser(PlaylistIOM3U, "m3u")
33 self.addPlaylistParser(PlaylistIOPLS, "pls")
34 self.addPlaylistParser(PlaylistIOInternal, "e2pls")
36 # 'None' is magic to start at the list of mountpoints
37 self.filelist = FileList(None, 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 r = self.filelist.getServiceRef()
278 if self.currList == "playlist":
279 t = self.playlist.getSelection()
284 self["currenttext"].setText(os.path.basename(text))
287 if self.currList == "filelist":
288 if self.filelist.canDescent():
289 self.filelist.descent()
290 self.updateCurrentInfo()
293 self.playlist.clear()
294 self.copyDirectory(os.path.dirname(self.filelist.getSelection()[0].getPath()) + "/", recursive = False)
295 self.playServiceRefEntry(self.filelist.getServiceRef())
297 if self.currList == "playlist":
298 selection = self["playlist"].getSelection()
299 self.changeEntry(self.playlist.getSelectionIndex())
301 def keyNumberGlobal(self, number):
302 if number == 5: # enable seeking
303 if self.seek_target is None:
304 (len, pos) = self["PositionGauge"].get()
306 if self.isSeekable() and len != 0:
307 self.seek_target = pos
309 self.seekAbsolute(self.seek_target)
310 self.seek_target = None
311 elif number == 2: # abort
312 self.seek_target = None
313 elif (number == 4 or number == 6) and self.seek_target is not None:
314 (len, pos) = self["PositionGauge"].get()
317 self.seek_target -= len / 10
319 self.seek_target += len / 10
321 if self.seek_target > len * 9 / 10:
322 self.seek_target = len * 9 / 10
324 if self.seek_target < 0:
327 print "seek target is now", self.seek_target
331 def updateSeek(self):
332 if self.seek_target is None:
333 self["PositionGauge"].seek_pointer = False
335 self["PositionGauge"].seek_pointer = True
336 self["PositionGauge"].seek_pointer_position = self.seek_target
341 if self.currList == "filelist":
342 menu.append((_("switch to playlist"), "playlist"))
343 if self.filelist.canDescent():
344 menu.append((_("add directory to playlist"), "copydir"))
346 menu.append((_("add file to playlist"), "copy"))
348 menu.append((_("switch to filelist"), "filelist"))
349 menu.append((_("delete"), "delete"))
350 menu.append((_("clear playlist"), "clear"))
351 menu.append((_("hide player"), "hide"));
352 self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu)
354 def menuCallback(self, choice):
358 if choice[1] == "copydir":
359 self.copyDirectory(self.filelist.getSelection()[0])
360 elif choice[1] == "copy":
362 elif choice[1] == "playlist":
363 self.switchToPlayList()
364 elif choice[1] == "filelist":
365 self.switchToFileList()
366 elif choice[1] == "delete":
367 if self.playlist.getSelectionIndex() == self.playlist.getCurrentIndex():
370 elif choice[1] == "clear":
372 self.playlist.clear()
373 self.switchToFileList()
374 elif choice[1] == "hide":
377 def copyDirectory(self, directory, recursive = True):
378 print "copyDirectory", directory
379 filelist = FileList(directory, useServiceRef = True, isTop = True)
381 for x in filelist.getFileList():
382 if x[0][1] == True: #isDir
384 self.copyDirectory(x[0][0])
386 self.playlist.addFile(x[0][0])
387 self.playlist.updateList()
393 if self.filelist.getServiceRef().type == 4098: # playlist
395 list.append((_("Add files to playlist"), (self.ADDPLAYLIST, self.filelist.getServiceRef())))
396 list.append((_("Replace current playlist"), (self.REPLACEPLAYLIST, self.filelist.getServiceRef())))
397 self.session.openWithCallback(self.playlistCallback, ChoiceBox, title=_("You selected a playlist"), list = list)
399 self.playlist.addFile(self.filelist.getServiceRef())
400 self.playlist.updateList()
401 if len(self.playlist) == 1:
404 def addPlaylistParser(self, parser, extension):
405 self.playlistparsers[extension] = parser
407 def playlistCallback(self, answer):
408 if answer is not None:
409 extension = answer[1][1].getPath()[answer[1][1].getPath().rfind('.') + 1:]
410 print "extension:", extension
411 if self.playlistparsers.has_key(extension):
412 playlist = self.playlistparsers[extension]()
413 if answer[1][0] == self.REPLACEPLAYLIST:
415 self.playlist.clear()
416 self.switchToFileList()
417 if answer[1][0] == self.REPLACEPLAYLIST or answer[1][0] == self.ADDPLAYLIST:
418 list = playlist.open(answer[1][1].getPath())
420 self.playlist.addFile(x.ref)
424 next = self.playlist.getCurrentIndex() + 1
425 if next < len(self.playlist):
426 self.changeEntry(next)
428 def previousEntry(self):
429 next = self.playlist.getCurrentIndex() - 1
431 self.changeEntry(next)
433 def deleteEntry(self):
434 self.playlist.deleteFile(self.playlist.getSelectionIndex())
435 self.playlist.updateList()
436 if len(self.playlist) == 0:
437 self.switchToFileList()
439 def changeEntry(self, index):
440 self.playlist.setCurrentPlaying(index)
443 def playServiceRefEntry(self, serviceref):
444 serviceRefList = self.playlist.getServiceRefList()
445 for count in range(len(serviceRefList)):
446 if serviceRefList[count] == serviceref:
447 self.changeEntry(count)
451 if len(self.playlist.getServiceRefList()):
452 currref = self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()]
453 if self.session.nav.getCurrentlyPlayingServiceReference() is None or currref != self.session.nav.getCurrentlyPlayingServiceReference():
454 self.session.nav.playService(self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()])
455 info = eServiceCenter.getInstance().info(currref)
456 description = info and info.getInfoString(currref, iServiceInformation.sDescription) or ""
457 self["title"].setText(description)
458 self.unPauseService()
460 def updatedSeekState(self):
461 if self.seekstate == self.SEEK_STATE_PAUSE:
462 self.playlist.pauseFile()
463 elif self.seekstate == self.SEEK_STATE_PLAY:
464 self.playlist.playFile()
465 elif self.seekstate in ( self.SEEK_STATE_FF_2X,
466 self.SEEK_STATE_FF_4X,
467 self.SEEK_STATE_FF_8X,
468 self.SEEK_STATE_FF_32X,
469 self.SEEK_STATE_FF_64X,
470 self.SEEK_STATE_FF_128X):
471 self.playlist.forwardFile()
472 elif self.seekstate in ( self.SEEK_STATE_BACK_16X,
473 self.SEEK_STATE_BACK_32X,
474 self.SEEK_STATE_BACK_64X,
475 self.SEEK_STATE_BACK_128X,):
476 self.playlist.rewindFile()
478 def pauseEntry(self):
482 self.playlist.stopFile()
483 self.session.nav.playService(None)
484 self.updateMusicInformation(clear=True)
486 def unPauseService(self):
487 self.setSeekState(self.SEEK_STATE_PLAY)