Display actual song names for Audio CDs with CD-Text feature (requires libcdio)
[enigma2.git] / lib / python / Plugins / Extensions / MediaPlayer / plugin.py
1 from os import path as os_path, remove as os_remove, listdir as os_listdir, popen
2 from time import strftime
3 from enigma import iPlayableService, eTimer, eServiceCenter, iServiceInformation
4 from Screens.Screen import Screen
5 from Screens.MessageBox import MessageBox
6 from Screens.InputBox import InputBox
7 from Components.ActionMap import NumberActionMap, HelpableActionMap
8 from Components.Label import Label
9 from Components.Pixmap import Pixmap
10 from Components.Label import Label
11 from Components.FileList import FileList
12 from Components.MediaPlayer import PlayList
13 from Tools.Directories import resolveFilename, SCOPE_CONFIG, SCOPE_PLAYLIST, SCOPE_SKIN_IMAGE
14 from Components.ServicePosition import ServicePositionGauge
15 from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
16 from Components.Playlist import PlaylistIOInternal, PlaylistIOM3U, PlaylistIOPLS
17 from Screens.InfoBarGenerics import InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSupport, InfoBarNotifications
18 from ServiceReference import ServiceReference
19 from Screens.ChoiceBox import ChoiceBox
20 from Screens.HelpMenu import HelpableScreen
21 import random
22
23 class MyPlayList(PlayList):
24         def __init__(self):
25                 PlayList.__init__(self)
26
27         def PlayListShuffle(self):
28                 random.shuffle(self.list)
29                 self.l.setList(self.list)
30                 self.currPlaying = -1
31                 self.oldCurrPlaying = -1
32
33 class MediaPixmap(Pixmap):
34         def applySkin(self, desktop, screen):
35                 self.default_pixmap = None
36                 if self.skinAttributes is not None:
37                         for (attrib, value) in self.skinAttributes:
38                                 if attrib == "pixmap":
39                                         self.default_pixmap = value
40                                         break
41                 if self.default_pixmap is None:
42                         self.default_pixmap = resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/no_coverArt.png")
43                 return Pixmap.applySkin(self, desktop, screen)
44
45 class MediaPlayer(Screen, InfoBarBase, InfoBarSeek, InfoBarAudioSelection, InfoBarCueSheetSupport, InfoBarNotifications, HelpableScreen):
46         ALLOW_SUSPEND = True
47         ENABLE_RESUME_SUPPORT = True
48
49         def __init__(self, session, args = None):
50                 Screen.__init__(self, session)
51                 InfoBarAudioSelection.__init__(self)
52                 InfoBarCueSheetSupport.__init__(self, actionmap = "MediaPlayerCueSheetActions")
53                 InfoBarNotifications.__init__(self)
54                 InfoBarBase.__init__(self)
55                 HelpableScreen.__init__(self)
56                 self.summary = None
57                 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
58                 self.session.nav.stopService()
59
60                 self.playlistparsers = {}
61                 self.addPlaylistParser(PlaylistIOM3U, "m3u")
62                 self.addPlaylistParser(PlaylistIOPLS, "pls")
63                 self.addPlaylistParser(PlaylistIOInternal, "e2pls")
64
65                 # 'None' is magic to start at the list of mountpoints
66                 self.filelist = FileList(None, matchingPattern = "(?i)^.*\.(mp3|ogg|ts|wav|wave|m3u|pls|e2pls|mpg|vob)", useServiceRef = True, additionalExtensions = "4098:m3u 4098:e2pls 4098:pls")
67                 self["filelist"] = self.filelist
68
69                 self.playlist = MyPlayList()
70                 #self.playlist = PlayList()
71                 self.is_closing = False
72                 self.delname = ""
73                 self["playlist"] = self.playlist
74
75                 self["PositionGauge"] = ServicePositionGauge(self.session.nav)
76
77                 self["currenttext"] = Label("")
78
79                 self["artisttext"] = Label(_("Artist:"))
80                 self["artist"] = Label("")
81                 self["titletext"] = Label(_("Title:"))
82                 self["title"] = Label("")
83                 self["albumtext"] = Label(_("Album:"))
84                 self["album"] = Label("")
85                 self["yeartext"] = Label(_("Year:"))
86                 self["year"] = Label("")
87                 self["genretext"] = Label(_("Genre:"))
88                 self["genre"] = Label("")
89                 self["coverArt"] = MediaPixmap()
90
91                 self.seek_target = None
92
93                 class MoviePlayerActionMap(NumberActionMap):
94                         def __init__(self, player, contexts = [ ], actions = { }, prio=0):
95                                 NumberActionMap.__init__(self, contexts, actions, prio)
96                                 self.player = player
97
98                         def action(self, contexts, action):
99                                 self.player.show()
100                                 return NumberActionMap.action(self, contexts, action)
101
102
103                 self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions", 
104                         {
105                                 "ok": (self.ok, _("add file to playlist")),
106                                 "cancel": (self.exit, _("exit mediaplayer")),
107                         }, -2)
108
109                 self["MediaPlayerActions"] = HelpableActionMap(self, "MediaPlayerActions", 
110                         {
111                                 "play": (self.xplayEntry, _("play entry")),
112                                 "pause": (self.pauseEntry, _("pause")),
113                                 "stop": (self.stopEntry, _("stop entry")),
114                                 "previous": (self.previousMarkOrEntry, _("play from previous mark or playlist entry")),
115                                 "next": (self.nextMarkOrEntry, _("play from next mark or playlist entry")),
116                                 "menu": (self.showMenu, _("menu")),
117                                 "skipListbegin": (self.skip_listbegin, _("jump to listbegin")),
118                                 "skipListend": (self.skip_listend, _("jump to listend")),
119                                 "prevBouquet": (self.switchToPlayList, _("switch to playlist")),
120                                 "nextBouquet": (self.switchToFileList, _("switch to filelist")),
121                                 "delete": (self.deletePlaylistEntry, _("delete playlist entry")),
122                                 "shift_stop": (self.clear_playlist, _("clear playlist")),
123                                 "shift_record": (self.playlist.PlayListShuffle, _("shuffle playlist")),
124                         }, -2)
125
126                 self["InfobarEPGActions"] = HelpableActionMap(self, "InfobarEPGActions", 
127                         {
128                                 "showEventInfo": (self.showEventInformation, _("show event details")),
129                         })
130
131                 self["actions"] = MoviePlayerActionMap(self, ["DirectionActions"], 
132                 {
133                         "right": self.rightDown,
134                         "rightRepeated": self.doNothing,
135                         "rightUp": self.rightUp,
136                         "left": self.leftDown,
137                         "leftRepeated": self.doNothing,
138                         "leftUp": self.leftUp,
139
140                         "up": self.up,
141                         "upRepeated": self.up,
142                         "upUp": self.doNothing,
143                         "down": self.down,
144                         "downRepeated": self.down,
145                         "downUp": self.doNothing,
146                 }, -2)
147
148                 InfoBarSeek.__init__(self, actionmap = "MediaPlayerSeekActions")
149
150                 self.onClose.append(self.delMPTimer)
151                 self.onClose.append(self.__onClose)
152
153                 self.righttimer = False
154                 self.rightKeyTimer = eTimer()
155                 self.rightKeyTimer.callback.append(self.rightTimerFire)
156
157                 self.lefttimer = False
158                 self.leftKeyTimer = eTimer()
159                 self.leftKeyTimer.callback.append(self.leftTimerFire)
160
161                 self.currList = "filelist"
162
163                 self.coverArtFileName = ""
164                 self.isAudioCD = False
165                 self.AudioCD_albuminfo = {}
166
167                 self.playlistIOInternal = PlaylistIOInternal()
168                 list = self.playlistIOInternal.open(resolveFilename(SCOPE_CONFIG, "playlist.e2pls"))
169                 if list:
170                         for x in list:
171                                 self.playlist.addFile(x.ref)
172                         self.playlist.updateList()
173
174                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
175                         {
176                                 iPlayableService.evUpdatedInfo: self.__evUpdatedInfo
177                         })
178
179         def doNothing(self):
180                 pass
181
182         def createSummary(self):
183                 return MediaPlayerLCDScreen
184
185         def exit(self):
186                 self.session.openWithCallback(self.exitCB, MessageBox, _("Do you really want to exit?"), timeout=5)
187
188         def exitCB(self, answer):
189                 if answer == True:
190                         self.playlistIOInternal.clear()
191                         for x in self.playlist.list:
192                                 self.playlistIOInternal.addService(ServiceReference(x[0]))
193                         if not self.isAudioCD:
194                                 self.playlistIOInternal.save(resolveFilename(SCOPE_CONFIG, "playlist.e2pls"))
195                         self.close()
196
197         def checkSkipShowHideLock(self):
198                 self.updatedSeekState()
199
200         def doEofInternal(self, playing):
201                 if playing:
202                         self.nextEntry()
203                 else:
204                         self.show()
205
206         def __onClose(self):
207                 self.session.nav.playService(self.oldService)
208
209         def __evUpdatedInfo(self):
210                 currPlay = self.session.nav.getCurrentService()
211                 currenttitle = currPlay.info().getInfo(iServiceInformation.sCurrentTitle)
212                 totaltitles = currPlay.info().getInfo(iServiceInformation.sTotalTitles)
213                 sTitle = currPlay.info().getInfoString(iServiceInformation.sTitle)
214                 print "[__evUpdatedInfo] title %d of %d (%s)" % (currenttitle, totaltitles, sTitle)
215                 self.readTitleInformation()
216
217         def delMPTimer(self):
218                 del self.rightKeyTimer
219                 del self.leftKeyTimer
220
221         def readTitleInformation(self):
222                 currPlay = self.session.nav.getCurrentService()
223                 if currPlay is not None:
224                         sTitle = currPlay.info().getInfoString(iServiceInformation.sTitle)
225                         sAlbum = currPlay.info().getInfoString(iServiceInformation.sAlbum)
226                         sGenre = currPlay.info().getInfoString(iServiceInformation.sGenre)
227                         sArtist = currPlay.info().getInfoString(iServiceInformation.sArtist)
228
229                         if sTitle == "":
230                                 sTitle = currPlay.info().getName().split('/')[-1]
231
232                         if self.AudioCD_albuminfo:
233                                 if sAlbum == "" and "TITLE" in self.AudioCD_albuminfo:
234                                         sAlbum = self.AudioCD_albuminfo["TITLE"]
235                                 if sGenre == "" and "GENRE" in self.AudioCD_albuminfo:
236                                         sGenre = self.AudioCD_albuminfo["GENRE"]
237                                 if sArtist == "" and "PERFORMER" in self.AudioCD_albuminfo:
238                                         sArtist = self.AudioCD_albuminfo["PERFORMER"]
239
240                         self.updateMusicInformation( artist = sArtist, title = sTitle, album = sAlbum, genre = sGenre, clear = True )
241                 else:
242                         self.updateMusicInformation()
243
244         def updateMusicInformation(self, artist = "", title = "", album = "", year = "", genre = "", clear = False):
245                 self.updateSingleMusicInformation("artist", artist, clear)
246                 self.updateSingleMusicInformation("title", title, clear)
247                 self.updateSingleMusicInformation("album", album, clear)
248                 self.updateSingleMusicInformation("year", year, clear)
249                 self.updateSingleMusicInformation("genre", genre, clear)
250
251         def updateSingleMusicInformation(self, name, info, clear):
252                 if info != "" or clear:
253                         if self[name].getText() != info:
254                                 self[name].setText(info)
255
256         def updateCoverArtPixmap(self, path):
257                 while not path.endswith("/"):
258                         path = path[:-1]
259                 pngname = path + "folder.png"
260                 
261                 if not os_path.exists(pngname):
262                         pngname = self["coverArt"].default_pixmap
263                 if self.coverArtFileName != pngname:
264                         self.coverArtFileName = pngname
265                         self["coverArt"].instance.setPixmapFromFile(self.coverArtFileName)
266
267         def leftDown(self):
268                 self.lefttimer = True
269                 self.leftKeyTimer.start(1000)
270
271         def rightDown(self):
272                 self.righttimer = True
273                 self.rightKeyTimer.start(1000)
274
275         def leftUp(self):
276                 if self.lefttimer:
277                         self.leftKeyTimer.stop()
278                         self.lefttimer = False
279                         self[self.currList].pageUp()
280                         self.updateCurrentInfo()
281
282         def rightUp(self):
283                 if self.righttimer:
284                         self.rightKeyTimer.stop()
285                         self.righttimer = False
286                         self[self.currList].pageDown()
287                         self.updateCurrentInfo()
288
289         def leftTimerFire(self):
290                 self.leftKeyTimer.stop()
291                 self.lefttimer = False
292                 self.switchToFileList()
293
294         def rightTimerFire(self):
295                 self.rightKeyTimer.stop()
296                 self.righttimer = False
297                 self.switchToPlayList()
298
299         def switchToFileList(self):
300                 self.currList = "filelist"
301                 self.filelist.selectionEnabled(1)
302                 self.playlist.selectionEnabled(0)
303                 self.updateCurrentInfo()
304
305         def switchToPlayList(self):
306                 if len(self.playlist) != 0:
307                         self.currList = "playlist"
308                         self.filelist.selectionEnabled(0)
309                         self.playlist.selectionEnabled(1)
310                         self.updateCurrentInfo()
311
312         def up(self):
313                 self[self.currList].up()
314                 self.updateCurrentInfo()
315
316         def down(self):
317                 self[self.currList].down()
318                 self.updateCurrentInfo()
319
320         def showAfterSeek(self):
321                 self.show()
322
323         def showAfterCuesheetOperation(self):
324                 self.show()
325
326         def hideAfterResume(self):
327                 self.hide()
328
329         def getIdentifier(self, ref):
330                 if self.isAudioCD:
331                         return ref.getName()
332                 else:
333                         text = ref.getPath()
334                         return text.split('/')[-1]
335
336         # FIXME: maybe this code can be optimized 
337         def updateCurrentInfo(self):
338                 text = ""
339                 if self.currList == "filelist":
340                         idx = self.filelist.getSelectionIndex()
341                         r = self.filelist.list[idx]
342                         text = r[1][7]
343                         if r[0][1] == True:
344                                 if len(text) < 2:
345                                         text += " "
346                                 if text[:2] != "..":
347                                         text = "/" + text
348                         self.summaries.setText(text,1)
349
350                         idx += 1
351                         if idx < len(self.filelist.list):
352                                 r = self.filelist.list[idx]
353                                 text = r[1][7]
354                                 if r[0][1] == True:
355                                         text = "/" + text
356                                 self.summaries.setText(text,3)
357                         else:
358                                 self.summaries.setText(" ",3)
359
360                         idx += 1
361                         if idx < len(self.filelist.list):
362                                 r = self.filelist.list[idx]
363                                 text = r[1][7]
364                                 if r[0][1] == True:
365                                         text = "/" + text
366                                 self.summaries.setText(text,4)
367                         else:
368                                 self.summaries.setText(" ",4)
369
370                         text = ""
371                         if not self.filelist.canDescent():
372                                 r = self.filelist.getServiceRef()
373                                 if r is None:
374                                         return
375                                 text = r.getPath()
376                                 self["currenttext"].setText(os_path.basename(text))
377
378                 if self.currList == "playlist":
379                         t = self.playlist.getSelection()
380                         if t is None:
381                                 return
382                         #display current selected entry on LCD
383                         text = self.getIdentifier(t)
384                         self.summaries.setText(text,1)
385                         self["currenttext"].setText(text)
386                         idx = self.playlist.getSelectionIndex()
387                         idx += 1
388                         if idx < len(self.playlist):
389                                 currref = self.playlist.getServiceRefList()[idx]
390                                 text = self.getIdentifier(currref)
391                                 self.summaries.setText(text,3)
392                         else:
393                                 self.summaries.setText(" ",3)
394
395                         idx += 1
396                         if idx < len(self.playlist):
397                                 currref = self.playlist.getServiceRefList()[idx]
398                                 text = self.getIdentifier(currref)
399                                 self.summaries.setText(text,4)
400                         else:
401                                 self.summaries.setText(" ",4)
402
403         def ok(self):
404                 if self.currList == "filelist":
405                         if self.filelist.canDescent():
406                                 self.filelist.descent()
407                                 self.updateCurrentInfo()
408                         else:
409                                 self.copyFile()
410
411                 if self.currList == "playlist":
412                         selection = self["playlist"].getSelection()
413                         self.changeEntry(self.playlist.getSelectionIndex())
414
415         def showMenu(self):
416                 menu = []
417                 if self.currList == "filelist":
418                         if self.filelist.canDescent():
419                                 menu.append((_("add directory to playlist"), "copydir"))
420                         else:
421                                 menu.append((_("add files to playlist"), "copyfiles"))
422                         menu.append((_("switch to playlist"), "playlist"))
423                 else:
424                         menu.append((_("switch to filelist"), "filelist"))
425
426                         menu.append((_("shuffle playlist"), "shuffle"))
427
428                         menu.append((_("delete"), "delete"))
429                         menu.append((_("clear playlist"), "clear"))
430                 menu.append((_("hide player"), "hide"));
431                 menu.append((_("save playlist"), "saveplaylist"));
432                 menu.append((_("load playlist"), "loadplaylist"));
433                 menu.append((_("delete saved playlist"), "deleteplaylist"));
434                 self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu)
435
436         def menuCallback(self, choice):
437                 if choice is None:
438                         return
439
440                 if choice[1] == "copydir":
441                         self.copyDirectory(self.filelist.getSelection()[0])
442                 elif choice[1] == "copyfiles":
443                         self.stopEntry()
444                         self.playlist.clear()
445                         self.copyDirectory(os_path.dirname(self.filelist.getSelection()[0].getPath()) + "/", recursive = False)
446                         self.playServiceRefEntry(self.filelist.getServiceRef())
447                 elif choice[1] == "playlist":
448                         self.switchToPlayList()
449                 elif choice[1] == "filelist":
450                         self.switchToFileList()
451                 elif choice[1] == "delete":
452                         if self.playlist.getSelectionIndex() == self.playlist.getCurrentIndex():
453                                 self.stopEntry()
454                         self.deleteEntry()
455                 elif choice[1] == "clear":
456                         self.stopEntry()
457                         self.playlist.clear()
458                         self.switchToFileList()
459                 elif choice[1] == "hide":
460                         self.hide()
461                 elif choice[1] == "saveplaylist":
462                         self.save_playlist()
463                 elif choice[1] == "loadplaylist":
464                         self.load_playlist()
465                 elif choice[1] == "deleteplaylist":
466                         self.delete_saved_playlist()
467                 elif choice[1] == "shuffle":
468                         self.playlist.PlayListShuffle()
469
470
471         def showEventInformation(self):
472                 from Screens.EventView import EventViewSimple
473                 from ServiceReference import ServiceReference
474                 evt = self[self.currList].getCurrentEvent()
475                 if evt:
476                         self.session.open(EventViewSimple, evt, ServiceReference(self.getCurrent()))
477
478         # also works on filelist (?)
479         def getCurrent(self):
480                 return self["playlist"].getCurrent()
481
482         def deletePlaylistEntry(self):
483                 if self.currList == "playlist":
484                         if self.playlist.getSelectionIndex() == self.playlist.getCurrentIndex():
485                                 self.stopEntry()
486                         self.deleteEntry()
487
488         def skip_listbegin(self):
489                 if self.currList == "filelist":
490                         self.filelist.moveToIndex(0)
491                 else:
492                         self.playlist.moveToIndex(0)
493                 self.updateCurrentInfo()
494
495         def skip_listend(self):
496                 if self.currList == "filelist":
497                         idx = len(self.filelist.list)
498                         self.filelist.moveToIndex(idx - 1)
499                 else:
500                         self.playlist.moveToIndex(len(self.playlist)-1)
501                 self.updateCurrentInfo()
502
503         def save_playlist(self):
504                 self.session.openWithCallback(self.save_playlist2,InputBox, title=_("Please enter filename (empty = use current date)"),windowTitle = _("Save Playlist"))
505
506         def save_playlist2(self, name):
507                 if name is not None:
508                         name = name.strip()
509                         if name == "":
510                                 name = strftime("%y%m%d_%H%M%S")
511                         name += ".e2pls"
512                         self.playlistIOInternal.clear()
513                         for x in self.playlist.list:
514                                 self.playlistIOInternal.addService(ServiceReference(x[0]))
515                         self.playlistIOInternal.save(resolveFilename(SCOPE_PLAYLIST) + name)
516
517         def load_playlist(self):
518                 listpath = []
519                 playlistdir = resolveFilename(SCOPE_PLAYLIST)
520                 try:
521                         for i in os_listdir(playlistdir):
522                                 listpath.append((i,playlistdir + i))
523                 except IOError,e:
524                         print "Error while scanning subdirs ",e
525                 self.session.openWithCallback(self.PlaylistSelected, ChoiceBox, title=_("Please select a playlist..."), list = listpath)
526
527         def PlaylistSelected(self,path):
528                 if path is not None:
529                         self.clear_playlist()
530                         self.playlistIOInternal = PlaylistIOInternal()
531                         list = self.playlistIOInternal.open(path[1])
532                         if list:
533                                 for x in list:
534                                         self.playlist.addFile(x.ref)
535                                 self.playlist.updateList()
536
537         def delete_saved_playlist(self):
538                 listpath = []
539                 playlistdir = resolveFilename(SCOPE_PLAYLIST)
540                 try:
541                         for i in os_listdir(playlistdir):
542                                 listpath.append((i,playlistdir + i))
543                 except IOError,e:
544                         print "Error while scanning subdirs ",e
545                 self.session.openWithCallback(self.DeletePlaylistSelected, ChoiceBox, title=_("Please select a playlist to delete..."), list = listpath)
546
547         def DeletePlaylistSelected(self,path):
548                 if path is not None:
549                         self.delname = path[1]
550                         self.session.openWithCallback(self.deleteConfirmed, MessageBox, _("Do you really want to delete %s?") % (path[1]))
551
552         def deleteConfirmed(self, confirmed):
553                 if confirmed:
554                         os_remove(self.delname)
555
556         def clear_playlist(self):
557                 self.stopEntry()
558                 self.playlist.clear()
559                 self.switchToFileList()
560
561         def copyDirectory(self, directory, recursive = True):
562                 print "copyDirectory", directory
563                 filelist = FileList(directory, useServiceRef = True, isTop = True)
564
565                 for x in filelist.getFileList():
566                         if x[0][1] == True: #isDir
567                                 if recursive:
568                                         self.copyDirectory(x[0][0])
569                         else:
570                                 self.playlist.addFile(x[0][0])
571                 self.playlist.updateList()
572
573         def copyFile(self):
574                 if self.filelist.getServiceRef().type == 4098: # playlist
575                         ServiceRef = self.filelist.getServiceRef()
576                         extension = ServiceRef.getPath()[ServiceRef.getPath().rfind('.') + 1:]
577                         print "extension:", extension
578                         if self.playlistparsers.has_key(extension):
579                                 playlist = self.playlistparsers[extension]()
580                                 list = playlist.open(ServiceRef.getPath())
581                                 for x in list:
582                                         self.playlist.addFile(x.ref)
583                 else:
584                         self.playlist.addFile(self.filelist.getServiceRef())
585                         self.playlist.updateList()
586                         if len(self.playlist) == 1:
587                                 self.changeEntry(0)
588
589         def addPlaylistParser(self, parser, extension):
590                 self.playlistparsers[extension] = parser
591
592         def nextEntry(self):
593                 next = self.playlist.getCurrentIndex() + 1
594                 if next < len(self.playlist):
595                         self.changeEntry(next)
596
597         def nextMarkOrEntry(self):
598                 if not self.jumpPreviousNextMark(lambda x: x):
599                         next = self.playlist.getCurrentIndex() + 1
600                         if next < len(self.playlist):
601                                 self.changeEntry(next)
602                         else:
603                                 self.doSeek(-1)
604
605         def previousMarkOrEntry(self):
606                 if not self.jumpPreviousNextMark(lambda x: -x-5*90000, start=True):
607                         next = self.playlist.getCurrentIndex() - 1
608                         if next >= 0:
609                                 self.changeEntry(next)
610
611         def deleteEntry(self):
612                 self.playlist.deleteFile(self.playlist.getSelectionIndex())
613                 self.playlist.updateList()
614                 if len(self.playlist) == 0:
615                         self.switchToFileList()
616
617         def changeEntry(self, index):
618                 self.playlist.setCurrentPlaying(index)
619                 self.playEntry()
620
621         def playServiceRefEntry(self, serviceref):
622                 serviceRefList = self.playlist.getServiceRefList()
623                 for count in range(len(serviceRefList)):
624                         if serviceRefList[count] == serviceref:
625                                 self.changeEntry(count)
626                                 break
627                         
628         def xplayEntry(self):
629                 if self.currList == "playlist":
630                         self.playEntry()
631                 else:
632                         self.stopEntry()
633                         self.playlist.clear()
634                         sel = self.filelist.getSelection()
635                         if sel:
636                                 if sel[1]: # can descent
637                                         # add directory to playlist
638                                         self.copyDirectory(sel[0])
639                                 else:
640                                         # add files to playlist
641                                         self.copyDirectory(os_path.dirname(sel[0].getPath()) + "/", recursive = False)
642                         if len(self.playlist) > 0:
643                                 self.changeEntry(0)
644         
645         def playEntry(self):
646                 if len(self.playlist.getServiceRefList()):
647                         needsInfoUpdate = False
648                         currref = self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()]
649                         if self.session.nav.getCurrentlyPlayingServiceReference() is None or currref != self.session.nav.getCurrentlyPlayingServiceReference():
650                                 self.session.nav.playService(self.playlist.getServiceRefList()[self.playlist.getCurrentIndex()])
651                                 info = eServiceCenter.getInstance().info(currref)
652                                 description = info and info.getInfoString(currref, iServiceInformation.sDescription) or ""
653                                 self["title"].setText(description)
654                                 # display just playing musik on LCD
655                                 idx = self.playlist.getCurrentIndex()
656                                 currref = self.playlist.getServiceRefList()[idx]
657                                 text = self.getIdentifier(currref)
658                                 text = ">"+text
659                                 ext = text[-3:].lower()
660
661                                 # FIXME: the information if the service contains video (and we should hide our window) should com from the service instead 
662                                 if ext not in ["mp3", "wav", "ogg"] and not self.isAudioCD:
663                                         self.hide()
664                                 else:
665                                         needsInfoUpdate = True
666                                 self.summaries.setText(text,1)
667
668                                 # get the next two entries
669                                 idx += 1
670                                 if idx < len(self.playlist):
671                                         currref = self.playlist.getServiceRefList()[idx]
672                                         text = self.getIdentifier(currref)
673                                         self.summaries.setText(text,3)
674                                 else:
675                                         self.summaries.setText(" ",3)
676
677                                 idx += 1
678                                 if idx < len(self.playlist):
679                                         currref = self.playlist.getServiceRefList()[idx]
680                                         text = self.getIdentifier(currref)
681                                         self.summaries.setText(text,4)
682                                 else:
683                                         self.summaries.setText(" ",4)
684                         else:
685                                 idx = self.playlist.getCurrentIndex()
686                                 currref = self.playlist.getServiceRefList()[idx]
687                                 text = currref.getPath()
688                                 ext = text[-3:].lower()
689                                 if ext not in ["mp3", "wav", "ogg"] and not self.isAudioCD:
690                                         self.hide()
691                                 else:
692                                         needsInfoUpdate = True
693
694                         self.unPauseService()
695                         if needsInfoUpdate == True:
696                                 self.updateCoverArtPixmap(currref.getPath())
697                         else:
698                                 pngname = self["coverArt"].default_pixmap
699                                 self.coverArtFileName = pngname
700                                 self["coverArt"].instance.setPixmapFromFile(self.coverArtFileName)
701                         self.readTitleInformation()
702
703         def updatedSeekState(self):
704                 if self.seekstate == self.SEEK_STATE_PAUSE:
705                         self.playlist.pauseFile()
706                 elif self.seekstate == self.SEEK_STATE_PLAY:
707                         self.playlist.playFile()
708                 elif self.isStateForward(self.seekstate):
709                         self.playlist.forwardFile()
710                 elif self.isStateBackward(self.seekstate):
711                         self.playlist.rewindFile()
712
713         def pauseEntry(self):
714                 self.pauseService()
715                 self.show()
716
717         def stopEntry(self):
718                 self.playlist.stopFile()
719                 self.session.nav.playService(None)
720                 self.updateMusicInformation(clear=True)
721                 self.show()
722
723         def unPauseService(self):
724                 self.setSeekState(self.SEEK_STATE_PLAY)
725
726
727 class MediaPlayerLCDScreen(Screen):
728         skin = """
729         <screen position="0,0" size="132,64" title="LCD Text">
730                 <widget name="text1" position="4,0" size="132,35" font="Regular;16"/>
731                 <widget name="text3" position="4,36" size="132,14" font="Regular;10"/>
732                 <widget name="text4" position="4,49" size="132,14" font="Regular;10"/>
733         </screen>"""
734
735         def __init__(self, session, parent):
736                 Screen.__init__(self, session)
737                 self["text1"] = Label("Mediaplayer")
738                 self["text3"] = Label("")
739                 self["text4"] = Label("")
740
741         def setText(self, text, line):
742                 print "lcd set text:", text, line
743                 if len(text) > 10:
744                         if text[-4:] == ".mp3":
745                                 text = text[:-4]
746                 textleer = "    "
747                 text = text + textleer*10
748                 if line == 1:
749                         self["text1"].setText(text)
750                 elif line == 3:
751                         self["text3"].setText(text)
752                 elif line == 4:
753                         self["text4"].setText(text)
754
755 def main(session, **kwargs):
756         session.open(MediaPlayer)
757
758 def menu(menuid, **kwargs):
759         if menuid == "mainmenu":
760                 return [(_("Media player"), main, "media_player", 45)]
761         return []
762
763 def filescan_open(list, session, **kwargs):
764         from enigma import eServiceReference
765
766         mp = session.open(MediaPlayer)
767
768         mp.switchToPlayList()
769         for file in list:
770                 ref = eServiceReference(4097, 0, file.path)
771                 mp.playlist.addFile(ref)
772
773         # TODO: rather play first than last file?
774         mp.playServiceRefEntry(ref)
775         mp.playlist.updateList()
776
777 def audioCD_open(list, session, **kwargs):
778         from enigma import eServiceReference
779
780         mp = session.open(MediaPlayer)
781
782         mp.playlist.clear()
783         mp.isAudioCD = True
784
785         mp.switchToPlayList()
786         cdtext = popen('cdtextinfo -l').read()
787         tracklist = []
788         if cdtext is not "":
789                 tracklist = cdtext.splitlines()
790                 cdtext = popen('cdtextinfo -a').read()
791                 if cdtext is not "":
792                         albumtags = cdtext.splitlines()
793                         for tag in albumtags:
794                                 tag = tag.split(':',1)
795                                 mp.AudioCD_albuminfo[tag[0]] = tag[1]
796                         print mp.AudioCD_albuminfo
797         idx = 0
798         for file in list:
799                 ref = eServiceReference(4097, 0, file.path)
800                 if idx < len(tracklist):
801                         track = tracklist[idx]
802                         ref.setName("%d - %s" % (int(track.split(':',1)[0]), track.split(':')[1]))
803                         idx += 1
804                 mp.playlist.addFile(ref)
805
806         mp.changeEntry(0)
807         mp.playlist.updateList()
808         mp.switchToPlayList()
809
810 def filescan(**kwargs):
811         from Components.Scanner import Scanner, ScanPath
812         return [
813                 Scanner(mimetypes = ["video/mpeg"],
814                         paths_to_scan =
815                                 [
816                                         ScanPath(path = "", with_subdirs = False),
817                                 ],
818                         name = "Movie",
819                         description = "View Movies...",
820                         openfnc = filescan_open,
821                 ),
822                 Scanner(mimetypes = ["audio/mpeg", "audio/x-wav", "application/ogg"],
823                         paths_to_scan =
824                                 [
825                                         ScanPath(path = "", with_subdirs = False),
826                                 ],
827                         name = "Music",
828                         description = "Play Music...",
829                         openfnc = filescan_open,
830                 ),
831                 Scanner(mimetypes = ["audio/x-cda", "audio/x-wav"],
832                         paths_to_scan =
833                                 [
834                                         ScanPath(path = "", with_subdirs = False),
835                                 ],
836                         name = "Audio-CD",
837                         description = "Play Audio-CD...",
838                         openfnc = audioCD_open,
839                 )
840         ]
841
842 from Plugins.Plugin import PluginDescriptor
843 def Plugins(**kwargs):
844         return [
845                 PluginDescriptor(name = "MediaPlayer", description = "Play back media files", where = PluginDescriptor.WHERE_MENU, fnc = menu),
846                 PluginDescriptor(name = "MediaPlayer", where = PluginDescriptor.WHERE_FILESCAN, fnc = filescan)
847         ]