add some skin fixes/extensions made by Nemesis (thanks for this)
[enigma2.git] / lib / python / Screens / MediaPlayer.py
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
21
22 import os
23
24 class MediaPlayer(Screen, InfoBarSeek):
25         def __init__(self, session, args = None):
26                 Screen.__init__(self, session)
27                 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
28                 self.session.nav.stopService()
29
30                 self.playlistparsers = {}
31                 self.addPlaylistParser(PlaylistIOM3U, "m3u")
32                 self.addPlaylistParser(PlaylistIOPLS, "pls")
33                 self.addPlaylistParser(PlaylistIOInternal, "e2pls")
34
35                 self.filelist = FileList(resolveFilename(SCOPE_MEDIA), matchingPattern = "^.*\.(mp3|ogg|ts|wav|wave|m3u|pls|e2pls|mpg|vob)", useServiceRef = True)              
36                 self["filelist"] = self.filelist
37
38                 self.playlist = PlayList()
39                 self["playlist"] = self.playlist
40                 
41                 self["PositionGauge"] = ServicePositionGauge(self.session.nav)
42                 
43                 self["currenttext"] = Label("")
44                 
45                 self["artisttext"] = Label(_("Artist:"))
46                 self["artist"] = Label("")
47                 self["titletext"] = Label(_("Title:"))
48                 self["title"] = Label("")
49                 self["albumtext"] = Label(_("Album:"))
50                 self["album"] = Label("")
51                 self["yeartext"] = Label(_("Year:"))
52                 self["year"] = Label("")
53                 self["genretext"] = Label(_("Genre:"))
54                 self["genre"] = Label("")
55                 self["coverArt"] = Pixmap()
56                 
57                 #self["text"] = Input("1234", maxSize=True, type=Input.NUMBER)
58
59                 class MoviePlayerActionMap(NumberActionMap):
60                         def __init__(self, player, contexts = [ ], actions = { }, prio=0):
61                                 NumberActionMap.__init__(self, contexts, actions, prio)
62                                 self.player = player
63
64                         def action(self, contexts, action):
65                                 self.player.show()
66                                 return NumberActionMap.action(self, contexts, action)
67
68                 self["actions"] = MoviePlayerActionMap(self, ["OkCancelActions", "DirectionActions", "NumberActions", "MediaPlayerSeekActions"],
69                 {
70                         "ok": self.ok,
71                         "cancel": self.exit,
72                         
73                         "right": self.rightDown,
74                         "rightRepeated": self.doNothing,
75                         "rightUp": self.rightUp,
76                         "left": self.leftDown,
77                         "leftRepeated": self.doNothing,
78                         "leftUp": self.leftUp,
79                         
80                         "up": self.up,
81                         "upRepeated": self.up,
82                         "down": self.down,
83                         "downRepeated": self.down,
84                         
85                         "play": self.playEntry,
86                         "pause": self.pauseEntry,
87                         "stop": self.stopEntry,
88                         
89                         "previous": self.previousEntry,
90                         "next": self.nextEntry,
91                         
92                         "menu": self.showMenu,
93                         
94             "1": self.keyNumberGlobal,
95             "2": self.keyNumberGlobal,
96             "3": self.keyNumberGlobal,
97             "4": self.keyNumberGlobal,
98             "5": self.keyNumberGlobal,
99             "6": self.keyNumberGlobal,
100             "7": self.keyNumberGlobal,
101             "8": self.keyNumberGlobal,
102             "9": self.keyNumberGlobal,
103             "0": self.keyNumberGlobal
104         }, -2)
105
106                 InfoBarSeek.__init__(self)
107
108                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
109                         {
110                                 #iPlayableService.evStart: self.__serviceStarted,
111                                 #iPlayableService.evSeekableStatusChanged: InfoBarSeek.__seekableStatusChanged,
112
113                                 iPlayableService.evEOF: self.__evEOF,
114 #                               iPlayableService.evSOF: self.__evSOF,
115                         })
116
117                 self.onClose.append(self.delMPTimer)
118                 self.onClose.append(self.__onClose)
119                 
120                 self.righttimer = False
121                 self.rightKeyTimer = eTimer()
122                 self.rightKeyTimer.timeout.get().append(self.rightTimerFire)
123
124                 self.lefttimer = False
125                 self.leftKeyTimer = eTimer()
126                 self.leftKeyTimer.timeout.get().append(self.leftTimerFire)
127                 
128                 self.infoTimer = eTimer()
129                 self.infoTimer.timeout.get().append(self.infoTimerFire)
130                 self.infoTimer.start(500)
131                 
132                 self.currList = "filelist"
133
134                 self.coverArtFileName = ""
135                 
136                 self.playlistIOInternal = PlaylistIOInternal()
137                 list = self.playlistIOInternal.open(resolveFilename(SCOPE_CONFIG, "playlist.e2pls"))
138                 if list:
139                         for x in list:
140                                 self.playlist.addFile(x.ref)
141                         self.playlist.updateList()              
142                 
143         def doNothing(self):
144                 pass
145         
146         def exit(self):
147                 self.playlistIOInternal.clear()
148                 for x in self.playlist.list:
149                         self.playlistIOInternal.addService(ServiceReference(x[0]))
150                 self.playlistIOInternal.save(resolveFilename(SCOPE_CONFIG, "playlist.e2pls"))
151                 self.close()
152         
153         def checkSkipShowHideLock(self):
154                 self.updatedSeekState()
155         
156         def __evEOF(self):
157                 self.nextEntry()
158         
159         def __onClose(self):
160                 self.session.nav.playService(self.oldService)
161         
162         def delMPTimer(self):
163                 del self.rightKeyTimer
164                 del self.leftKeyTimer
165                 del self.infoTimer
166                 
167         def infoTimerFire(self):
168                 currPlay = self.session.nav.getCurrentService()
169                 if currPlay is not None:
170                         self.updateMusicInformation( artist = currPlay.info().getInfoString(iServiceInformation.sArtist),
171                                                                                  title = currPlay.info().getInfoString(iServiceInformation.sTitle),
172                                                                                  album = currPlay.info().getInfoString(iServiceInformation.sAlbum),
173                                                                                  genre = currPlay.info().getInfoString(iServiceInformation.sGenre),
174                                                                                  clear = True)
175                         self.updateCoverArtPixmap( currPlay.info().getName() )
176                 else:
177                         self.updateMusicInformation()
178                         self.updateCoverArtPixmap( "" )
179         
180         def updateMusicInformation(self, artist = "", title = "", album = "", year = "", genre = "", clear = False):
181                 self.updateSingleMusicInformation("artist", artist, clear)
182                 self.updateSingleMusicInformation("title", title, clear)
183                 self.updateSingleMusicInformation("album", album, clear)
184                 self.updateSingleMusicInformation("year", year, clear)
185                 self.updateSingleMusicInformation("genre", genre, clear)
186
187         def updateSingleMusicInformation(self, name, info, clear):
188                 if info != "" or clear:
189                         if self[name].getText() != info:
190                                 self[name].setText(info)
191
192         def updateCoverArtPixmap(self, currentServiceName):
193                 filename = currentServiceName
194                 # The "getName" usually adds something like "MP3 File:" infront of filename
195                 # Get rid of this...by finding the first "/"
196                 filename = filename[filename.find("/"):]
197                 path = os.path.dirname(filename)
198                 pngname = path + "/" + "folder.png"
199                 if not os.path.exists(pngname):
200                         pngname = resolveFilename(SCOPE_SKIN_IMAGE, "no_coverArt.png")
201                 if self.coverArtFileName != pngname:
202                         self.coverArtFileName = pngname
203                         self["coverArt"].instance.setPixmapFromFile(self.coverArtFileName)
204
205         def fwdTimerFire(self):
206                 self.fwdKeyTimer.stop()
207                 self.fwdtimer = False
208                 self.nextEntry()
209         
210         def rwdTimerFire(self):
211                 self.rwdKeyTimer.stop()
212                 self.rwdtimer = False
213                 self.previousEntry()
214         
215         def leftDown(self):
216                 self.lefttimer = True
217                 self.leftKeyTimer.start(1000)
218
219         def rightDown(self):
220                 self.righttimer = True
221                 self.rightKeyTimer.start(1000)
222                 
223         def leftUp(self):
224                 if self.lefttimer:
225                         self.leftKeyTimer.stop()
226                         self.lefttimer = False
227                         self[self.currList].pageUp()
228     
229         def rightUp(self):
230                 if self.righttimer:
231                         self.rightKeyTimer.stop()
232                         self.righttimer = False
233                         self[self.currList].pageDown()
234                         
235         def leftTimerFire(self):
236                 self.leftKeyTimer.stop()
237                 self.lefttimer = False
238                 self.switchToFileList()
239         
240         def rightTimerFire(self):
241                 self.rightKeyTimer.stop()
242                 self.righttimer = False
243                 self.switchToPlayList()
244                                 
245         def switchToFileList(self):
246                 self.currList = "filelist"
247                 self.filelist.selectionEnabled(1)
248                 self.playlist.selectionEnabled(0)
249                 self.updateCurrentInfo()
250                 
251         def switchToPlayList(self):
252                 if len(self.playlist) != 0:
253                         self.currList = "playlist"
254                         self.filelist.selectionEnabled(0)
255                         self.playlist.selectionEnabled(1)
256                         self.updateCurrentInfo()
257                 
258         def up(self):
259                 self[self.currList].up()
260                 self.updateCurrentInfo()
261
262         def down(self):
263                 self[self.currList].down()
264                 self.updateCurrentInfo()
265
266         def updateCurrentInfo(self):
267                 text = ""
268                 if self.currList == "filelist":
269                         if not self.filelist.canDescent():
270                                 text = self.filelist.getServiceRef().getPath()
271                 if self.currList == "playlist":
272                         text = self.playlist.getSelection().getPath()
273                 
274                 self["currenttext"].setText(os.path.basename(text))
275     
276         def ok(self):
277                 if self.currList == "filelist":
278                         if self.filelist.canDescent():
279                                 self.filelist.descent()
280                                 self.updateCurrentInfo()
281                         else:
282                                 self.copyFile()
283                 if self.currList == "playlist":
284                         selection = self["playlist"].getSelection()
285                         self.changeEntry(self.playlist.getSelectionIndex())
286
287         def keyNumberGlobal(self, number):
288                 pass
289         
290         def showMenu(self):
291                 menu = []
292                 if self.currList == "filelist":
293                         menu.append((_("switch to playlist"), "playlist"))
294                         if self.filelist.canDescent():
295                                 menu.append((_("add directory to playlist"), "copydir"))
296                         else:
297                                 menu.append((_("add file to playlist"), "copy"))
298                 else:
299                         menu.append((_("switch to filelist"), "filelist"))
300                         menu.append((_("delete"), "delete"))
301                         menu.append((_("clear playlist"), "clear"))
302                 menu.append((_("hide player"), "hide"));
303                 self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu)
304                 
305         def menuCallback(self, choice):
306                 if choice is None:
307                         return
308                 
309                 if choice[1] == "copydir":
310                         self.copyDirectory(self.filelist.getSelection()[0])
311                 elif choice[1] == "copy":
312                         self.copyFile()
313                 elif choice[1] == "playlist":
314                         self.switchToPlayList()
315                 elif choice[1] == "filelist":
316                         self.switchToFileList()
317                 elif choice[1] == "delete":
318                         if self.playlist.getSelectionIndex() == self.playlist.getCurrentIndex():
319                                 self.stopEntry()
320                         self.deleteEntry()
321                 elif choice[1] == "clear":
322                         self.stopEntry()
323                         self.playlist.clear()
324                         self.switchToFileList()
325                 elif choice[1] == "hide":
326                         self.hide()
327
328         def copyDirectory(self, directory):
329                 filelist = FileList(directory, useServiceRef = True, isTop = True)
330                 
331                 for x in filelist.getFileList():
332                         if x[0][1] == True: #isDir
333                                 self.copyDirectory(x[0][0])
334                         else:
335                                 self.playlist.addFile(x[0][0])
336                 self.playlist.updateList()
337         
338         ADDPLAYLIST = 0
339         REPLACEPLAYLIST = 1
340         
341         def copyFile(self):
342                 if self.filelist.getServiceRef().type == 4098: # playlist
343                         list = []
344                         list.append((_("Add files to playlist"), (self.ADDPLAYLIST, self.filelist.getServiceRef())))
345                         list.append((_("Replace current playlist"), (self.REPLACEPLAYLIST, self.filelist.getServiceRef())))
346                         self.session.openWithCallback(self.playlistCallback, ChoiceBox, title=_("You selected a playlist"), list = list)
347                 else:
348                         self.playlist.addFile(self.filelist.getServiceRef())
349                         self.playlist.updateList()
350                         if len(self.playlist) == 1:
351                                 self.changeEntry(0)
352
353         def addPlaylistParser(self, parser, extension):
354                 self.playlistparsers[extension] = parser
355
356         def playlistCallback(self, answer):
357                 if answer is not None:
358                         extension = answer[1][1].getPath()[answer[1][1].getPath().rfind('.') + 1:]
359                         print "extension:", extension
360                         if self.playlistparsers.has_key(extension):
361                                 playlist = self.playlistparsers[extension]()
362                                 if answer[1][0] == self.REPLACEPLAYLIST:
363                                         self.stopEntry()
364                                         self.playlist.clear()
365                                         self.switchToFileList()
366                                 if answer[1][0] == self.REPLACEPLAYLIST or answer[1][0] == self.ADDPLAYLIST:
367                                         list = playlist.open(answer[1][1].getPath())
368                                         for x in list:
369                                                 self.playlist.addFile(x.ref)
370                                 
371
372         def nextEntry(self):
373                 next = self.playlist.getCurrentIndex() + 1
374                 if next < len(self.playlist):
375                         self.changeEntry(next)
376         
377         def previousEntry(self):
378                 next = self.playlist.getCurrentIndex() - 1
379                 if next >= 0:
380                         self.changeEntry(next)
381                         
382         def deleteEntry(self):
383                 self.playlist.deleteFile(self.playlist.getSelectionIndex())
384                 self.playlist.updateList()
385                 if len(self.playlist) == 0:
386                         self.switchToFileList()
387                 
388         def changeEntry(self, index):
389                 self.playlist.setCurrentPlaying(index)
390                 self.playEntry()
391         
392         def playEntry(self):
393                 if len(self.playlist.getServiceRefList()):
394                         currref = self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()]
395                         if self.session.nav.getCurrentlyPlayingServiceReference() is None or currref != self.session.nav.getCurrentlyPlayingServiceReference():
396                                 self.session.nav.playService(self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()])
397                                 info = eServiceCenter.getInstance().info(currref)
398                                 description = info and info.getInfoString(currref, iServiceInformation.sDescription) or ""
399                                 self["title"].setText(description)
400                         self.unPauseService()
401                                 
402         def updatedSeekState(self):
403                 if self.seekstate == self.SEEK_STATE_PAUSE:
404                         self.playlist.pauseFile()
405                 elif self.seekstate == self.SEEK_STATE_PLAY:
406                         self.playlist.playFile()
407                 elif self.seekstate in ( self.SEEK_STATE_FF_2X,
408                                                                  self.SEEK_STATE_FF_4X,
409                                                                  self.SEEK_STATE_FF_8X,
410                                                                  self.SEEK_STATE_FF_32X,
411                                                                  self.SEEK_STATE_FF_64X,
412                                                                  self.SEEK_STATE_FF_128X):
413                         self.playlist.forwardFile()
414                 elif self.seekstate in ( self.SEEK_STATE_BACK_16X,
415                                                                  self.SEEK_STATE_BACK_32X,
416                                                                  self.SEEK_STATE_BACK_64X,
417                                                                  self.SEEK_STATE_BACK_128X,):
418                         self.playlist.rewindFile()
419         
420         def pauseEntry(self):
421                 self.pauseService()
422                 
423         def stopEntry(self):
424                 self.playlist.stopFile()
425                 self.session.nav.playService(None)
426                 self.updateMusicInformation(clear=True)
427
428         def unPauseService(self):
429                 self.setSeekState(self.SEEK_STATE_PLAY)
430
431
432