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