finally fix satfinder with new config
[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         ALLOW_SUSPEND = True
26
27         def __init__(self, session, args = None):
28                 Screen.__init__(self, session)
29                 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
30                 self.session.nav.stopService()
31
32                 self.playlistparsers = {}
33                 self.addPlaylistParser(PlaylistIOM3U, "m3u")
34                 self.addPlaylistParser(PlaylistIOPLS, "pls")
35                 self.addPlaylistParser(PlaylistIOInternal, "e2pls")
36
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
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                                 text = self.filelist.getServiceRef().getPath()
275                 if self.currList == "playlist":
276                         text = self.playlist.getSelection().getPath()
277
278                 self["currenttext"].setText(os.path.basename(text))
279
280         def ok(self):
281                 if self.currList == "filelist":
282                         if self.filelist.canDescent():
283                                 self.filelist.descent()
284                                 self.updateCurrentInfo()
285                         else:
286                                 self.playlist.clear()
287                                 self.copyDirectory(os.path.dirname(self.filelist.getSelection()[0].getPath()) + "/", recursive = False)
288                                 self.playServiceRefEntry(self.filelist.getServiceRef())
289                                 
290                 if self.currList == "playlist":
291                         selection = self["playlist"].getSelection()
292                         self.changeEntry(self.playlist.getSelectionIndex())
293
294         def keyNumberGlobal(self, number):
295                 if number == 5: # enable seeking
296                         if self.seek_target is None:
297                                 (len, pos) = self["PositionGauge"].get()
298                                 
299                                 if self.isSeekable() and len != 0:
300                                         self.seek_target = pos
301                         else:
302                                 self.seekAbsolute(self.seek_target)
303                                 self.seek_target = None
304                 elif number == 2: # abort
305                         self.seek_target = None
306                 elif (number == 4 or number == 6) and self.seek_target is not None:
307                         (len, pos) = self["PositionGauge"].get()
308                         
309                         if number == 4:
310                                 self.seek_target -= len / 10
311                         else:
312                                 self.seek_target += len / 10
313                         
314                         if self.seek_target > len * 9 / 10:
315                                 self.seek_target = len * 9 / 10
316                         
317                         if self.seek_target < 0:
318                                 self.seek_target = 0
319
320                 print "seek target is now", self.seek_target
321                 
322                 self.updateSeek()
323         
324         def updateSeek(self):
325                 if self.seek_target is None:
326                         self["PositionGauge"].seek_pointer = False
327                 else:
328                         self["PositionGauge"].seek_pointer = True
329                         self["PositionGauge"].seek_pointer_position = self.seek_target
330
331
332         def showMenu(self):
333                 menu = []
334                 if self.currList == "filelist":
335                         menu.append((_("switch to playlist"), "playlist"))
336                         if self.filelist.canDescent():
337                                 menu.append((_("add directory to playlist"), "copydir"))
338                         else:
339                                 menu.append((_("add file to playlist"), "copy"))
340                 else:
341                         menu.append((_("switch to filelist"), "filelist"))
342                         menu.append((_("delete"), "delete"))
343                         menu.append((_("clear playlist"), "clear"))
344                 menu.append((_("hide player"), "hide"));
345                 self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu)
346
347         def menuCallback(self, choice):
348                 if choice is None:
349                         return
350
351                 if choice[1] == "copydir":
352                         self.copyDirectory(self.filelist.getSelection()[0])
353                 elif choice[1] == "copy":
354                         self.copyFile()
355                 elif choice[1] == "playlist":
356                         self.switchToPlayList()
357                 elif choice[1] == "filelist":
358                         self.switchToFileList()
359                 elif choice[1] == "delete":
360                         if self.playlist.getSelectionIndex() == self.playlist.getCurrentIndex():
361                                 self.stopEntry()
362                         self.deleteEntry()
363                 elif choice[1] == "clear":
364                         self.stopEntry()
365                         self.playlist.clear()
366                         self.switchToFileList()
367                 elif choice[1] == "hide":
368                         self.hide()
369
370         def copyDirectory(self, directory, recursive = True):
371                 print "copyDirectory", directory
372                 filelist = FileList(directory, useServiceRef = True, isTop = True)
373
374                 for x in filelist.getFileList():
375                         if x[0][1] == True: #isDir
376                                 if recursive:
377                                         self.copyDirectory(x[0][0])
378                         else:
379                                 self.playlist.addFile(x[0][0])
380                 self.playlist.updateList()
381
382         ADDPLAYLIST = 0
383         REPLACEPLAYLIST = 1
384
385         def copyFile(self):
386                 if self.filelist.getServiceRef().type == 4098: # playlist
387                         list = []
388                         list.append((_("Add files to playlist"), (self.ADDPLAYLIST, self.filelist.getServiceRef())))
389                         list.append((_("Replace current playlist"), (self.REPLACEPLAYLIST, self.filelist.getServiceRef())))
390                         self.session.openWithCallback(self.playlistCallback, ChoiceBox, title=_("You selected a playlist"), list = list)
391                 else:
392                         self.playlist.addFile(self.filelist.getServiceRef())
393                         self.playlist.updateList()
394                         if len(self.playlist) == 1:
395                                 self.changeEntry(0)
396
397         def addPlaylistParser(self, parser, extension):
398                 self.playlistparsers[extension] = parser
399
400         def playlistCallback(self, answer):
401                 if answer is not None:
402                         extension = answer[1][1].getPath()[answer[1][1].getPath().rfind('.') + 1:]
403                         print "extension:", extension
404                         if self.playlistparsers.has_key(extension):
405                                 playlist = self.playlistparsers[extension]()
406                                 if answer[1][0] == self.REPLACEPLAYLIST:
407                                         self.stopEntry()
408                                         self.playlist.clear()
409                                         self.switchToFileList()
410                                 if answer[1][0] == self.REPLACEPLAYLIST or answer[1][0] == self.ADDPLAYLIST:
411                                         list = playlist.open(answer[1][1].getPath())
412                                         for x in list:
413                                                 self.playlist.addFile(x.ref)
414
415
416         def nextEntry(self):
417                 next = self.playlist.getCurrentIndex() + 1
418                 if next < len(self.playlist):
419                         self.changeEntry(next)
420
421         def previousEntry(self):
422                 next = self.playlist.getCurrentIndex() - 1
423                 if next >= 0:
424                         self.changeEntry(next)
425
426         def deleteEntry(self):
427                 self.playlist.deleteFile(self.playlist.getSelectionIndex())
428                 self.playlist.updateList()
429                 if len(self.playlist) == 0:
430                         self.switchToFileList()
431
432         def changeEntry(self, index):
433                 self.playlist.setCurrentPlaying(index)
434                 self.playEntry()
435
436         def playServiceRefEntry(self, serviceref):
437                 serviceRefList = self.playlist.getServiceRefList()
438                 for count in range(len(serviceRefList)):
439                         if serviceRefList[count] == serviceref:
440                                 self.changeEntry(count)
441                                 break
442
443         def playEntry(self):
444                 if len(self.playlist.getServiceRefList()):
445                         currref = self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()]
446                         if self.session.nav.getCurrentlyPlayingServiceReference() is None or currref != self.session.nav.getCurrentlyPlayingServiceReference():
447                                 self.session.nav.playService(self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()])
448                                 info = eServiceCenter.getInstance().info(currref)
449                                 description = info and info.getInfoString(currref, iServiceInformation.sDescription) or ""
450                                 self["title"].setText(description)
451                         self.unPauseService()
452
453         def updatedSeekState(self):
454                 if self.seekstate == self.SEEK_STATE_PAUSE:
455                         self.playlist.pauseFile()
456                 elif self.seekstate == self.SEEK_STATE_PLAY:
457                         self.playlist.playFile()
458                 elif self.seekstate in ( self.SEEK_STATE_FF_2X,
459                                                                  self.SEEK_STATE_FF_4X,
460                                                                  self.SEEK_STATE_FF_8X,
461                                                                  self.SEEK_STATE_FF_32X,
462                                                                  self.SEEK_STATE_FF_64X,
463                                                                  self.SEEK_STATE_FF_128X):
464                         self.playlist.forwardFile()
465                 elif self.seekstate in ( self.SEEK_STATE_BACK_16X,
466                                                                  self.SEEK_STATE_BACK_32X,
467                                                                  self.SEEK_STATE_BACK_64X,
468                                                                  self.SEEK_STATE_BACK_128X,):
469                         self.playlist.rewindFile()
470
471         def pauseEntry(self):
472                 self.pauseService()
473
474         def stopEntry(self):
475                 self.playlist.stopFile()
476                 self.session.nav.playService(None)
477                 self.updateMusicInformation(clear=True)
478
479         def unPauseService(self):
480                 self.setSeekState(self.SEEK_STATE_PLAY)