whitespace cleanup
[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.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
20
21 import os
22
23 class MediaPlayer(Screen, InfoBarSeek):
24         ALLOW_SUSPEND = True
25
26         def __init__(self, session, args = None):
27                 Screen.__init__(self, session)
28                 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
29                 self.session.nav.stopService()
30
31                 self.playlistparsers = {}
32                 self.addPlaylistParser(PlaylistIOM3U, "m3u")
33                 self.addPlaylistParser(PlaylistIOPLS, "pls")
34                 self.addPlaylistParser(PlaylistIOInternal, "e2pls")
35
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
39
40                 self.playlist = PlayList()
41                 self["playlist"] = self.playlist
42
43                 self["PositionGauge"] = ServicePositionGauge(self.session.nav)
44                 
45                 self["currenttext"] = Label("")
46
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()
58                 
59                 self.seek_target = None
60                 
61                 #self["text"] = Input("1234", maxSize=True, type=Input.NUMBER)
62
63                 class MoviePlayerActionMap(NumberActionMap):
64                         def __init__(self, player, contexts = [ ], actions = { }, prio=0):
65                                 NumberActionMap.__init__(self, contexts, actions, prio)
66                                 self.player = player
67
68                         def action(self, contexts, action):
69                                 self.player.show()
70                                 return NumberActionMap.action(self, contexts, action)
71
72                 self["actions"] = MoviePlayerActionMap(self, ["OkCancelActions", "DirectionActions", "NumberActions", "MediaPlayerSeekActions"],
73                 {
74                         "ok": self.ok,
75                         "cancel": self.exit,
76
77                         "right": self.rightDown,
78                         "rightRepeated": self.doNothing,
79                         "rightUp": self.rightUp,
80                         "left": self.leftDown,
81                         "leftRepeated": self.doNothing,
82                         "leftUp": self.leftUp,
83
84                         "up": self.up,
85                         "upRepeated": self.up,
86                         "down": self.down,
87                         "downRepeated": self.down,
88
89                         "play": self.playEntry,
90                         "pause": self.pauseEntry,
91                         "stop": self.stopEntry,
92
93                         "previous": self.previousEntry,
94                         "next": self.nextEntry,
95
96                         "menu": self.showMenu,
97
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
108                 }, -2)
109
110                 InfoBarSeek.__init__(self)
111
112                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
113                         {
114                                 #iPlayableService.evStart: self.__serviceStarted,
115                                 #iPlayableService.evSeekableStatusChanged: InfoBarSeek.__seekableStatusChanged,
116
117                                 iPlayableService.evEOF: self.__evEOF,
118 #                               iPlayableService.evSOF: self.__evSOF,
119                         })
120
121                 self.onClose.append(self.delMPTimer)
122                 self.onClose.append(self.__onClose)
123
124                 self.righttimer = False
125                 self.rightKeyTimer = eTimer()
126                 self.rightKeyTimer.timeout.get().append(self.rightTimerFire)
127
128                 self.lefttimer = False
129                 self.leftKeyTimer = eTimer()
130                 self.leftKeyTimer.timeout.get().append(self.leftTimerFire)
131
132                 self.infoTimer = eTimer()
133                 self.infoTimer.timeout.get().append(self.infoTimerFire)
134                 self.infoTimer.start(500)
135
136                 self.currList = "filelist"
137
138                 self.coverArtFileName = ""
139
140                 self.playlistIOInternal = PlaylistIOInternal()
141                 list = self.playlistIOInternal.open(resolveFilename(SCOPE_CONFIG, "playlist.e2pls"))
142                 if list:
143                         for x in list:
144                                 self.playlist.addFile(x.ref)
145                         self.playlist.updateList()
146
147         def doNothing(self):
148                 pass
149
150         def exit(self):
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"))
155                 self.close()
156
157         def checkSkipShowHideLock(self):
158                 self.updatedSeekState()
159
160         def __evEOF(self):
161                 self.nextEntry()
162
163         def __onClose(self):
164                 self.session.nav.playService(self.oldService)
165
166         def delMPTimer(self):
167                 del self.rightKeyTimer
168                 del self.leftKeyTimer
169                 del self.infoTimer
170
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),
178                                                                                  clear = True)
179                         self.updateCoverArtPixmap( currPlay.info().getName() )
180                 else:
181                         self.updateMusicInformation()
182                         self.updateCoverArtPixmap( "" )
183
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)
190
191         def updateSingleMusicInformation(self, name, info, clear):
192                 if info != "" or clear:
193                         if self[name].getText() != info:
194                                 self[name].setText(info)
195
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)
208
209         def fwdTimerFire(self):
210                 self.fwdKeyTimer.stop()
211                 self.fwdtimer = False
212                 self.nextEntry()
213
214         def rwdTimerFire(self):
215                 self.rwdKeyTimer.stop()
216                 self.rwdtimer = False
217                 self.previousEntry()
218
219         def leftDown(self):
220                 self.lefttimer = True
221                 self.leftKeyTimer.start(1000)
222
223         def rightDown(self):
224                 self.righttimer = True
225                 self.rightKeyTimer.start(1000)
226
227         def leftUp(self):
228                 if self.lefttimer:
229                         self.leftKeyTimer.stop()
230                         self.lefttimer = False
231                         self[self.currList].pageUp()
232
233         def rightUp(self):
234                 if self.righttimer:
235                         self.rightKeyTimer.stop()
236                         self.righttimer = False
237                         self[self.currList].pageDown()
238
239         def leftTimerFire(self):
240                 self.leftKeyTimer.stop()
241                 self.lefttimer = False
242                 self.switchToFileList()
243
244         def rightTimerFire(self):
245                 self.rightKeyTimer.stop()
246                 self.righttimer = False
247                 self.switchToPlayList()
248
249         def switchToFileList(self):
250                 self.currList = "filelist"
251                 self.filelist.selectionEnabled(1)
252                 self.playlist.selectionEnabled(0)
253                 self.updateCurrentInfo()
254
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()
261
262         def up(self):
263                 self[self.currList].up()
264                 self.updateCurrentInfo()
265
266         def down(self):
267                 self[self.currList].down()
268                 self.updateCurrentInfo()
269
270         def updateCurrentInfo(self):
271                 text = ""
272                 if self.currList == "filelist":
273                         if not self.filelist.canDescent():
274                                 r = self.filelist.getServiceRef()
275                                 if r is None:
276                                         return
277                                 text = r.getPath()
278                 if self.currList == "playlist":
279                         t = self.playlist.getSelection()
280                         if t is None:
281                                 return
282                         text = t.getPath()
283
284                 self["currenttext"].setText(os.path.basename(text))
285
286         def ok(self):
287                 if self.currList == "filelist":
288                         if self.filelist.canDescent():
289                                 self.filelist.descent()
290                                 self.updateCurrentInfo()
291                         else:
292                                 self.stopEntry()
293                                 self.playlist.clear()
294                                 self.copyDirectory(os.path.dirname(self.filelist.getSelection()[0].getPath()) + "/", recursive = False)
295                                 self.playServiceRefEntry(self.filelist.getServiceRef())
296                                 
297                 if self.currList == "playlist":
298                         selection = self["playlist"].getSelection()
299                         self.changeEntry(self.playlist.getSelectionIndex())
300
301         def keyNumberGlobal(self, number):
302                 if number == 5: # enable seeking
303                         if self.seek_target is None:
304                                 (len, pos) = self["PositionGauge"].get()
305                                 
306                                 if self.isSeekable() and len != 0:
307                                         self.seek_target = pos
308                         else:
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()
315                         
316                         if number == 4:
317                                 self.seek_target -= len / 10
318                         else:
319                                 self.seek_target += len / 10
320                         
321                         if self.seek_target > len * 9 / 10:
322                                 self.seek_target = len * 9 / 10
323                         
324                         if self.seek_target < 0:
325                                 self.seek_target = 0
326
327                 print "seek target is now", self.seek_target
328                 
329                 self.updateSeek()
330         
331         def updateSeek(self):
332                 if self.seek_target is None:
333                         self["PositionGauge"].seek_pointer = False
334                 else:
335                         self["PositionGauge"].seek_pointer = True
336                         self["PositionGauge"].seek_pointer_position = self.seek_target
337
338
339         def showMenu(self):
340                 menu = []
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"))
345                         else:
346                                 menu.append((_("add file to playlist"), "copy"))
347                 else:
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)
353
354         def menuCallback(self, choice):
355                 if choice is None:
356                         return
357
358                 if choice[1] == "copydir":
359                         self.copyDirectory(self.filelist.getSelection()[0])
360                 elif choice[1] == "copy":
361                         self.copyFile()
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():
368                                 self.stopEntry()
369                         self.deleteEntry()
370                 elif choice[1] == "clear":
371                         self.stopEntry()
372                         self.playlist.clear()
373                         self.switchToFileList()
374                 elif choice[1] == "hide":
375                         self.hide()
376
377         def copyDirectory(self, directory, recursive = True):
378                 print "copyDirectory", directory
379                 filelist = FileList(directory, useServiceRef = True, isTop = True)
380
381                 for x in filelist.getFileList():
382                         if x[0][1] == True: #isDir
383                                 if recursive:
384                                         self.copyDirectory(x[0][0])
385                         else:
386                                 self.playlist.addFile(x[0][0])
387                 self.playlist.updateList()
388
389         ADDPLAYLIST = 0
390         REPLACEPLAYLIST = 1
391
392         def copyFile(self):
393                 if self.filelist.getServiceRef().type == 4098: # playlist
394                         list = []
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)
398                 else:
399                         self.playlist.addFile(self.filelist.getServiceRef())
400                         self.playlist.updateList()
401                         if len(self.playlist) == 1:
402                                 self.changeEntry(0)
403
404         def addPlaylistParser(self, parser, extension):
405                 self.playlistparsers[extension] = parser
406
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:
414                                         self.stopEntry()
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())
419                                         for x in list:
420                                                 self.playlist.addFile(x.ref)
421
422
423         def nextEntry(self):
424                 next = self.playlist.getCurrentIndex() + 1
425                 if next < len(self.playlist):
426                         self.changeEntry(next)
427
428         def previousEntry(self):
429                 next = self.playlist.getCurrentIndex() - 1
430                 if next >= 0:
431                         self.changeEntry(next)
432
433         def deleteEntry(self):
434                 self.playlist.deleteFile(self.playlist.getSelectionIndex())
435                 self.playlist.updateList()
436                 if len(self.playlist) == 0:
437                         self.switchToFileList()
438
439         def changeEntry(self, index):
440                 self.playlist.setCurrentPlaying(index)
441                 self.playEntry()
442
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)
448                                 break
449
450         def playEntry(self):
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()
459
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()
477
478         def pauseEntry(self):
479                 self.pauseService()
480
481         def stopEntry(self):
482                 self.playlist.stopFile()
483                 self.session.nav.playService(None)
484                 self.updateMusicInformation(clear=True)
485
486         def unPauseService(self):
487                 self.setSeekState(self.SEEK_STATE_PLAY)