2 # Merlin Music Player E2
6 # Coded by Dr.Best (c) 2010
7 # Support: www.dreambox-tools.info
9 # This plugin is licensed under the Creative Commons
10 # Attribution-NonCommercial-ShareAlike 3.0 Unported
11 # License. To view a copy of this license, visit
12 # http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
13 # Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
15 # Alternatively, this plugin may be distributed and executed on hardware which
16 # is licensed by Dream Multimedia GmbH.
18 # This plugin is NOT free software. It is open source, you are allowed to
19 # modify it (if you keep the license), but it may not be commercially
20 # distributed other than under the conditions noted above.
23 from Plugins.Plugin import PluginDescriptor
24 from Screens.Screen import Screen
25 from Components.ActionMap import ActionMap, NumberActionMap
26 from Components.Label import Label
27 from enigma import RT_VALIGN_CENTER, RT_HALIGN_LEFT, RT_HALIGN_RIGHT, RT_HALIGN_CENTER, gFont, eListbox,ePoint, eListboxPythonMultiContent
29 import merlinmp3player
30 ENIGMA_MERLINPLAYER_ID = 0x1014
31 from Components.FileList import FileList
32 from enigma import eServiceReference, eTimer
33 from os import path as os_path, mkdir as os_mkdir, listdir as os_listdir, walk as os_walk, access as os_access, W_OK as os_W_OK
34 from Components.ProgressBar import ProgressBar
35 from twisted.internet import reactor, defer
36 from twisted.web import client
37 from twisted.web.client import HTTPClientFactory, downloadPage
38 from enigma import getDesktop
39 from Screens.MessageBox import MessageBox
40 from Components.GUIComponent import GUIComponent
41 from enigma import ePicLoad
42 from xml.etree.cElementTree import fromstring as cet_fromstring
43 from urllib import quote
44 from Components.ScrollLabel import ScrollLabel
45 from Components.AVSwitch import AVSwitch
46 from Tools.Directories import fileExists, resolveFilename, SCOPE_CURRENT_SKIN
47 from Tools.LoadPixmap import LoadPixmap
48 from Components.Pixmap import Pixmap, MultiPixmap
49 from Components.ServicePosition import ServicePositionGauge
50 from Screens.InfoBarGenerics import InfoBarSeek, InfoBarNotifications
51 from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
52 from enigma import iPlayableService, iServiceInformation
53 from Components.Sources.StaticText import StaticText
54 from Screens.ChoiceBox import ChoiceBox
55 from Screens.VirtualKeyBoard import VirtualKeyBoard
56 from Tools.BoundFunction import boundFunction
57 from sqlite3 import dbapi2 as sqlite
58 from mutagen.flac import FLAC
59 from mutagen.mp3 import MP3
60 from mutagen.id3 import ID3, USLT
61 from mutagen.easyid3 import EasyID3
62 from mutagen.easymp4 import EasyMP4
63 from mutagen.oggvorbis import OggVorbis
64 from datetime import timedelta as datetime_timedelta
66 from random import shuffle, randrange
67 from Components.config import config, ConfigSubsection, ConfigDirectory, ConfigYesNo, ConfigInteger, getConfigListEntry, configfile
68 from Components.ConfigList import ConfigListScreen
69 from Tools.HardwareInfo import HardwareInfo
71 from Components.SystemInfo import SystemInfo
72 from enigma import eServiceCenter, getBestPlayableServiceReference
73 from Components.VideoWindow import VideoWindow
74 from ServiceReference import ServiceReference
75 from Screens.EpgSelection import EPGSelection
76 from Screens.EventView import EventViewEPGSelect
77 from enigma import ePoint, eEPGCache
78 from Screens.InfoBarGenerics import NumberZap
81 START_MERLIN_PLAYER_SCREEN_TIMER_VALUE = 7000
83 config.plugins.merlinmusicplayer = ConfigSubsection()
84 config.plugins.merlinmusicplayer.hardwaredecoder = ConfigYesNo(default = True)
85 config.plugins.merlinmusicplayer.startlastsonglist = ConfigYesNo(default = True)
86 config.plugins.merlinmusicplayer.lastsonglistindex = ConfigInteger(-1)
87 config.plugins.merlinmusicplayer.databasepath = ConfigDirectory(default = "/hdd/")
88 config.plugins.merlinmusicplayer.usegoogleimage = ConfigYesNo(default = True)
89 config.plugins.merlinmusicplayer.googleimagepath = ConfigDirectory(default = "/hdd/")
90 config.plugins.merlinmusicplayer.usescreensaver = ConfigYesNo(default = True)
91 config.plugins.merlinmusicplayer.screensaverwait = ConfigInteger(1,limits = (1, 60))
92 config.plugins.merlinmusicplayer.idreamextendedpluginlist = ConfigYesNo(default = True)
93 config.plugins.merlinmusicplayer.merlinmusicplayerextendedpluginlist = ConfigYesNo(default = True)
94 config.plugins.merlinmusicplayer.defaultfilebrowserpath = ConfigDirectory(default = "/hdd/")
95 config.plugins.merlinmusicplayer.rememberlastfilebrowserpath = ConfigYesNo(default = True)
96 config.plugins.merlinmusicplayer.idreammainmenu = ConfigYesNo(default = False)
97 config.plugins.merlinmusicplayer.merlinmusicplayermainmenu = ConfigYesNo(default = False)
99 from enigma import ePythonMessagePump
100 from threading import Thread, Lock
110 self.__list.append(val)
116 ret = self.__list.pop()
123 class PathToDatabase(Thread):
125 Thread.__init__(self)
126 self.__running = False
127 self.__cancel = False
129 self.__messages = ThreadQueue()
130 self.__messagePump = ePythonMessagePump()
132 def __getMessagePump(self):
133 return self.__messagePump
135 def __getMessageQueue(self):
136 return self.__messages
138 def __getRunning(self):
139 return self.__running
144 MessagePump = property(__getMessagePump)
145 Message = property(__getMessageQueue)
146 isRunning = property(__getRunning)
148 def Start(self, path):
149 if not self.__running:
154 mp = self.__messagePump
155 self.__running = True
156 self.__cancel = False
158 connection = OpenDatabase()
159 if connection is not None:
160 connection.text_factory = str
161 cursor = connection.cursor()
164 for root, subFolders, files in os_walk(self.__path):
167 for filename in files:
170 cursor.execute('SELECT song_id FROM Songs WHERE filename = "%s";' % os_path.join(root,filename))
171 row = cursor.fetchone()
173 audio, isAudio, title, genre,artist,album,tracknr,track,date,length,bitrate = getID3Tags(root,filename)
177 cursor.execute('SELECT artist_id FROM Artists WHERE artist = "%s";' % (artist.replace('"','""')))
179 row = cursor.fetchone()
181 cursor.execute('INSERT INTO Artists (artist) VALUES("%s");' % (artist.replace('"','""')))
182 artistID = cursor.lastrowid
187 cursor.execute('SELECT album_id FROM Album WHERE album_text = "%s";' % (album.replace('"','""')))
188 row = cursor.fetchone()
190 cursor.execute('INSERT INTO Album (album_text) VALUES("%s");' % (album.replace('"','""')))
191 albumID = cursor.lastrowid
197 cursor.execute('SELECT genre_id FROM Genre WHERE genre_text = "%s";' % (genre.replace('"','""')))
198 row = cursor.fetchone()
200 cursor.execute('INSERT INTO Genre (genre_text) VALUES("%s");' % (genre.replace('"','""')))
201 genreID = cursor.lastrowid
207 cursor.execute("INSERT INTO Songs (filename,title,artist_id,album_id,genre_id,tracknumber, bitrate, length, track, date) VALUES(?,?,?,?,?,?,?,?,?,?);" , (os_path.join(root,filename),title,artistID,albumID,genreID, tracknr, bitrate, length, track, date))
208 self.__messages.push((THREAD_WORKING, _("%s\n added to database") % os_path.join(root,filename)))
211 except sqlite.IntegrityError:
212 self.__messages.push((THREAD_WORKING, _("%s\n already exists in database!") % os_path.join(root,filename)))
215 elif time() - checkTime >= 0.1: # update interval for gui
216 self.__messages.push((THREAD_WORKING, _("%s\n already exists in database!") % os_path.join(root,filename)))
220 if not self.__cancel:
225 self.__messages.push((THREAD_FINISHED, _("Process aborted.\n 0 files added to database!\nPress OK to close.") ))
227 self.__messages.push((THREAD_FINISHED, _("%d files added to database!\nPress OK to close." % counter)))
229 self.__messages.push((THREAD_FINISHED, _("Error!\nCan not open database!\nCheck if save folder is correct and writeable!\nPress OK to close.") ))
231 self.__running = False
232 Thread.__init__(self)
234 pathToDatabase = PathToDatabase()
237 class iDreamAddToDatabase(Screen):
238 skin = """<screen name="iDreamAddToDatabase" position="center,center" size="560,320" title="Add music files to iDream database">
239 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
240 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
241 <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
242 <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
243 <widget name="output" position="10,10" size="540,300" valign="center" halign="center" font="Regular;22" />
244 <widget render="Label" source="key_red" position="0,0" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
245 <widget render="Label" source="key_green" position="140,0" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
247 def __init__(self, session, initDir):
248 Screen.__init__(self, session)
249 self["actions"] = ActionMap(["WizardActions", "ColorActions"],
257 self["key_red"] = StaticText(_("Cancel"))
258 self["key_green"] = StaticText("Close")
259 self["output"] = Label()
260 self.onClose.append(self.__onClose)
261 pathToDatabase.MessagePump.recv_msg.get().append(self.gotThreadMsg)
262 if not pathToDatabase.isRunning and initDir:
263 pathToDatabase.Start(initDir)
265 def gotThreadMsg(self, msg):
266 msg = pathToDatabase.Message.pop()
267 self["output"].setText(msg[1])
268 if msg[0] == THREAD_FINISHED:
269 self["key_red"].setText("")
275 if pathToDatabase.isRunning:
276 pathToDatabase.Cancel()
279 pathToDatabase.MessagePump.recv_msg.get().remove(self.gotThreadMsg)
282 class myHTTPClientFactory(HTTPClientFactory):
283 def __init__(self, url, method='GET', postdata=None, headers=None,
284 agent="SHOUTcast", timeout=0, cookies=None,
285 followRedirect=1, lastModified=None, etag=None):
286 HTTPClientFactory.__init__(self, url, method=method, postdata=postdata,
287 headers=headers, agent=agent, timeout=timeout, cookies=cookies,followRedirect=followRedirect)
289 def sendUrlCommand(url, contextFactory=None, timeout=60, *args, **kwargs):
290 scheme, host, port, path = client._parse(url)
291 factory = myHTTPClientFactory(url, *args, **kwargs)
292 reactor.connectTCP(host, port, factory, timeout=timeout)
293 return factory.deferred
296 class MethodArguments:
297 def __init__(self, method = None, arguments = None):
299 self.arguments = arguments
302 def __init__(self, cache = True, index = 0, listview = [], headertext = "", methodarguments = None):
305 self.listview = listview
306 self.headertext = headertext
307 self.methodarguments = methodarguments
310 def __init__(self, text = "", mode = 0, id = -1, navigator = False, artistID = 0, albumID = 0, title = "", artist = "", filename = "", bitrate = None, length = "", genre = "", track = "", date = "", album = "", playlistID = 0, genreID = 0, songID = 0, join = True, PTS = None):
313 self.navigator = navigator
314 self.artistID = artistID
315 self.albumID = albumID
318 self.filename = filename
319 if bitrate is not None:
321 self.bitrate = "%d Kbps" % bitrate
323 self.bitrate = bitrate
328 if track is not None:
329 self.track = "Track %s" % track
334 self.date = " (%s)" % date
340 self.playlistID = playlistID
341 self.genreID = genreID
347 connectstring = os_path.join(config.plugins.merlinmusicplayer.databasepath.value ,"iDream.db")
349 if os_path.exists(connectstring):
352 connection = sqlite.connect(connectstring)
353 if not os_access(connectstring, os_W_OK):
354 print "[MerlinMusicPlayer] Error: database file needs to be writable, can not open %s for writing..." % connectstring
358 print "[MerlinMusicPlayer] unable to open database file: %s" % connectstring
361 connection.execute('CREATE TABLE IF NOT EXISTS Songs (song_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, filename TEXT NOT NULL UNIQUE, title TEXT, artist_id INTEGER, album_id INTEGER, genre_id INTEGER, tracknumber INTEGER, bitrate INTEGER, length TEXT, track TEXT, date TEXT, lyrics TEXT);')
362 connection.execute('CREATE TABLE IF NOT EXISTS Artists (artist_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, artist TEXT NOT NULL UNIQUE);')
363 connection.execute('CREATE TABLE IF NOT EXISTS Album (album_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, album_text TEXT NOT NULL UNIQUE);')
364 connection.execute('CREATE TABLE IF NOT EXISTS Genre (genre_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, genre_text TEXT NOT NULL UNIQUE);')
365 connection.execute('CREATE TABLE IF NOT EXISTS Playlists (playlist_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, playlist_text TEXT NOT NULL);')
366 connection.execute('CREATE TABLE IF NOT EXISTS Playlist_Songs (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, playlist_id INTEGER NOT NULL, song_id INTEGER NOT NULL);')
367 connection.execute('CREATE TABLE IF NOT EXISTS CurrentSongList (ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, song_id INTEGER, filename TEXT NOT NULL, title TEXT, artist TEXT, album TEXT, genre TEXT, bitrate TEXT, length TEXT, track TEXT, date TEXT, PTS INTEGER);')
370 def getEncodedString(value):
373 returnValue = value.encode("utf-8", 'ignore')
374 except UnicodeDecodeError:
376 returnValue = value.encode("iso8859-1", 'ignore')
377 except UnicodeDecodeError:
379 returnValue = value.decode("cp1252").encode("utf-8")
380 except UnicodeDecodeError:
384 def getID3Tags(root,filename):
397 if filename.lower().endswith(".mp3"):
398 try: audio = MP3(os_path.join(root,filename), ID3 = EasyID3)
400 elif filename.lower().endswith(".flac"):
402 audio = FLAC(os_path.join(root,filename))
405 elif filename.lower().endswith(".m4a"):
406 try: audio = EasyMP4(os_path.join(root,filename))
408 elif filename.lower().endswith(".ogg"):
409 try: audio = OggVorbis(os_path.join(root,filename))
414 title = getEncodedString(audio.get('title', [filename])[0])
416 # list index out of range workaround
417 genre = getEncodedString(audio.get('genre', ['n/a'])[0])
420 artist = getEncodedString(audio.get('artist', ['n/a'])[0])
421 album = getEncodedString(audio.get('album', ['n/a'])[0])
423 tracknr = int(audio.get('tracknumber', ['-1'])[0].split("/")[0])
426 track = getEncodedString(audio.get('tracknumber', ['n/a'])[0])
427 date = getEncodedString(audio.get('date', ['n/a'])[0])
429 length = str(datetime_timedelta(seconds=int(audio.info.length))).encode("utf-8", 'ignore')
433 bitrate = audio.info.bitrate / 1000
438 title = os_path.splitext(os_path.basename(filename))[0]
448 return audio, isAudio, title, genre ,artist, album, tracknr, track, date, length, bitrate
450 class MerlinMusicPlayerScreenSaver(Screen):
452 sz_w = getDesktop(0).size().width()
455 <screen name="MerlinMusicPlayerScreenSaver" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="MerlinMusicPlayerScreenSaver">
456 <widget name="coverArt" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/no_coverArt.png" position="200,77" size="238,238" transparent="1" alphatest="blend" />
457 <widget name="display" position="200,315" size="1280,24" zPosition="1" transparent="1" font="Regular;20" foregroundColor="#fcc000" />
461 <screen name="MerlinMusicPlayerScreenSaver" position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="MerlinMusicPlayerScreenSaver">
462 <widget name="coverArt" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/no_coverArt.png" position="200,77" size="238,238" transparent="1" alphatest="blend" />
463 <widget name="display" position="200,315" size="1024,24" zPosition="1" transparent="1" font="Regular;20" foregroundColor="#fcc000" />
468 <screen name="MerlinMusicPlayerScreenSaver" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="MerlinMusicPlayerScreenSaver">
469 <widget name="coverArt" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/no_coverArt.png" position="200,77" size="238,238" transparent="1" alphatest="blend" />
470 <widget name="display" position="200,315" size="720,24" zPosition="1" transparent="1" font="Regular;20" foregroundColor="#fcc000" />
474 def __init__(self, session):
475 self.session = session
476 Screen.__init__(self, session)
477 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EventViewActions"],
485 "pageUp": self.close,
486 "pageDown": self.close,
487 "yellow": self.close,
493 "prevBouquet": self.close,
494 "nextBouquet": self.close,
498 self["coverArt"] = MerlinMediaPixmap()
499 self.coverMoveTimer = eTimer()
500 self.coverMoveTimer.timeout.get().append(self.moveCoverArt)
501 self.coverMoveTimer.start(1)
502 self["display"] = Label()
504 def updateDisplayText(self, text):
505 self["display"].setText(text)
507 def updateLCD(self, text, line):
508 self.summaries.setText(text,line)
510 def updateCover(self, filename = None, modus = 0):
511 print "[MerlinMusicPlayerScreenSaver] updating coverart with filename = %s and modus = %d" % (filename, modus)
514 self["coverArt"].showCoverFromFile(filename)
516 self["coverArt"].showDefaultCover()
518 self["coverArt"].showDefaultCover()
520 self["coverArt"].embeddedCoverArt()
522 self["coverArt"].updateCoverArt(filename)
524 self["coverArt"].showCoverFromFile(filename)
526 def moveCoverArt(self):
527 x = randrange(getDesktop(0).size().width()-238)
528 y = randrange(getDesktop(0).size().height()-238-28)
529 self["coverArt"].move(ePoint(x,y))
530 self["display"].move(ePoint(x,y+240))
531 self.coverMoveTimer.start(15000)
533 def createSummary(self):
534 return MerlinMusicPlayerLCDScreen
537 class MerlinMusicPlayerTV(MerlinMusicPlayerScreenSaver):
539 w = getDesktop(0).size().width()
540 h = getDesktop(0).size().height()
551 <screen backgroundColor="transparent" flags="wfNoBorder" position="0,0" size="%d,%d" title="MerlinMusicPlayerTV">
552 <widget backgroundColor="transparent" name="video" position="0,0" size="%d,%d" zPosition="1"/>
553 <widget name="coverArt" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/no_coverArt.png" position="%d,%d" size="64,64" transparent="1" alphatest="blend" zPosition="2" />
554 <widget name="display" position="%d,%d" size="%d,24" zPosition="2" backgroundColor="#33000000" font="Regular;20" foregroundColor="#fcc000" />
555 </screen>""" % (w,h,w,h,cx,cy,dx,dy,dw)
558 def __init__(self, session, currentService, servicelist):
559 self.session = session
560 Screen.__init__(self, session)
561 self.onClose.append(self.__onClose)
562 self["actions"] = ActionMap(["OkCancelActions", "DirectionActions", "ChannelSelectBaseActions", "ChannelSelectEPGActions"],
564 "cancel": self.close,
566 "right": self.nextService,
567 "left": self.prevService,
568 "nextBouquet": self.nextBouquet,
569 "prevBouquet": self.prevBouquet,
570 "showEPGList": self.openEventView,
573 self["actions2"] = NumberActionMap(["NumberActions"],
575 "1": self.keyNumberGlobal,
576 "2": self.keyNumberGlobal,
577 "3": self.keyNumberGlobal,
578 "4": self.keyNumberGlobal,
579 "5": self.keyNumberGlobal,
580 "6": self.keyNumberGlobal,
581 "7": self.keyNumberGlobal,
582 "8": self.keyNumberGlobal,
583 "9": self.keyNumberGlobal,
585 self.epgcache = eEPGCache.getInstance()
586 self.servicelist = servicelist
587 self["coverArt"] = MerlinMediaPixmap()
588 self["display"] = Label()
589 self["video"] = VideoWindow(fb_width = getDesktop(0).size().width(), fb_height = getDesktop(0).size().height())
590 if self.servicelist is None:
591 self.playService(currentService)
593 current = ServiceReference(self.servicelist.getCurrentSelection())
594 self.playService(current.ref)
596 self.showHideTimer = eTimer()
597 self.showHideTimer.timeout.get().append(self.showHideTimerTimeout)
598 self.idx = config.usage.infobar_timeout.index
600 self.showHideTimer.start(self.idx * 1000)
601 self.displayShown = True
604 if self.displayShown:
605 if self.showHideTimer.isActive():
606 self.showHideTimer.stop()
607 self["coverArt"].hide()
608 self["display"].hide()
610 self["coverArt"].show()
611 self["display"].show()
613 self.showHideTimer.start(self.idx * 1000)
614 self.displayShown = not self.displayShown
616 def showHideTimerTimeout(self):
619 def updateDisplayText(self, text):
620 if self.showHideTimer.isActive():
621 self.showHideTimer.stop()
622 self["display"].setText(text)
623 self.displayShown = False
626 # Source Code taken from Virtual(Pip)Zap :-)
628 # switch with numbers
629 def keyNumberGlobal(self, number):
630 self.session.openWithCallback(self.numberEntered, NumberZap, number)
632 def numberEntered(self, retval):
634 self.zapToNumber(retval)
636 def searchNumberHelper(self, serviceHandler, num, bouquet):
637 servicelist = serviceHandler.list(bouquet)
638 if not servicelist is None:
640 serviceIterator = servicelist.getNext()
641 if not serviceIterator.valid(): #check end of list
643 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
646 if not num: #found service with searched number ?
647 return serviceIterator, 0
650 def zapToNumber(self, number):
651 bouquet = self.servicelist.bouquet_root
653 serviceHandler = eServiceCenter.getInstance()
654 bouquetlist = serviceHandler.list(bouquet)
655 if not bouquetlist is None:
657 bouquet = bouquetlist.getNext()
658 if not bouquet.valid(): #check end of list
660 if bouquet.flags & eServiceReference.isDirectory:
661 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
662 if not service is None:
663 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
664 self.servicelist.clearPath()
665 if self.servicelist.bouquet_root != bouquet:
666 self.servicelist.enterPath(self.servicelist.bouquet_root)
667 self.servicelist.enterPath(bouquet)
668 self.servicelist.setCurrentSelection(service) #select the service in servicelist
669 # update infos, no matter if service is none or not
670 current = ServiceReference(self.servicelist.getCurrentSelection())
671 self.playService(current.ref)
673 def nextService(self):
674 if self.servicelist is not None:
676 if self.servicelist.inBouquet():
677 prev = self.servicelist.getCurrentSelection()
679 prev = prev.toString()
681 if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
682 self.servicelist.nextBouquet()
684 self.servicelist.moveDown()
685 cur = self.servicelist.getCurrentSelection()
686 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
689 self.servicelist.moveDown()
690 if self.isPlayable():
691 current = ServiceReference(self.servicelist.getCurrentSelection())
692 self.playService(current.ref)
696 def prevService(self):
697 if self.servicelist is not None:
698 # get previous service
699 if self.servicelist.inBouquet():
700 prev = self.servicelist.getCurrentSelection()
702 prev = prev.toString()
704 if config.usage.quickzap_bouquet_change.value:
705 if self.servicelist.atBegin():
706 self.servicelist.prevBouquet()
707 self.servicelist.moveUp()
708 cur = self.servicelist.getCurrentSelection()
709 if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
712 self.servicelist.moveUp()
713 if self.isPlayable():
714 current = ServiceReference(self.servicelist.getCurrentSelection())
715 self.playService(current.ref)
719 def isPlayable(self):
720 # check if service is playable
721 current = ServiceReference(self.servicelist.getCurrentSelection())
722 return not (current.ref.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
725 def nextBouquet(self):
726 if self.servicelist is not None:
727 # next bouquet with first service
728 if config.usage.multibouquet.value:
729 self.servicelist.nextBouquet()
730 current = ServiceReference(self.servicelist.getCurrentSelection())
731 self.playService(current.ref)
733 def prevBouquet(self):
734 if self.servicelist is not None:
735 # previous bouquet with first service
736 if config.usage.multibouquet.value:
737 self.servicelist.prevBouquet()
738 current = ServiceReference(self.servicelist.getCurrentSelection())
739 self.playService(current.ref)
741 def openSingleServiceEPG(self):
743 current = ServiceReference(self.servicelist.getCurrentSelection())
744 self.session.open(EPGSelection, current.ref)
746 def openEventView(self):
749 self.epglist = epglist
750 service = ServiceReference(self.servicelist.getCurrentSelection())
752 evt = self.epgcache.lookupEventTime(ref, -1)
755 evt = self.epgcache.lookupEventTime(ref, -1, 1)
759 self.session.open(EventViewEPGSelect, epglist[0], service, self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
761 def eventViewCallback(self, setEvent, setService, val):
762 epglist = self.epglist
765 epglist[0] = epglist[1]
769 def openMultiServiceEPG(self):
773 def openSimilarList(self, eventid, refstr):
774 self.session.open(EPGSelection, refstr, None, eventid)
776 def playService(self, service):
777 if service and (service.flags & eServiceReference.isGroup):
778 ref = getBestPlayableServiceReference(service, eServiceReference())
781 self.pipservice = eServiceCenter.getInstance().play(ref)
782 if self.pipservice and not self.pipservice.setTarget(1):
783 self.pipservice.start()
786 self.pipservice = None
787 if self.showHideTimer.isActive():
788 self.showHideTimer.stop()
792 class MerlinMusicPlayerScreen(Screen, InfoBarBase, InfoBarSeek, InfoBarNotifications):
794 sz_w = getDesktop(0).size().width()
797 <screen name="MerlinMusicPlayerScreen" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
798 <eLabel backgroundColor="#999999" position="178,112" size="924,2" zPosition="1"/>
799 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="178,104" size="250,20" text="MERLIN MUSIC PLAYER" valign="center" zPosition="2"/>
800 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="852,104" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
801 <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmp3pHD.png" position="128,72" size="1024,576"/>
802 <widget name="coverArt" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/no_coverArt.png" position="328,149" size="238,238" transparent="1" alphatest="blend" />
803 <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr.png" position="688,232" size="150,20" transparent="1" zPosition="1"/>
804 <widget name="title" position="362,415" size="600,28" zPosition="1" transparent="1" font="Regular;24" foregroundColor="#fcc000" />
805 <widget name="album" position="362,462" size="600,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
806 <widget name="artist" position="362,492" size="600,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
807 <widget name="genre" position="362,522" size="600,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
808 <widget name="nextTitle" position="362,562" size="600,22" zPosition="1" transparent="1" font="Regular;16" foregroundColor="#f0f0f0" />
809 <widget name="PositionGauge" position="664,264" size="198,14" pointer="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/progressbar.png:198,0" seek_pointer="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/progressbar.png:198,0" transparent="1"/>
810 <widget source="session.CurrentService" render="Label" position="873,267" size="116,18" zPosition="1" font="Regular;18" halign="left" foregroundColor="#999999" transparent="1" >
811 <convert type="ServicePosition">Length,ShowHours</convert>
813 <widget source="session.CurrentService" render="Label" position="684,292" size="198,20" zPosition="1" font="Regular;20" halign="left" foregroundColor="#fcc000" transparent="1" >
814 <convert type="ServicePosition">Position,ShowHours</convert>
816 <widget name="shuffle" pixmaps="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/placeholder1.png,/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr_shuf.png" position="598,275" size="53,34" transparent="1" alphatest="on"/>
817 <widget name="repeat" pixmaps="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/placeholder1.png,/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr_rep.png" position="598,239" size="53,34" transparent="1" alphatest="on"/>
818 <widget name="dvrStatus" pixmaps="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr_pl.png,/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr_pau.png" position="683,227" size="160,39" transparent="1" alphatest="on"/>
822 <screen name="MerlinMusicPlayerScreen" position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
823 <eLabel backgroundColor="#999999" position="50,40" size="924,2" zPosition="1"/>
824 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,32" size="250,20" text="MERLIN MUSIC PLAYER" valign="center" zPosition="2"/>
825 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="724,32" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
826 <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmp3pHD.png" position="0,0" size="1024,576"/>
827 <widget name="coverArt" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/no_coverArt.png" position="200,77" size="238,238" transparent="1" alphatest="blend" />
828 <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr.png" position="560,160" size="150,20" transparent="1" zPosition="1"/>
829 <widget name="title" position="234,343" size="600,28" zPosition="1" transparent="1" font="Regular;24" foregroundColor="#fcc000" />
830 <widget name="album" position="234,390" size="600,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
831 <widget name="artist" position="234,420" size="600,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
832 <widget name="genre" position="234,450" size="600,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
833 <widget name="nextTitle" position="234,490" size="600,22" zPosition="1" transparent="1" font="Regular;16" foregroundColor="#f0f0f0" />
834 <widget name="PositionGauge" position="536,197" size="198,14" pointer="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/progressbar.png:198,0" seek_pointer="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/progressbar.png:198,0" transparent="1"/>
835 <widget source="session.CurrentService" render="Label" position="745,195" size="116,18" zPosition="1" font="Regular;18" halign="left" foregroundColor="#999999" transparent="1" >
836 <convert type="ServicePosition">Length,ShowHours</convert>
838 <widget source="session.CurrentService" render="Label" position="556,220" size="198,20" zPosition="1" font="Regular;20" halign="left" foregroundColor="#fcc000" transparent="1" >
839 <convert type="ServicePosition">Position,ShowHours</convert>
841 <widget name="shuffle" pixmaps="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/placeholder1.png,/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr_shuf.png" position="470,203" size="53,34" transparent="1" alphatest="on"/>
842 <widget name="repeat" pixmaps="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/placeholder1.png,/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr_rep.png" position="470,167" size="53,34" transparent="1" alphatest="on"/>
843 <widget name="dvrStatus" pixmaps="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr_pl.png,/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr_pau.png" position="555,155" size="160,39" transparent="1" alphatest="on"/>
847 <screen name="MerlinMusicPlayerScreen" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
848 <eLabel backgroundColor="#999999" position="50,50" size="620,2" zPosition="1"/>
849 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,40" size="250,20" text="MERLIN MUSIC PLAYER" valign="center" zPosition="2"/>
850 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="420,40" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
851 <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmp3p.png" position="120,350" size="33,162"/>
852 <widget name="coverArt" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/no_coverArt.png" position="106,130" size="180,180" transparent="1" alphatest="blend" />
853 <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr.png" position="410,160" size="150,20" transparent="1" zPosition="1"/>
854 <widget name="title" position="160,345" size="550,28" zPosition="1" transparent="1" font="Regular;24" foregroundColor="#fcc000" />
855 <widget name="album" position="160,392" size="550,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
856 <widget name="artist" position="160,422" size="550,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
857 <widget name="genre" position="160,455" size="550,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
858 <widget name="nextTitle" position="160,492" size="550,22" zPosition="1" transparent="1" font="Regular;16" foregroundColor="#f0f0f0" />
859 <widget name="PositionGauge" position="386,197" size="198,14" pointer="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/progressbar.png:198,0" seek_pointer="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/progressbar.png:198,0" transparent="1"/>
860 <widget source="session.CurrentService" render="Label" position="595,193" size="116,18" zPosition="1" font="Regular;18" halign="left" foregroundColor="#999999" transparent="1" >
861 <convert type="ServicePosition">Length,ShowHours</convert>
863 <widget source="session.CurrentService" render="Label" position="406,220" size="198,20" zPosition="1" font="Regular;20" halign="left" foregroundColor="#fcc000" transparent="1" >
864 <convert type="ServicePosition">Position,ShowHours</convert>
866 <widget name="shuffle" pixmaps="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/placeholder1.png,/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr_shuf.png" position="320,203" size="53,34" transparent="1" alphatest="on"/>
867 <widget name="repeat" pixmaps="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/placeholder1.png,/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr_rep.png" position="320,167" size="53,34" transparent="1" alphatest="on"/>
868 <widget name="dvrStatus" pixmaps="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr_pl.png,/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr_pau.png" position="405,155" size="160,39" transparent="1" alphatest="on"/>
871 def __init__(self, session, songlist, index, idreammode, currentservice, servicelist):
872 self.session = session
873 Screen.__init__(self, session)
874 InfoBarNotifications.__init__(self)
875 InfoBarBase.__init__(self)
876 self["actions"] = ActionMap(["WizardActions", "MediaPlayerActions", "EPGSelectActions", "MediaPlayerSeekActions", "ColorActions"],
878 "back": self.closePlayer,
879 "pause": self.pauseEntry,
880 "stop": self.stopEntry,
881 "right": self.playNext,
882 "left": self.playPrevious,
883 "up": self.showPlaylist,
884 "down" : self.showPlaylist,
885 "prevBouquet": self.shuffleList,
886 "nextBouquet": self.repeatSong,
887 "info" : self.showLyrics,
888 "yellow": self.pauseEntry,
890 "input_date_time": self.config,
894 self.onClose.append(self.__onClose)
895 self.session.nav.stopService()
896 self["PositionGauge"] = ServicePositionGauge(self.session.nav)
897 self["coverArt"] = MerlinMediaPixmap()
898 self["repeat"] = MultiPixmap()
899 self["shuffle"] = MultiPixmap()
900 self["dvrStatus"] = MultiPixmap()
901 self["title"] = Label()
902 self["album"] = Label()
903 self["artist"] = Label()
904 self["genre"] = Label()
905 self["nextTitle"] = Label()
906 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
908 iPlayableService.evUpdatedInfo: self.__evUpdatedInfo,
909 iPlayableService.evUser+10: self.__evAudioDecodeError,
910 iPlayableService.evUser+12: self.__evPluginError,
911 iPlayableService.evUser+13: self.embeddedCoverArt,
912 iPlayableService.evStart: self.__serviceStarted,
915 InfoBarSeek.__init__(self, actionmap = "MediaPlayerSeekActions")
916 self.songList = songlist
917 self.origSongList = songlist[:]
918 self.currentIndex = index
921 self.currentFilename = ""
922 self.currentGoogleCoverFile = ""
923 self.googleDownloadDir = os_path.join(config.plugins.merlinmusicplayer.googleimagepath.value, "downloaded_covers/" )
924 if not os_path.exists(self.googleDownloadDir):
926 os_mkdir(self.googleDownloadDir)
928 self.googleDownloadDir = "/tmp/"
931 self.onShown.append(self.__onShown)
933 self.currentTitle = ""
935 self.screenSaverTimer = eTimer()
936 self.screenSaverTimer.timeout.get().append(self.screenSaverTimerTimeout)
937 self.screenSaverScreen = None
939 self.iDreamMode = idreammode
940 self.currentService = currentservice
941 self.serviceList = servicelist
943 def embeddedCoverArt(self):
944 self["coverArt"].embeddedCoverArt()
945 if self.screenSaverScreen:
946 self.screenSaverScreen.updateCover(modus = 2)
948 def screenSaverTimerTimeout(self):
949 if config.plugins.merlinmusicplayer.usescreensaver.value:
950 if self.screenSaverTimer.isActive():
951 self.screenSaverTimer.stop()
952 if not self.screenSaverScreen:
953 self.screenSaverScreen = self.session.instantiateDialog(MerlinMusicPlayerScreenSaver)
954 self.session.execDialog(self.screenSaverScreen)
955 self.screenSaverScreen.updateLCD(self.currentTitle,1)
956 self.screenSaverScreen.updateLCD(self.nextTitle,4)
957 album = self["album"].getText()
959 text = "%s - %s" % (self["title"].getText(), album)
961 text = self["title"].getText()
962 self.screenSaverScreen.updateDisplayText(text)
963 self.screenSaverScreen.updateCover(self["coverArt"].coverArtFileName, modus = 0)
965 def resetScreenSaverTimer(self):
966 if config.plugins.merlinmusicplayer.usescreensaver.value and config.plugins.merlinmusicplayer.screensaverwait.value != 0:
967 if self.screenSaverTimer.isActive():
968 self.screenSaverTimer.stop()
969 self.screenSaverTimer.start(config.plugins.merlinmusicplayer.screensaverwait.value * 60000)
974 self["coverArt"].onShow()
975 self.playSong(self.songList[self.currentIndex][0].filename)
977 self.summaries.setText(self.currentTitle,1)
978 self.summaries.setText(self.nextTitle,4)
979 if self.screenSaverScreen:
980 self.screenSaverScreen.doClose()
981 self.screenSaverScreen = None
982 self.resetScreenSaverTimer()
985 del self["coverArt"].picload
989 if self.screenSaverTimer.isActive():
990 self.screenSaverTimer.stop()
991 self.session.openWithCallback(self.setupFinished, MerlinMusicPlayerSetup, False)
994 if SystemInfo.get("NumVideoDecoders", 1) > 1:
995 if self.screenSaverTimer.isActive():
996 self.screenSaverTimer.stop()
997 if self.screenSaverScreen:
998 self.screenSaverScreen.doClose()
999 self.screenSaverScreen = None
1000 self.screenSaverScreen = self.session.instantiateDialog(MerlinMusicPlayerTV, self.currentService, self.serviceList)
1001 self.session.execDialog(self.screenSaverScreen)
1002 self.screenSaverScreen.updateLCD(self.currentTitle,1)
1003 self.screenSaverScreen.updateLCD(self.nextTitle,4)
1004 album = self["album"].getText()
1006 text = "%s - %s" % (self["title"].getText(), album)
1008 text = self["title"].getText()
1009 self.screenSaverScreen.updateDisplayText(text)
1010 self.screenSaverScreen.updateCover(self["coverArt"].coverArtFileName, modus = 0)
1012 def setupFinished(self, result):
1014 self.googleDownloadDir = os_path.join(config.plugins.merlinmusicplayer.googleimagepath.value, "downloaded_covers/" )
1015 if not os_path.exists(self.googleDownloadDir):
1017 os_mkdir(self.googleDownloadDir)
1019 self.googleDownloadDir = "/tmp/"
1020 self.resetScreenSaverTimer()
1022 def closePlayer(self):
1023 if config.plugins.merlinmusicplayer.startlastsonglist.value:
1024 config.plugins.merlinmusicplayer.lastsonglistindex.value = self.currentIndex
1025 config.plugins.merlinmusicplayer.lastsonglistindex.save()
1026 connection = OpenDatabase()
1027 if connection is not None:
1028 connection.text_factory = str
1029 cursor = connection.cursor()
1030 cursor.execute("Delete from CurrentSongList;")
1031 for song in self.origSongList:
1032 cursor.execute("INSERT INTO CurrentSongList (song_id, filename,title,artist,album,genre, bitrate, length, track, date, PTS) VALUES(?,?,?,?,?,?,?,?,?,?,?);" , (song[0].songID, song[0].filename,song[0].title,song[0].artist,song[0].album,song[0].genre, song[0].bitrate, song[0].length, song[0].track, song[0].date, song[0].PTS))
1036 if self.screenSaverTimer.isActive():
1037 self.screenSaverTimer.stop()
1040 def playSong(self, filename):
1041 self.session.nav.stopService()
1043 self.currentFilename = filename
1044 if not config.plugins.merlinmusicplayer.hardwaredecoder.value and self.currentFilename.lower().endswith(".mp3") and self.songList[self.currentIndex][0].PTS is None:
1045 sref = eServiceReference(ENIGMA_MERLINPLAYER_ID, 0, self.currentFilename) # play mp3 file with merlinmp3player lib
1046 self.session.nav.playService(sref)
1048 self.updateMusicInformation( self.songList[self.currentIndex][0].artist, self.songList[self.currentIndex][0].title,
1049 self.songList[self.currentIndex][0].album, self.songList[self.currentIndex][0].genre, self.songList[self.currentIndex][0].date, clear = True )
1051 path,filename = os_path.split(self.currentFilename)
1052 audio, isAudio, title, genre,artist,album,tracknr,track,date,length,bitrate = getID3Tags(path,filename)
1055 year = "(%s)" % str(date)
1058 self.updateMusicInformation( artist, title, album, genre, year, clear = True )
1060 self.updateMusicInformation( title = title, clear = True)
1063 sref = eServiceReference(4097, 0, self.currentFilename)
1064 self.session.nav.playService(sref)
1065 if self.songList[self.currentIndex][0].PTS is not None:
1066 service = self.session.nav.getCurrentService()
1068 self.seek = service.seek()
1069 self.updateMusicInformationCUE()
1070 self.ptsTimer = eTimer()
1071 self.ptsTimer.callback.append(self.ptsTimerCallback)
1072 self.ptsTimer.start(1000)
1073 self["nextTitle"].setText(self.getNextTitle())
1075 def ptsTimerCallback(self):
1077 pts = self.seek.getPlayPosition()
1080 for songs in self.songList:
1081 if pts[1] > songs[0].PTS:
1082 currentIndex = index
1086 if currentIndex != self.currentIndex:
1087 self.currentIndex = currentIndex
1088 self.updateMusicInformationCUE()
1089 self.ptsTimer.start(1000)
1091 def updateMusicInformationCUE(self):
1092 self.updateSingleMusicInformation("artist", self.songList[self.currentIndex][0].artist, True)
1093 self.updateSingleMusicInformation("title", self.songList[self.currentIndex][0].title, True)
1094 self.updateSingleMusicInformation("album", self.songList[self.currentIndex][0].album, True)
1095 self.summaries.setText(self.songList[self.currentIndex][0].title,1)
1096 if self.screenSaverScreen:
1097 self.screenSaverScreen.updateLCD(self.songList[self.currentIndex][0].title,1)
1098 if self.songList[self.currentIndex][0].album:
1099 self.screenSaverScreen.updateDisplayText("%s - %s" % (self.songList[self.currentIndex][0].title,self.songList[self.currentIndex][0].album))
1101 self.screenSaverScreen.updateDisplayText(self.songList[self.currentIndex][0].title)
1102 self.updateCover(self.songList[self.currentIndex][0].artist, self.songList[self.currentIndex][0].album)
1103 self.currentTitle = self.songList[self.currentIndex][0].title
1104 self["nextTitle"].setText(self.getNextTitle())
1106 def __serviceStarted(self):
1107 self["dvrStatus"].setPixmapNum(0)
1109 def __evUpdatedInfo(self):
1110 currPlay = self.session.nav.getCurrentService()
1111 if currPlay is not None:
1112 sTitle = currPlay.info().getInfoString(iServiceInformation.sTagTitle)
1113 sAlbum = currPlay.info().getInfoString(iServiceInformation.sTagAlbum)
1114 sArtist = currPlay.info().getInfoString(iServiceInformation.sTagArtist)
1115 sGenre = currPlay.info().getInfoString(iServiceInformation.sTagGenre)
1116 sYear = currPlay.info().getInfoString(iServiceInformation.sTagDate)
1118 sYear = "(%s)" % sYear
1120 sTitle = os_path.splitext(os_path.basename(self.currentFilename))[0]
1122 if self.songList[self.currentIndex][0].PTS is None:
1123 self.updateMusicInformation( sArtist, sTitle, sAlbum, sGenre, sYear, clear = True )
1125 self.updateSingleMusicInformation("genre", sGenre, True)
1127 self.updateMusicInformation()
1129 def updateMusicInformation(self, artist = "", title = "", album = "", genre = "", year = "", clear = False):
1131 album = "%s %s" % (album, year)
1132 self.updateSingleMusicInformation("artist", artist, clear)
1133 self.updateSingleMusicInformation("title", title, clear)
1134 self.updateSingleMusicInformation("album", album, clear)
1135 self.updateSingleMusicInformation("genre", genre, clear)
1136 self.currentTitle = title
1137 if not self.iDreamMode and self.songList[self.currentIndex][0].PTS is None:
1139 self.songList[self.currentIndex][0].title = title
1140 self.songList[self.currentIndex][0].artist = artist
1141 self.summaries.setText(title,1)
1142 if self.screenSaverScreen:
1143 self.screenSaverScreen.updateLCD(title,1)
1145 self.screenSaverScreen.updateDisplayText("%s - %s" % (title,album))
1147 self.screenSaverScreen.updateDisplayText(title)
1148 self.updateCover(artist, album)
1150 def updateCover(self, artist, album):
1154 if self.currentFilename.lower().endswith(".mp3"):
1156 audio = ID3(self.currentFilename)
1158 except: audio = None
1159 elif self.currentFilename.lower().endswith(".flac"):
1161 audio = FLAC(self.currentFilename)
1163 except: audio = None
1164 elif self.currentFilename.lower().endswith(".m4a"):
1166 audio = MP4(self.currentFilename)
1168 except: audio = None
1169 elif self.currentFilename.lower().endswith(".ogg"):
1171 audio = OggVorbis(self.currentFilename)
1173 except: audio = None
1176 apicframes = audio.getall("APIC")
1177 if len(apicframes) >= 1:
1179 if not config.plugins.merlinmusicplayer.hardwaredecoder.value:
1180 coverArtFile = file("/tmp/.id3coverart", 'wb')
1181 coverArtFile.write(apicframes[0].data)
1182 coverArtFile.close()
1183 self["coverArt"].embeddedCoverArt()
1184 if self.screenSaverScreen:
1185 self.screenSaverScreen.updateCover(modus = 2)
1186 elif audiotype == 2:
1187 if len(audio.pictures) >= 1:
1189 elif audiotype == 3:
1190 if 'covr' in audio.tags:
1192 elif audiotype == 4:
1193 if 'METADATA_BLOCK_PICTURE' in audio.tags:
1197 if not self["coverArt"].updateCoverArt(self.currentFilename):
1198 if config.plugins.merlinmusicplayer.usegoogleimage.value:
1199 self.getGoogleCover(artist, album)
1201 self["coverArt"].showDefaultCover()
1202 if self.screenSaverScreen:
1203 self.screenSaverScreen.updateCover(modus = 1)
1205 if self.screenSaverScreen:
1206 self.screenSaverScreen.updateCover(filename = self.currentFilename, modus = 3)
1207 self.currentGoogleCoverFile = ""
1209 self.currentGoogleCoverFile = ""
1211 def updateSingleMusicInformation(self, name, info, clear):
1212 if info != "" or clear:
1213 if self[name].getText() != info:
1214 self[name].setText(info)
1216 def getGoogleCover(self, artist,album):
1217 if artist != "" and album != "":
1218 url = "http://images.google.de/images?q=%s+%s&btnG=Bilder-Suche" % (quote(album),quote(artist))
1219 sendUrlCommand(url, None,10).addCallback(self.googleImageCallback).addErrback(self.coverDownloadFailed)
1221 self["coverArt"].showDefaultCover()
1223 def googleImageCallback(self, result):
1224 foundPos = result.find("imgres?imgurl=")
1225 foundPos2 = result.find("&imgrefurl=")
1226 if foundPos != -1 and foundPos2 != -1:
1227 url = result[foundPos+14:foundPos2]
1228 parts = url.split("/")
1229 filename = parts[-1]
1230 if filename != self.currentGoogleCoverFile:
1231 self.currentGoogleCoverFile = filename
1232 filename = self.googleDownloadDir + parts[-1]
1233 if os_path.exists(filename):
1234 print "[MerlinMusicPlayer] using cover from %s " % filename
1235 self["coverArt"].showCoverFromFile(filename)
1236 if self.screenSaverScreen:
1237 self.screenSaverScreen.updateCover(filename = filename, modus = 4)
1239 print "[MerlinMusicPlayer] downloading cover from %s " % url
1240 downloadPage(url , self.googleDownloadDir + parts[-1]).addCallback(boundFunction(self.coverDownloadFinished, filename)).addErrback(self.coverDownloadFailed)
1242 def coverDownloadFailed(self,result):
1243 print "[MerlinMusicPlayer] cover download failed: %s " % result
1244 self["coverArt"].showDefaultCover()
1245 if self.screenSaverScreen:
1246 self.screenSaverScreen.updateCover(modus = 1)
1248 def coverDownloadFinished(self,filename, result):
1249 print "[MerlinMusicPlayer] cover download finished"
1250 self["coverArt"].showCoverFromFile(filename)
1251 if self.screenSaverScreen:
1252 self.screenSaverScreen.updateCover(filename = filename, modus = 4)
1254 def __evAudioDecodeError(self):
1255 currPlay = self.session.nav.getCurrentService()
1256 sAudioType = currPlay.info().getInfoString(iServiceInformation.sUser+10)
1257 print "[MerlinMusicPlayer] audio-codec %s can't be decoded by hardware" % (sAudioType)
1258 self.session.open(MessageBox, _("This Dreambox can't decode %s streams!") % sAudioType, type = MessageBox.TYPE_INFO,timeout = 20 )
1260 def __evPluginError(self):
1261 currPlay = self.session.nav.getCurrentService()
1262 message = currPlay.info().getInfoString(iServiceInformation.sUser+12)
1263 print "[MerlinMusicPlayer]" , message
1264 self.session.open(MessageBox, message, type = MessageBox.TYPE_INFO,timeout = 20 )
1266 def doEofInternal(self, playing):
1270 def checkSkipShowHideLock(self):
1271 self.updatedSeekState()
1273 def updatedSeekState(self):
1274 if self.seekstate == self.SEEK_STATE_PAUSE:
1275 self["dvrStatus"].setPixmapNum(1)
1276 elif self.seekstate == self.SEEK_STATE_PLAY:
1277 self["dvrStatus"].setPixmapNum(0)
1279 def pauseEntry(self):
1281 self.resetScreenSaverTimer()
1284 #play the current song from beginning again
1285 if self.songList[self.currentIndex][0].PTS is None:
1286 self.playSong(self.songList[self.currentIndex][0].filename)
1289 self.seek.seekTo(self.songList[self.currentIndex][0].PTS)
1290 self.updatedSeekState()
1291 self.resetScreenSaverTimer()
1293 def unPauseService(self):
1294 self.setSeekState(self.SEEK_STATE_PLAY)
1296 def stopEntry(self):
1298 self.session.nav.stopService()
1299 self.origSongList = []
1301 if config.plugins.merlinmusicplayer.startlastsonglist.value:
1302 config.plugins.merlinmusicplayer.lastsonglistindex.value = -1
1303 config.plugins.merlinmusicplayer.lastsonglistindex.save()
1304 connection = OpenDatabase()
1305 if connection is not None:
1306 connection.text_factory = str
1307 cursor = connection.cursor()
1308 cursor.execute("Delete from CurrentSongList;")
1312 self.resetScreenSaverTimer()
1317 if self.currentIndex +1 > len(self.songList) -1:
1318 self.currentIndex = 0
1320 self.currentIndex += 1
1321 if self.songList[self.currentIndex][0].PTS is None:
1322 self.playSong(self.songList[self.currentIndex][0].filename)
1325 if not self.screenSaverScreen:
1326 self.resetScreenSaverTimer()
1328 def playPrevious(self):
1330 if self.currentIndex - 1 < 0:
1331 self.currentIndex = len(self.songList) - 1
1333 self.currentIndex -= 1
1335 if self.songList[self.currentIndex][0].PTS is None:
1336 self.playSong(self.songList[self.currentIndex][0].filename)
1339 self.resetScreenSaverTimer()
1341 def getNextTitle(self):
1343 index = self.currentIndex
1345 if self.currentIndex + 1 > len(self.songList) -1:
1348 index = self.currentIndex + 1
1349 if self.iDreamMode or self.songList[index][0].PTS is not None:
1350 text = "%s - %s" % (self.songList[index][0].title, self.songList[index][0].artist)
1352 if self.songList[index][0].filename.lower().startswith("http://"):
1353 text = self.songList[index][0].filename
1355 path,filename = os_path.split(self.songList[index][0].filename)
1356 audio, isAudio, title, genre,artist,album,tracknr,track,date,length,bitrate = getID3Tags(path,filename)
1359 text = "%s - %s" % (title, artist)
1365 self.nextTitle = text
1366 self.summaries.setText(text,4)
1367 if self.screenSaverScreen:
1368 self.screenSaverScreen.updateLCD(text,4)
1371 def shuffleList(self):
1372 if self.songList[self.currentIndex][0].PTS is None: # not implemented for cue files yet
1373 self.shuffle = not self.shuffle
1375 self["shuffle"].setPixmapNum(1)
1376 shuffle(self.songList)
1378 self.songList = self.origSongList[:]
1379 self["shuffle"].setPixmapNum(0)
1381 for x in self.songList:
1382 if x[0].filename == self.currentFilename:
1383 self.currentIndex = index
1386 self["nextTitle"].setText(self.getNextTitle())
1388 self.session.open(MessageBox, _("Shuffle is not available yet with cue-files!"), type = MessageBox.TYPE_INFO,timeout = 20 )
1389 self.resetScreenSaverTimer()
1391 def repeatSong(self):
1392 if self.songList[self.currentIndex][0].PTS is None: # not implemented for cue files yet
1393 self.repeat = not self.repeat
1395 self["repeat"].setPixmapNum(1)
1397 self["repeat"].setPixmapNum(0)
1398 self["nextTitle"].setText(self.getNextTitle())
1400 self.session.open(MessageBox, _("Repeat is not available yet with cue-files!"), type = MessageBox.TYPE_INFO,timeout = 20 )
1401 self.resetScreenSaverTimer()
1403 def showPlaylist(self):
1404 if self.screenSaverTimer.isActive():
1405 self.screenSaverTimer.stop()
1406 self.session.openWithCallback(self.showPlaylistCallback, MerlinMusicPlayerSongList, self.songList, self.currentIndex, self.iDreamMode)
1408 def showPlaylistCallback(self, index):
1410 self.currentIndex = index
1412 if self.songList[self.currentIndex][0].PTS is None:
1413 self.playSong(self.songList[self.currentIndex][0].filename)
1417 self.resetScreenSaverTimer()
1419 def playCUETrack(self):
1420 if self.ptsTimer.isActive():
1421 self.ptsTimer.stop()
1423 self.seek.seekTo(self.songList[self.currentIndex][0].PTS)
1424 self.updatedSeekState()
1425 self.updateMusicInformationCUE()
1426 self.ptsTimer.start(1000)
1428 def showLyrics(self):
1429 if self.screenSaverTimer.isActive():
1430 self.screenSaverTimer.stop()
1431 self.session.openWithCallback(self.resetScreenSaverTimer, MerlinMusicPlayerLyrics, self.songList[self.currentIndex][0])
1433 def createSummary(self):
1434 return MerlinMusicPlayerLCDScreen
1436 class MerlinMusicPlayerLyrics(Screen):
1438 sz_w = getDesktop(0).size().width()
1441 <screen name="MerlinMusicPlayerLyrics" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="Merlin Music Player Lyrics">
1442 <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmpborderHD.png" position="128,72" size="1024,576"/>
1443 <eLabel backgroundColor="#999999" position="178,112" size="924,2" zPosition="1"/>
1444 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="178,104" size="250,20" text="MERLIN MUSIC PLAYER" valign="center" zPosition="2"/>
1445 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="852,104" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
1446 <widget name="headertext" position="178,145" zPosition="1" size="900,23" font="Regular;20" transparent="1" foregroundColor="#fcc000" backgroundColor="#00000000"/>
1447 <widget name="resulttext" position="178,172" zPosition="1" size="900,20" font="Regular;16" transparent="1" backgroundColor="#00000000"/>
1448 <widget name="lyric_text" position="178,222" zPosition="2" size="940,350" font="Regular;18" transparent="0" backgroundColor="#00000000"/>
1452 <screen name="MerlinMusicPlayerLyrics" position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="Merlin Music Player Lyrics">
1453 <eLabel backgroundColor="#999999" position="50,40" size="924,2" zPosition="1"/>
1454 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,32" size="250,20" text="MERLIN MUSIC PLAYER" valign="center" zPosition="2"/>
1455 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="724,32" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
1456 <widget name="headertext" position="50,73" zPosition="1" size="900,23" font="Regular;20" transparent="1" foregroundColor="#fcc000" backgroundColor="#00000000"/>
1457 <widget name="resulttext" position="50,100" zPosition="1" size="900,20" font="Regular;16" transparent="1" backgroundColor="#00000000"/>
1458 <widget name="lyric_text" position="50,150" zPosition="2" size="940,350" font="Regular;18" transparent="0" backgroundColor="#00000000"/>
1462 <screen name="MerlinMusicPlayerLyrics" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="Merlin Music Player Lyrics">
1463 <eLabel backgroundColor="#999999" position="50,50" size="620,2" zPosition="1"/>
1464 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,40" size="250,20" text="MERLIN MUSIC PLAYER" valign="center" zPosition="2"/>
1465 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="420,40" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
1466 <widget name="headertext" position="50,73" zPosition="1" size="620,23" font="Regular;20" transparent="1" foregroundColor="#fcc000" backgroundColor="#00000000"/>
1467 <widget name="resulttext" position="50,100" zPosition="1" size="620,20" font="Regular;16" transparent="1" backgroundColor="#00000000"/>
1468 <widget name="lyric_text" position="50,150" zPosition="2" size="620,350" font="Regular;18" transparent="0" backgroundColor="#00000000"/>
1472 def __init__(self, session, currentsong):
1473 self.session = session
1474 Screen.__init__(self, session)
1475 self["headertext"] = Label(_("Merlin Music Player Lyrics"))
1476 # leoslyrics does not work anymore
1477 # self["resulttext"] = Label(_("Getting lyrics from api.leoslyrics.com..."))
1478 self["resulttext"] = Label()
1479 self["actions"] = ActionMap(["WizardActions", "DirectionActions"],
1482 "upUp": self.pageUp,
1483 "leftUp": self.pageUp,
1484 "downUp": self.pageDown,
1485 "rightUp": self.pageDown,
1487 self["lyric_text"] = ScrollLabel()
1488 self.currentSong = currentsong
1489 self.onLayoutFinish.append(self.startRun)
1492 # leoslyrics does not work anymore
1493 #url = "http://api.leoslyrics.com/api_search.php?auth=duane&artist=%s&songtitle=%s" % (quote(self.currentSong.artist), quote(self.currentSong.title))
1494 #sendUrlCommand(url, None,10).addCallback(self.getHID).addErrback(self.urlError)
1495 # get lyric-text from id3 tag
1497 audio = ID3(self.currentSong.filename)
1501 text = getEncodedString(self.getLyricsFromID3Tag(audio)).replace("\r\n","\n")
1502 text = text.replace("\r","\n")
1503 self["lyric_text"].setText(text)
1505 self["lyric_text"].setText("No lyrics found")
1507 def getLyricsFromID3Tag(self,tag):
1508 for frame in tag.values():
1509 if frame.FrameID == "USLT":
1511 return "No lyrics found in id3-tag"
1514 def urlError(self, error = None):
1515 if error is not None:
1516 self["resulttext"].setText(str(error.getErrorMessage()))
1518 def getHID(self, xmlstring):
1519 root = cet_fromstring(xmlstring)
1521 child = root.find("searchResults")
1523 child2 = child.find("result")
1525 url = "http://api.leoslyrics.com/api_lyrics.php?auth=duane&hid=%s" % quote(child2.get("hid"))
1526 sendUrlCommand(url, None,10).addCallback(self.getLyrics).addErrback(self.urlError)
1528 self["resulttext"].setText(_("No lyrics found"))
1530 def getLyrics(self, xmlstring):
1531 root = cet_fromstring(xmlstring)
1533 child = root.find("lyric")
1535 title = child.findtext("title").encode("utf-8", 'ignore')
1536 child2 = child.find("artist")
1538 artist = child2.findtext("name").encode("utf-8", 'ignore')
1541 lyrictext = child.findtext("text").encode("utf-8", 'ignore')
1542 self["lyric_text"].setText(lyrictext)
1543 result = _("Response -> lyrics for: %s (%s)") % (title,artist)
1544 self["resulttext"].setText(result)
1546 self["resulttext"].setText(_("No lyrics found"))
1549 self["lyric_text"].pageUp()
1552 self["lyric_text"].pageDown()
1554 class MerlinMusicPlayerSongList(Screen):
1556 sz_w = getDesktop(0).size().width()
1559 <screen name="MerlinMusicPlayerSongList" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="Songlist">
1560 <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmpborderHD.png" position="128,72" size="1024,576"/>
1561 <eLabel backgroundColor="#999999" position="178,112" size="924,2" zPosition="1"/>
1562 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="178,104" size="250,20" text="MERLIN MUSIC PLAYER" valign="center" zPosition="2"/>
1563 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="852,104" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
1564 <widget name="headertext" position="178,145" zPosition="1" size="900,23" font="Regular;20" transparent="1" foregroundColor="#fcc000" backgroundColor="#00000000"/>
1565 <widget name="list" position="178,182" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0" backgroundColor="#00000000"/>
1569 <screen name="MerlinMusicPlayerSongList" position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="Songlist">
1570 <eLabel backgroundColor="#999999" position="50,40" size="924,2" zPosition="1"/>
1571 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,32" size="250,20" text="MERLIN MUSIC PLAYER" valign="center" zPosition="2"/>
1572 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="724,32" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
1573 <widget name="headertext" position="50,73" zPosition="1" size="900,23" font="Regular;20" transparent="1" foregroundColor="#fcc000" backgroundColor="#00000000"/>
1574 <widget name="list" position="50,110" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0" backgroundColor="#00000000"/>
1578 <screen name="MerlinMusicPlayerSongList" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="Songlist">
1579 <eLabel backgroundColor="#999999" position="50,50" size="620,2" zPosition="1"/>
1580 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,40" size="250,20" text="MERLIN MUSIC PLAYER" valign="center" zPosition="2"/>
1581 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="420,40" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
1582 <widget name="headertext" position="50,73" zPosition="1" size="620,23" font="Regular;20" transparent="1" foregroundColor="#fcc000" backgroundColor="#00000000"/>
1583 <widget name="list" position="50,110" zPosition="2" size="620,350" scrollbarMode="showOnDemand" transparent="0" backgroundColor="#00000000"/>
1587 def __init__(self, session, songlist, index, idreammode):
1588 self.session = session
1589 Screen.__init__(self, session)
1590 self["headertext"] = Label(_("Merlin Music Player Songlist"))
1591 self["list"] = iDreamList()
1592 self["list"].connectSelChanged(self.lcdUpdate)
1593 self["actions"] = ActionMap(["WizardActions"],
1596 "back": self.closing,
1598 self.songList = songlist
1600 self.iDreamMode = idreammode
1601 self.onLayoutFinish.append(self.startRun)
1602 self.onShown.append(self.lcdUpdate)
1606 self["list"].setMode(10) # songlist
1607 self["list"].setList(self.songList)
1608 self["list"].moveToIndex(self.index)
1611 self.close(self["list"].getCurrentIndex())
1616 def lcdUpdate(self):
1618 index = self["list"].getCurrentIndex()
1619 songlist = self["list"].getList()
1620 mode = self.iDreamMode or songlist[index][0].PTS
1622 self.summaries.setText(songlist[index][0].title,1)
1624 self.summaries.setText(songlist[index][0].text,1)
1625 count = self["list"].getItemCount()
1631 self.summaries.setText(songlist[index][0].title,3)
1633 self.summaries.setText(songlist[index][0].text,3)
1635 index = self["list"].getCurrentIndex() + 1
1639 self.summaries.setText(songlist[index][0].title,4)
1641 self.summaries.setText(songlist[index][0].text,4)
1644 def createSummary(self):
1645 return MerlinMusicPlayerLCDScreenText
1647 class iDreamMerlin(Screen):
1650 sz_w = getDesktop(0).size().width()
1653 <screen name="iDreamMerlin" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
1654 <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmpborderHD.png" position="128,72" size="1024,576"/>
1655 <ePixmap position="178,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1656 <ePixmap position="328,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1657 <ePixmap position="478,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1658 <ePixmap position="628,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
1659 <widget render="Label" source="key_red" position="178,102" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1660 <widget render="Label" source="key_green" position="328,102" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1661 <widget render="Label" source="key_yellow" position="478,102" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1662 <widget render="Label" source="key_blue" position="628,102" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1663 <widget name="headertext" position="178,149" zPosition="1" size="900,23" font="Regular;20" transparent="1" foregroundColor="#fcc000" backgroundColor="#00000000"/>
1664 <widget name="list" position="178,182" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0" backgroundColor="#00000000"/>
1668 <screen name="iDreamMerlin" position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
1669 <ePixmap position="50,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1670 <ePixmap position="200,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1671 <ePixmap position="350,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1672 <ePixmap position="500,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
1673 <widget render="Label" source="key_red" position="50,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1674 <widget render="Label" source="key_green" position="200,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1675 <widget render="Label" source="key_yellow" position="350,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1676 <widget render="Label" source="key_blue" position="500,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1677 <widget name="headertext" position="50,77" zPosition="1" size="900,23" font="Regular;20" transparent="1" foregroundColor="#fcc000" backgroundColor="#00000000"/>
1678 <widget name="list" position="50,110" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0" backgroundColor="#00000000"/>
1682 <screen name="iDreamMerlin" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
1683 <ePixmap position="50,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1684 <ePixmap position="200,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1685 <ePixmap position="350,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1686 <ePixmap position="500,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
1687 <widget render="Label" source="key_red" position="50,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1688 <widget render="Label" source="key_green" position="200,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1689 <widget render="Label" source="key_yellow" position="350,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1690 <widget render="Label" source="key_blue" position="500,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1691 <widget name="headertext" position="50,77" zPosition="1" size="620,23" font="Regular;20" transparent="1" foregroundColor="#fcc000" backgroundColor="#00000000"/>
1692 <widget name="list" position="50,110" zPosition="2" size="620,350" scrollbarMode="showOnDemand" transparent="0" backgroundColor="#00000000"/>
1696 def __init__(self, session, servicelist):
1697 self.session = session
1698 Screen.__init__(self, session)
1699 self["list"] = iDreamList()
1700 self["list"].connectSelChanged(self.lcdUpdate)
1703 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EPGSelectActions"],
1706 "back": self.closing,
1707 "red": self.red_pressed,
1708 "green": self.green_pressed,
1709 "yellow": self.yellow_pressed,
1710 "blue": self.blue_pressed,
1711 "input_date_time": self.menu_pressed,
1712 "info" : self.info_pressed,
1715 self["actions2"] = NumberActionMap(["InputActions"],
1717 "0": self.keyNumber_pressed,
1720 self.onLayoutFinish.append(self.startRun)
1721 self.onShown.append(self.lcdUpdate)
1722 self.onClose.append(self.__onClose)
1724 self.serviceList = servicelist
1725 self.currentService = self.session.nav.getCurrentlyPlayingServiceReference()
1726 self.session.nav.stopService()
1729 self.mainMenuList = []
1731 self.LastMethod = None
1734 self["key_red"] = StaticText("")
1735 self["key_green"] = StaticText("")
1736 self["key_yellow"] = StaticText("")
1737 self["key_blue"] = StaticText("")
1738 self["headertext"] = Label(_("iDream Main Menu"))
1740 self.startMerlinPlayerScreenTimer = eTimer()
1741 self.startMerlinPlayerScreenTimer.timeout.get().append(self.info_pressed)
1743 def getPlayList(self):
1744 connection = OpenDatabase()
1745 if connection is not None:
1746 connection.text_factory = str
1747 cursor = connection.cursor()
1749 cursor.execute("select playlist_id,playlist_text from playlists order by playlist_text;")
1751 playList.append((row[1], row[0]))
1758 def sqlCommand(self, sqlSatement):
1759 connection = OpenDatabase()
1760 if connection is not None:
1761 cursor = connection.cursor()
1762 cursor.execute(sqlSatement)
1767 def clearCache(self):
1768 for items in self.cacheList:
1771 items.headertext = ""
1773 def getCurrentSelection(self):
1775 try: sel = self["list"].l.getCurrentSelection()[0]
1779 def addListToPlaylistConfirmed(self, methodName, answer):
1781 playList = self.getPlayList()
1783 self.session.openWithCallback(methodName, ChoiceBox,list = playList)
1785 self.session.openWithCallback(self.createPlaylistConfirmed, MessageBox, _("There are no playlists defined.\nDo you want to create a new playlist?"))
1787 def menu_pressed(self):
1788 self.startMerlinPlayerScreenTimer.stop()
1789 options = [(_("Configuration"), self.config),(_("Search in iDream database"), self.searchInIDreamDatabase),]
1790 options.extend(((_("Scan path for music files and add them to database"), self.scanDir),))
1792 options.extend(((_("Create new playlist"), self.createPlaylist),))
1793 if self["list"].getDisplaySongMode():
1795 options.extend(((_("Delete song from current playlist"), self.deleteSongFromPlaylist),))
1797 options.extend(((_("Add selected song to a playlist"), self.addSongToPlaylist),))
1799 options.extend(((_("Add all songs from selected album to a playlist"), self.addAlbumToPlaylist),))
1800 elif self.mode == 19:
1801 options.extend(((_("Add all songs from selected artist to a playlist"), self.addArtistToPlaylist),))
1802 options.extend(((_("Delete song from database"), self.deleteSongFromDatabase),))
1803 options.extend(((_("Clear current songlist and play selected entry"), self.stopPlayingAndAppendFileToSongList),))
1804 options.extend(((_("Append file to current playing songlist"), self.appendFileToSongList),))
1805 if self.player is not None and self.player.songList:
1806 options.extend(((_("Insert file to current playing songlist and play next"), self.insertFileToSongList),))
1809 options.extend(((_("Delete selected playlist"), self.deletePlaylist),))
1810 elif self.mode == 4:
1811 options.extend(((_("Add all songs from selected artist to a playlist"), self.addArtistToPlaylist),))
1812 elif self.mode == 5 or self.mode == 7:
1813 options.extend(((_("Add all songs from selected album to a playlist"), self.addAlbumToPlaylist),))
1814 elif self.mode == 13:
1815 options.extend(((_("Add all songs from selected genre to a playlist"), self.addGenreToPlaylist),))
1816 self.session.openWithCallback(self.menuCallback, ChoiceBox,list = options)
1818 def menuCallback(self, ret):
1823 self.session.openWithCallback(self.pathSelected,SelectPath,"/media/")
1825 def pathSelected(self, res):
1827 self.session.openWithCallback(self.filesAdded, iDreamAddToDatabase,res)
1829 def filesAdded(self):
1830 if pathToDatabase.isRunning:
1838 def addGenreToPlaylist(self):
1839 self.session.openWithCallback(boundFunction(self.addListToPlaylistConfirmed,self.addGenreToPlaylistConfirmedCallback), MessageBox, _("Do you really want to add all songs from that genre to a playlist?"))
1841 def addGenreToPlaylistConfirmedCallback(self, ret):
1843 sel = self.getCurrentSelection()
1845 self.sqlCommand("INSERT INTO Playlist_Songs (playlist_id,song_id) select %d, song_id from songs where genre_id=%d order by album_id,tracknumber,title,filename;" % (ret[1],sel.genreID))
1848 def addArtistToPlaylist(self):
1849 self.session.openWithCallback(boundFunction(self.addListToPlaylistConfirmed, self.addArtistToPlaylistConfirmedCallback), MessageBox, _("Do you really want to add all songs from that artist to a playlist?"))
1851 def addArtistToPlaylistConfirmedCallback(self, ret):
1853 sel = self.getCurrentSelection()
1855 self.sqlCommand("INSERT INTO Playlist_Songs (playlist_id,song_id) select %d, song_id from songs where artist_id=%d order by album_id,tracknumber,title,filename;" % (ret[1],sel.artistID))
1858 def addAlbumToPlaylist(self):
1859 self.session.openWithCallback(boundFunction(self.addListToPlaylistConfirmed, self.addAlbumToPlaylistConfirmedCallback), MessageBox, _("Do you really want to add all songs from that album to a playlist?"))
1861 def addAlbumToPlaylistConfirmedCallback(self, ret):
1863 sel = self.getCurrentSelection()
1865 self.sqlCommand("INSERT INTO Playlist_Songs (playlist_id,song_id) select %d, song_id from songs where album_id=%d order by tracknumber,title,filename;" % (ret[1],sel.albumID))
1868 def deletePlaylist(self):
1869 self.session.openWithCallback(self.deletePlaylistConfirmed, MessageBox, _("Do you really want to delete the current playlist?"))
1871 def deletePlaylistConfirmed(self, answer):
1873 sel = self.getCurrentSelection()
1875 self.sqlCommand("delete from playlist_songs where playlist_id = %d" % (sel.playlistID))
1876 self.sqlCommand("delete from playlists where playlist_id = %d" % (sel.playlistID))
1877 self["list"].removeItem(self["list"].getCurrentIndex())
1881 def deleteSongFromPlaylist(self):
1882 self.session.openWithCallback(self.deleteSongFromPlaylistConfirmed, MessageBox, _("Do you really want to delete that song the current playlist?"))
1884 def deleteSongFromPlaylistConfirmed(self, answer):
1886 sel = self.getCurrentSelection()
1888 self.sqlCommand("delete from playlist_songs where song_id = %d" % (sel.songID))
1889 self["list"].removeItem(self["list"].getCurrentIndex())
1892 def deleteSongFromDatabase(self):
1893 self.session.openWithCallback(self.deleteSongFromDatabaseConfirmed, MessageBox, _("Do you really want to delete that song from the database?"))
1895 def deleteSongFromDatabaseConfirmed(self, answer):
1897 sel = self.getCurrentSelection()
1899 self.sqlCommand("delete from playlist_songs where song_id = %d" % (sel.songID))
1900 self.sqlCommand("delete from songs where song_id = %d" % (sel.songID))
1901 self["list"].removeItem(self["list"].getCurrentIndex())
1904 def addSongToPlaylist(self):
1905 playList = self.getPlayList()
1907 self.session.openWithCallback(self.addSongToPlaylistCallback, ChoiceBox,list = playList)
1909 self.session.openWithCallback(self.createPlaylistConfirmed, MessageBox, _("There are no playlists defined.\nDo you want to create a new playlist?"))
1911 def createPlaylistConfirmed(self, val):
1913 self.createPlaylist()
1915 def addSongToPlaylistCallback(self,ret):
1917 sel = self.getCurrentSelection()
1919 self.sqlCommand("INSERT INTO Playlist_Songs (playlist_id,song_id) VALUES(%d,%d);" % (ret[1],sel.songID))
1922 def createPlaylist(self):
1923 self.session.openWithCallback(self.createPlaylistFinished, VirtualKeyBoard, title = _("Enter name for playlist"))
1925 def createPlaylistFinished(self, text = None):
1927 self.sqlCommand('INSERT INTO Playlists (playlist_text) VALUES("%s");' % (text))
1931 def searchInIDreamDatabase(self):
1932 options = [(_("search for title"), 1),
1933 (_("search for artist"), 2),
1934 (_("search for album"), 3),
1935 (_("search in all of them"), 4),]
1936 self.session.openWithCallback(self.enterSearchText, ChoiceBox,list = options)
1938 def enterSearchText(self, ret):
1940 self.session.openWithCallback(boundFunction(self.enterSearchTextFinished,ret[1]), VirtualKeyBoard, title = _("Enter search-text"))
1942 def enterSearchTextFinished(self, searchType, searchText = None):
1944 search = "%" + searchText + "%"
1946 sql_where = "where title like '%s'" % search
1947 text = _('Search results for "%s" in all titles') % searchText
1948 elif searchType == 2:
1949 sql_where = "where artists.artist like '%s'" % search
1950 text = _('Search results for "%s" in all artists') % searchText
1951 elif searchType == 3:
1952 sql_where = "where album_text like '%s'" % search
1953 text = _('Search results for "%s" in all albums') % searchText
1955 sql_where = "where (title like '%s' or artists.artist like '%s' or album_text like '%s')" % (search,search,search)
1956 text = _('Search results for "%s" in title, artist or album') % searchText
1957 self.setButtons(red = True, yellow = True, blue = True)
1960 self["list"].setMode(self.mode)
1961 self.buildSearchSongList(sql_where, text, oldmode, True)
1964 def keyNumber_pressed(self, number):
1965 if number == 0 and self.mode != 0:
1966 self["list"].moveToIndex(0)
1970 sel = self.getCurrentSelection()
1974 self.green_pressed()
1976 self.mode = sel.mode
1977 self["list"].setMode(self.mode)
1978 if sel.navigator and len(self.cacheList) > 0:
1979 cache = self.cacheList.pop()
1981 cache = CacheList(cache = False, index = -1)
1983 self["headertext"].setText(cache.headertext)
1985 self["list"].setList(cache.listview)
1986 self.LastMethod = MethodArguments(method = cache.methodarguments.method, arguments = cache.methodarguments.arguments)
1988 cache.methodarguments.method(**cache.methodarguments.arguments)
1989 self["list"].moveToIndex(cache.index)
1992 if not sel.navigator:
1993 self.buildMainMenuList()
1994 elif self.mode == 1:
1995 self.setButtons(red = True)
1996 if not sel.navigator:
1997 self.buildPlaylistList(addToCache = True)
1998 elif self.mode == 2:
1999 self.setButtons(red = True, green = True, yellow = True, blue = True)
2000 if not sel.navigator:
2001 self.buildPlaylistSongList(playlistID = sel.playlistID, addToCache = True)
2002 elif self.mode == 4:
2003 self.setButtons(red = True)
2004 if not sel.navigator:
2005 self.buildArtistList(addToCache = True)
2006 elif self.mode == 5:
2007 self.setButtons(red = True)
2008 if not sel.navigator:
2009 self.buildArtistAlbumList(sel.artistID, addToCache = True)
2010 elif self.mode == 6:
2011 self.setButtons(red = True, green = True, yellow = True)
2012 if not sel.navigator:
2013 self.buildAlbumSongList(albumID = sel.albumID, mode = 5, addToCache = True)
2014 elif self.mode == 7:
2015 self.setButtons(red = True)
2016 if not sel.navigator:
2017 self.buildAlbumList(addToCache = True)
2018 elif self.mode == 8:
2019 self.setButtons(red = True, green = True, yellow = True)
2020 if not sel.navigator:
2021 self.buildAlbumSongList(albumID = sel.albumID, mode = 7, addToCache = True)
2022 elif self.mode == 10:
2023 self.setButtons(red = True, green = True, yellow = True, blue = True)
2024 if not sel.navigator:
2025 self.buildSongList(addToCache = True)
2026 elif self.mode == 13:
2027 self.setButtons(red = True)
2028 if not sel.navigator:
2029 self.buildGenreList(addToCache = True)
2030 elif self.mode == 14:
2031 self.setButtons(red = True, green = True, yellow = True, blue = True)
2032 if not sel.navigator:
2033 self.buildGenreSongList(genreID = sel.genreID, addToCache = True)
2034 elif self.mode == 18 or self.mode == 19:
2036 self.setButtons(red = True, green = True, yellow = True)
2038 self.setButtons(red = True, green = True, blue = True)
2039 if not sel.navigator:
2040 self.red_pressed() # back to main menu --> normally that can not be happened
2041 elif self.mode == 20:
2042 self.setButtons(red = True, green = True, yellow = True, blue = True)
2043 if not sel.navigator:
2044 self.red_pressed() # back to main menu --> normally that can not be happened
2046 def buildPlaylistList(self, addToCache):
2048 self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2050 arguments["addToCache"] = False
2051 self.LastMethod = MethodArguments(method = self.buildPlaylistList, arguments = arguments)
2052 self["headertext"].setText(_("Playlists"))
2053 connection = OpenDatabase()
2054 if connection is not None:
2055 connection.text_factory = str
2056 cursor = connection.cursor()
2058 playlistList.append((Item(text = _("[back]"), mode = 0, navigator = True),))
2059 cursor.execute("select playlists.playlist_id, playlist_text, count(Playlist_Songs.playlist_id) from playlists left outer join Playlist_Songs on playlists.playlist_id = Playlist_Songs.playlist_id group by playlists.playlist_id order by playlists.playlist_text;")
2061 playlistList.append((Item(text = "%s (%d)" % (row[1], row[2]), mode = 2, playlistID = row[0]),))
2064 self["list"].setList(playlistList)
2065 if len(playlistList) > 1:
2066 self["list"].moveToIndex(1)
2068 def buildPlaylistSongList(self, playlistID, addToCache):
2070 self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2072 arguments["playlistID"] = playlistID
2073 arguments["addToCache"] = False
2074 self.LastMethod = MethodArguments(method = self.buildPlaylistSongList, arguments = arguments)
2075 connection = OpenDatabase()
2076 if connection is not None:
2077 connection.text_factory = str
2078 cursor = connection.cursor()
2079 playlistSongList = []
2080 playlistSongList.append((Item(text = _("[back]"), mode = 1, navigator = True),))
2081 cursor.execute("select songs.song_id, title, artists.artist, filename, songs.artist_id, bitrate, length, genre_text, track, date, album_text, songs.Album_id from songs inner join artists on songs.artist_id = artists.artist_id inner join Album on songs.Album_id = Album.Album_id inner join genre on songs.genre_id = genre.genre_id inner join playlist_songs on songs.song_id = playlist_songs.song_id where playlist_songs.playlist_id = %d order by playlist_songs.id;" % (playlistID))
2083 playlistSongList.append((Item(mode = 99, songID = row[0], title = row[1], artist = row[2], filename = row[3], artistID = row[4], bitrate = row[5], length = row[6], genre = row[7], track = row[8], date = row[9], album = row[10], albumID = row[11], playlistID = playlistID),))
2084 cursor.execute("SELECT playlist_text from playlists where playlist_id = %d;" % playlistID)
2085 row = cursor.fetchone()
2086 self["headertext"].setText(_("Playlist (%s) -> Song List") % row[0])
2089 self["list"].setList(playlistSongList)
2090 if len(playlistSongList) > 1:
2091 self["list"].moveToIndex(1)
2093 def buildGenreList(self, addToCache):
2095 self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2097 arguments["addToCache"] = False
2098 self.LastMethod = MethodArguments(method = self.buildGenreList, arguments = arguments)
2099 self["headertext"].setText(_("Genre List"))
2100 connection = OpenDatabase()
2101 if connection is not None:
2102 connection.text_factory = str
2103 cursor = connection.cursor()
2105 genreList.append((Item(text = _("[back]"), mode = 0, navigator = True),))
2106 cursor.execute("select Genre.genre_id,Genre.Genre_text, count(*) from songs inner join Genre on songs.genre_id = Genre.Genre_id group by songs.Genre_id order by Genre.Genre_text;")
2108 genreList.append((Item(text = "%s (%d)" % (row[1], row[2]), mode = 14, genreID = row[0]),))
2111 self["list"].setList(genreList)
2112 if len(genreList) > 1:
2113 self["list"].moveToIndex(1)
2115 def buildGenreSongList(self, genreID, addToCache):
2117 self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2119 arguments["genreID"] = genreID
2120 arguments["addToCache"] = False
2121 self.LastMethod = MethodArguments(method = self.buildGenreSongList, arguments = arguments)
2122 connection = OpenDatabase()
2123 if connection is not None:
2124 connection.text_factory = str
2125 cursor = connection.cursor()
2127 genreSongList.append((Item(text = _("[back]"), mode = 13, navigator = True),))
2128 cursor.execute("select song_id, title, artists.artist, filename, songs.artist_id, bitrate, length, genre_text, track, date, album_text, songs.Album_id from songs inner join artists on songs.artist_id = artists.artist_id inner join Album on songs.Album_id = Album.Album_id inner join genre on songs.genre_id = genre.genre_id where songs.genre_id = %d order by title, filename;" % (genreID))
2130 genreSongList.append((Item(mode = 99, songID = row[0], title = row[1], artist = row[2], filename = row[3], artistID = row[4], bitrate = row[5], length = row[6], genre = row[7], track = row[8], date = row[9], album = row[10], albumID = row[11], genreID = genreID),))
2131 cursor.execute("SELECT genre_text from genre where genre_ID = %d;" % genreID)
2132 row = cursor.fetchone()
2133 self["headertext"].setText(_("Genre (%s) -> Song List") % row[0])
2136 self["list"].setList(genreSongList)
2137 if len(genreSongList) > 1:
2138 self["list"].moveToIndex(1)
2140 def setButtons(self, red = False, green = False, yellow = False, blue = False):
2142 self["key_red"].setText("Main Menu")
2144 self["key_red"].setText("")
2146 self["key_green"].setText("Play")
2148 self["key_green"].setText("")
2150 self["key_yellow"].setText("All Artists")
2152 self["key_yellow"].setText("")
2154 self["key_blue"].setText("Show Album")
2156 self["key_blue"].setText("")
2158 def info_pressed(self):
2159 self.startMerlinPlayerScreenTimer.stop()
2160 if self.player is not None:
2161 if self.player.songList:
2162 self.session.execDialog(self.player)
2164 def green_pressed(self):
2166 sel = self["list"].l.getCurrentSelection()[0]
2172 if self.player is not None:
2173 self.player.doClose()
2175 self.startMerlinPlayerScreenTimer.stop()
2176 self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,self["list"].getList()[1:], self["list"].getCurrentIndex() -1, True, self.currentService, self.serviceList)
2177 self.session.execDialog(self.player)
2179 def red_pressed(self):
2183 self["list"].setMode(self.mode)
2184 self.buildMainMenuList()
2186 def yellow_pressed(self):
2188 sel = self["list"].l.getCurrentSelection()[0]
2191 if sel.artistID != 0:
2194 self.setButtons(red = True, green = True, blue = True)
2195 self["list"].setMode(self.mode)
2196 self.buildArtistSongList(artistID = sel.artistID, mode = oldmode, addToCache = True)
2198 def blue_pressed(self):
2200 sel = self["list"].l.getCurrentSelection()[0]
2203 if sel.albumID != 0:
2204 self.setButtons(red = True, green = True, yellow = True)
2207 self["list"].setMode(self.mode)
2208 self.buildAlbumSongList(albumID = sel.albumID, mode = oldmode, addToCache = True)
2210 def buildSongList(self, addToCache):
2212 self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2214 arguments["addToCache"] = False
2215 self.LastMethod = MethodArguments(method = self.buildSongList, arguments = arguments)
2216 self["headertext"].setText(_("All Songs"))
2217 connection = OpenDatabase()
2218 if connection is not None:
2219 connection.text_factory = str
2220 cursor = connection.cursor()
2222 SongList.append((Item(text = _("[back]"), mode = 0, navigator = True),))
2223 cursor.execute("select song_id, title, artists.artist, filename, songs.artist_id, bitrate, length, genre_text, track, date, album_text, songs.Album_id from songs inner join artists on songs.artist_id = artists.artist_id inner join Album on songs.Album_id = Album.Album_id inner join genre on songs.genre_id = genre.genre_id order by title, filename;")
2225 SongList.append((Item(mode = 99, songID = row[0], title = row[1], artist = row[2], filename = row[3], artistID = row[4], bitrate = row[5], length = row[6], genre = row[7], track = row[8], date = row[9], album = row[10], albumID = row[11]),))
2228 self["list"].setList(SongList)
2229 if len(SongList) > 1:
2230 self["list"].moveToIndex(1)
2233 def buildSearchSongList(self, sql_where, headerText, mode, addToCache):
2235 self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2237 arguments["sql_where"] = sql_where
2238 arguments["headerText"] = headerText
2239 arguments["mode"] = mode
2240 arguments["addToCache"] = False
2241 self.LastMethod = MethodArguments(method = self.buildSearchSongList, arguments = arguments)
2242 self["headertext"].setText(headerText)
2243 connection = OpenDatabase()
2244 if connection is not None:
2245 connection.text_factory = str
2246 cursor = connection.cursor()
2248 SongList.append((Item(text = _("[back]"), mode = mode, navigator = True),))
2249 cursor.execute("select song_id, title, artists.artist, filename, songs.artist_id, bitrate, length, genre_text, track, date, album_text, songs.Album_id from songs inner join artists on songs.artist_id = artists.artist_id inner join Album on songs.Album_id = Album.Album_id inner join genre on songs.genre_id = genre.genre_id %s order by title, filename;" % sql_where)
2251 SongList.append((Item(mode = 99, songID = row[0], title = row[1], artist = row[2], filename = row[3], artistID = row[4], bitrate = row[5], length = row[6], genre = row[7], track = row[8], date = row[9], album = row[10], albumID = row[11]),))
2254 self["list"].setList(SongList)
2255 if len(SongList) > 1:
2256 self["list"].moveToIndex(1)
2259 def buildArtistSongList(self, artistID, mode, addToCache):
2261 self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2263 arguments["artistID"] = artistID
2264 arguments["mode"] = mode
2265 arguments["addToCache"] = False
2266 self.LastMethod = MethodArguments(method = self.buildArtistSongList, arguments = arguments)
2267 connection = OpenDatabase()
2268 if connection is not None:
2269 connection.text_factory = str
2270 cursor = connection.cursor()
2272 artistSongList.append((Item(text = _("[back]"), mode = mode, navigator = True),))
2273 cursor.execute("select song_id, title, artists.artist, filename, bitrate, length, genre_text, track, date, album_text, songs.Album_id from songs inner join artists on songs.artist_id = artists.artist_id inner join Album on songs.Album_id = Album.Album_id inner join genre on songs.genre_id = genre.genre_id where songs.artist_id = %d order by Album.album_text, tracknumber, filename;" % (artistID))
2275 artistSongList.append((Item(mode = 99, songID = row[0], title = row[1], artist = row[2], filename = row[3], bitrate = row[4], length = row[5], genre = row[6], track = row[7], date = row[8], album = row[9], albumID = row[10], artistID = artistID),))
2276 cursor.execute("SELECT artist from artists where artist_ID = %d;" % artistID)
2277 row = cursor.fetchone()
2278 self["headertext"].setText(_("Artist (%s) -> Song List") % row[0])
2281 self["list"].setList(artistSongList)
2282 if len(artistSongList) > 1:
2283 self["list"].moveToIndex(1)
2285 def buildAlbumSongList(self, albumID, mode, addToCache):
2287 self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2289 arguments["albumID"] = albumID
2290 arguments["mode"] = mode
2291 arguments["addToCache"] = False
2292 self.LastMethod = MethodArguments(method = self.buildAlbumSongList, arguments = arguments)
2293 connection = OpenDatabase()
2294 if connection is not None:
2295 connection.text_factory = str
2296 cursor = connection.cursor()
2298 albumSongList.append((Item(text = _("[back]"), mode = mode, navigator = True),))
2299 cursor.execute("select song_id, title, artists.artist, filename, songs.artist_id, bitrate, length, genre_text, track, date, album_text from songs inner join artists on songs.artist_id = artists.artist_id inner join Album on songs.Album_id = Album.Album_id inner join genre on songs.genre_id = genre.genre_id where songs.album_id = %d order by tracknumber, filename;" % (albumID))
2301 albumSongList.append((Item(mode = 99, songID = row[0], title = row[1], artist = row[2], filename = row[3], artistID = row[4], bitrate = row[5], length = row[6], genre = row[7], track = row[8], date = row[9], album = row[10], albumID = albumID),))
2302 cursor.execute("SELECT album_text from album where album_ID = %d;" % albumID)
2303 row = cursor.fetchone()
2304 self["headertext"].setText(_("Album (%s) -> Song List") % row[0])
2307 self["list"].setList(albumSongList)
2308 if len(albumSongList) > 1:
2309 self["list"].moveToIndex(1)
2311 def buildMainMenuList(self, addToCache = True):
2313 arguments["addToCache"] = True
2314 self.LastMethod = MethodArguments(method = self.buildMainMenuList, arguments = arguments)
2315 self["headertext"].setText(_("iDream Main Menu"))
2317 connection = OpenDatabase()
2318 if connection is not None:
2319 connection.text_factory = str
2320 cursor = connection.cursor()
2322 cursor.execute("SELECT COUNT (*) FROM playlists;")
2323 row = cursor.fetchone()
2324 mainMenuList.append((Item(text = _("Playlists (%d)") % row[0], mode = 1),))
2326 cursor.execute("SELECT COUNT (*) FROM artists;")
2327 row = cursor.fetchone()
2328 mainMenuList.append((Item(text = _("Artists (%d)") % row[0], mode = 4),))
2330 cursor.execute("SELECT COUNT (DISTINCT album_text) FROM album;")
2331 row = cursor.fetchone()
2332 mainMenuList.append((Item(text = _("Albums (%d)") % row[0], mode = 7),))
2334 cursor.execute("SELECT COUNT (*) FROM songs;")
2335 row = cursor.fetchone()
2336 mainMenuList.append((Item(text = _("Songs (%d)") % row[0], mode = 10),))
2338 cursor.execute("SELECT COUNT (*) FROM genre;")
2339 row = cursor.fetchone()
2340 mainMenuList.append((Item(text = _("Genres (%d)") % row[0], mode = 13),))
2343 self["list"].setList(mainMenuList)
2344 self["list"].moveToIndex(0)
2346 def buildArtistList(self, addToCache):
2348 self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2350 arguments["addToCache"] = False
2351 self.LastMethod = MethodArguments(method = self.buildArtistList, arguments = arguments)
2352 self["headertext"].setText(_("Artists List"))
2353 connection = OpenDatabase()
2354 if connection is not None:
2355 connection.text_factory = str
2356 cursor = connection.cursor()
2358 artistList.append((Item(text = _("[back]"), mode = 0, navigator = True),))
2359 cursor.execute("SELECT artists.artist_id,artists.artist, count (distinct album.album_text) FROM songs INNER JOIN artists ON songs.artist_id = artists.artist_id inner join album on songs.album_id = album.album_id GROUP BY songs.artist_id ORDER BY artists.artist;")
2361 artistList.append((Item(text = "%s (%d)" % (row[1], row[2]), mode = 5, artistID = row[0]),))
2364 self["list"].setList(artistList)
2366 def buildArtistAlbumList(self, ArtistID, addToCache):
2368 self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2370 arguments["ArtistID"] = ArtistID
2371 arguments["addToCache"] = False
2372 self.LastMethod = MethodArguments(method = self.buildArtistAlbumList, arguments = arguments)
2373 connection = OpenDatabase()
2374 if connection is not None:
2375 connection.text_factory = str
2376 cursor = connection.cursor()
2377 albumArtistList = []
2378 albumArtistList.append((Item(text = _("[back]"), mode = 4, navigator = True),))
2379 cursor.execute("select Album.Album_id,Album.Album_text from songs inner join Album on songs.Album_id = Album.Album_id where songs.artist_id = %d group by songs.Album_id order by Album.Album_text;" % ArtistID)
2381 cursor2 = connection.cursor()
2382 cursor2.execute("select count(song_id) from songs where album_id = %d;" % row[0])
2383 row2 = cursor2.fetchone()
2384 albumArtistList.append((Item(text = "%s (%d)" % (row[1], row2[0]), mode = 6, albumID = row[0], artistID = ArtistID),))
2386 cursor.execute("SELECT artist from artists where artist_ID = %d;" % ArtistID)
2387 row = cursor.fetchone()
2388 self["headertext"].setText(_("Artist (%s) -> Album List") % row[0])
2391 self["list"].setList(albumArtistList)
2392 if len(albumArtistList) > 1:
2393 self["list"].moveToIndex(1)
2395 def buildAlbumList(self, addToCache):
2397 self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2399 arguments["addToCache"] = False
2400 self.LastMethod = MethodArguments(method = self.buildAlbumList, arguments = arguments)
2401 self["headertext"].setText(_("Albums List"))
2402 connection = OpenDatabase()
2403 if connection is not None:
2404 connection.text_factory = str
2405 cursor = connection.cursor()
2407 albumList.append((Item(text = _("[back]"), mode = 0, navigator = True),))
2408 cursor.execute("select Album.Album_id,Album.Album_text, count(*) from songs inner join Album on songs.Album_id = Album.Album_id group by songs.Album_id order by Album.Album_text;")
2410 albumList.append((Item(text = "%s (%d)" % (row[1], row[2]), mode = 8, albumID = row[0]),))
2413 self["list"].setList(albumList)
2414 if len(albumList) > 1:
2415 self["list"].moveToIndex(1)
2418 if pathToDatabase.isRunning:
2419 self.showScanner = eTimer()
2420 self.showScanner.callback.append(self.showScannerCallback)
2421 self.showScanner.start(0,1)
2423 if config.plugins.merlinmusicplayer.startlastsonglist.value:
2424 self.startPlayerTimer = eTimer()
2425 self.startPlayerTimer.callback.append(self.startPlayerTimerCallback)
2426 self.startPlayerTimer.start(0,1)
2428 self["list"].setMode(self.mode)
2429 self.buildMainMenuList()
2431 def showScannerCallback(self):
2432 self.session.openWithCallback(self.filesAdded, iDreamAddToDatabase,None)
2435 def startPlayerTimerCallback(self):
2436 connection = OpenDatabase()
2437 if connection is not None:
2438 connection.text_factory = str
2439 cursor = connection.cursor()
2442 cursor.execute("select song_id, filename, title, artist, album, genre, bitrate, length, track, date, PTS from CurrentSongList;")
2444 SongList.append((Item(songID = row[0], text = os_path.basename(row[1]), filename = row[1], title = row[2], artist = row[3], album = row[4], genre = row[5], bitrate = row[6], length = row[7], track = row[8], date = row[9], PTS = row[10], join = False),))
2449 if self.player is not None:
2450 self.player.doClose()
2452 self.startMerlinPlayerScreenTimer.stop()
2453 count = len(SongList)
2455 # just to be sure, check the index , it's critical
2456 index = config.plugins.merlinmusicplayer.lastsonglistindex.value
2459 self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,SongList, index, iDreamMode, self.currentService, self.serviceList)
2460 self.session.execDialog(self.player)
2463 self.startMerlinPlayerScreenTimer.stop()
2464 self.session.openWithCallback(self.setupFinished, MerlinMusicPlayerSetup, True)
2466 def setupFinished(self, result):
2471 def stopPlayingAndAppendFileToSongList(self):
2472 self.startMerlinPlayerScreenTimer.stop()
2473 if self.player is not None:
2474 self.player.doClose()
2476 self.appendFileToSongList()
2477 self.startMerlinPlayerScreenTimer.start(START_MERLIN_PLAYER_SCREEN_TIMER_VALUE)
2479 def appendFileToSongList(self):
2481 playerAvailable = self.player is not None and self.player.songList
2482 sel = self.getCurrentSelection()
2485 self.player.songList.append((sel,))
2486 self.player.origSongList.append((sel,))
2488 SongList.append((sel,))
2489 if not playerAvailable:
2490 if self.player is not None:
2491 self.player.doClose()
2493 self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,SongList, 0, True, self.currentService, self.serviceList)
2494 self.player.playSong(self.player.songList[self.player.currentIndex][0].filename)
2495 self.player["coverArt"].onShow()
2496 self.player.init = 1
2498 self.player["nextTitle"].setText(self.player.getNextTitle())
2499 self.session.open(MessageBox, _("%s\nappended to songlist")%sel.title, type = MessageBox.TYPE_INFO,timeout = 3 )
2501 def insertFileToSongList(self):
2502 sel = self.getCurrentSelection()
2504 if self.player is not None and self.player.songList:
2505 index = self.player.currentIndex
2506 self.player.songList.insert(index+1,(sel,))
2507 self.player.origSongList.insert(index+1,(sel,))
2508 self.player["nextTitle"].setText(self.player.getNextTitle())
2509 self.session.open(MessageBox, _("%s\ninserted and will be played as next song")%sel.title, type = MessageBox.TYPE_INFO,timeout = 3 )
2511 self.appendFileToSongList()
2513 def Error(self, error = None):
2514 if error is not None:
2516 self["statustext"].setText(str(error.getErrorMessage()))
2521 def __onClose(self):
2522 self.startMerlinPlayerScreenTimer.stop()
2523 if self.player is not None:
2524 self.player.closePlayer()
2525 self.player.doClose()
2527 if self.serviceList is None:
2528 self.session.nav.playService(self.currentService)
2530 current = ServiceReference(self.serviceList.getCurrentSelection())
2531 self.session.nav.playService(current.ref)
2534 def lcdUpdate(self):
2535 self.startMerlinPlayerScreenTimer.start(START_MERLIN_PLAYER_SCREEN_TIMER_VALUE)
2537 count = self["list"].getItemCount()
2538 index = self["list"].getCurrentIndex()
2539 iDreamList = self["list"].getList()
2540 self.summaries.setText(iDreamList[index][0].title or iDreamList[index][0].text,1)
2545 self.summaries.setText(iDreamList[index][0].title or iDreamList[index][0].text,3)
2547 index = self["list"].getCurrentIndex() + 1
2550 self.summaries.setText(iDreamList[index][0].title or iDreamList[index][0].text,4)
2553 def createSummary(self):
2554 return MerlinMusicPlayerLCDScreenText
2557 class iDreamList(GUIComponent, object):
2558 def buildEntry(self, item):
2559 width = self.l.getItemSize().width()
2561 if self.displaySongMode:
2563 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width , 20, 0, RT_HALIGN_CENTER|RT_VALIGN_CENTER, "%s" % item.text))
2565 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width - 100 , 20, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "%s - %s" % (item.title, item.artist)))
2566 res.append((eListboxPythonMultiContent.TYPE_TEXT, width - 100,3,100, 20, 1, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, "%s" % item.track))
2567 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 26,width -200, 18, 1, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "%s%s" % (item.album, item.date)))
2568 res.append((eListboxPythonMultiContent.TYPE_TEXT, width -200, 26,200, 18, 1, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, "%s" % item.length))
2569 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 47,width -200, 18, 1, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "%s" % item.genre))
2570 res.append((eListboxPythonMultiContent.TYPE_TEXT, width -200, 47,200, 18, 1, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, "%s" % item.bitrate))
2573 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width , 20, 0, RT_HALIGN_CENTER|RT_VALIGN_CENTER, "%s" % item.text))
2575 if item.PTS is None:
2576 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width , 20, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "%s" % item.text))
2578 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width , 20, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "%s" % item.title))
2583 GUIComponent.__init__(self)
2584 self.l = eListboxPythonMultiContent()
2585 self.l.setBuildFunc(self.buildEntry)
2586 self.l.setFont(0, gFont("Regular", 20))
2587 self.l.setFont(1, gFont("Regular", 16))
2588 self.l.setItemHeight(22)
2589 self.onSelectionChanged = [ ]
2591 self.displaySongMode = False
2595 def connectSelChanged(self, fnc):
2596 if not fnc in self.onSelectionChanged:
2597 self.onSelectionChanged.append(fnc)
2599 def disconnectSelChanged(self, fnc):
2600 if fnc in self.onSelectionChanged:
2601 self.onSelectionChanged.remove(fnc)
2603 def selectionChanged(self):
2604 for x in self.onSelectionChanged:
2607 def getCurrent(self):
2608 cur = self.l.getCurrentSelection()
2609 return cur and cur[0]
2611 GUI_WIDGET = eListbox
2613 def postWidgetCreate(self, instance):
2614 instance.setContent(self.l)
2615 instance.selectionChanged.get().append(self.selectionChanged)
2617 def preWidgetRemove(self, instance):
2618 instance.setContent(None)
2619 instance.selectionChanged.get().remove(self.selectionChanged)
2621 def moveToIndex(self, index):
2622 self.instance.moveSelectionTo(index)
2624 def getCurrentIndex(self):
2625 return self.instance.getCurrentIndex()
2627 currentIndex = property(getCurrentIndex, moveToIndex)
2628 currentSelection = property(getCurrent)
2630 def setList(self, list):
2632 self.l.setList(list)
2633 self.itemCount = len(self.list) - 1
2635 def getItemCount(self):
2636 return self.itemCount
2641 def removeItem(self, index):
2642 del self.list[index]
2643 self.l.entryRemoved(index)
2645 def getDisplaySongMode(self):
2646 return self.displaySongMode
2648 def setMode(self, mode):
2650 if mode == 2 or mode == 6 or mode == 8 or mode == 10 or mode == 18 or mode == 19 or mode == 14 or mode == 20:
2651 self.displaySongMode = True
2652 self.l.setItemHeight(68)
2654 self.displaySongMode = False
2655 self.l.setItemHeight(22)
2658 class MerlinMediaPixmap(Pixmap):
2660 Pixmap.__init__(self)
2661 self.coverArtFileName = ""
2662 self.picload = ePicLoad()
2663 self.picload.PictureData.get().append(self.paintCoverArtPixmapCB)
2664 self.coverFileNames = ["folder.png", "folder.jpg", "cover.jpg", "cover.png", "coverArt.jpg"]
2666 def applySkin(self, desktop, screen):
2667 from Tools.LoadPixmap import LoadPixmap
2669 if self.skinAttributes is not None:
2670 for (attrib, value) in self.skinAttributes:
2671 if attrib == "pixmap":
2674 if noCoverFile is None:
2675 noCoverFile = resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/no_coverArt.png")
2676 self.noCoverPixmap = LoadPixmap(noCoverFile)
2677 return Pixmap.applySkin(self, desktop, screen)
2681 sc = AVSwitch().getFramebufferScale()
2682 self.picload.setPara((self.instance.size().width(), self.instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
2684 def paintCoverArtPixmapCB(self, picInfo=None):
2685 ptr = self.picload.getData()
2687 self.instance.setPixmap(ptr.__deref__())
2689 def updateCoverArt(self, path):
2691 while not path.endswith("/"):
2693 new_coverArtFileName = None
2694 for filename in self.coverFileNames:
2695 if fileExists(path + filename):
2696 new_coverArtFileName = path + filename
2697 if self.coverArtFileName != new_coverArtFileName:
2698 if new_coverArtFileName:
2699 self.coverArtFileName = new_coverArtFileName
2700 print "[MerlinMusicPlayer] using cover from %s " % self.coverArtFileName
2701 self.picload.startDecode(self.coverArtFileName)
2704 if new_coverArtFileName:
2708 def showDefaultCover(self):
2709 self.coverArtFileName = ""
2710 self.instance.setPixmap(self.noCoverPixmap)
2712 def showCoverFromFile(self, filename):
2713 self.coverArtFileName = filename
2714 self.picload.startDecode(self.coverArtFileName)
2716 def embeddedCoverArt(self):
2717 print "[embeddedCoverArt] found"
2718 self.coverArtFileName = "/tmp/.id3coverart"
2719 self.picload.startDecode(self.coverArtFileName)
2722 class SelectPath(Screen):
2723 skin = """<screen name="SelectPath" position="center,center" size="560,320" title="Select path">
2724 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
2725 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
2726 <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
2727 <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
2728 <widget name="target" position="0,60" size="540,22" valign="center" font="Regular;22" />
2729 <widget name="filelist" position="0,100" zPosition="1" size="560,220" scrollbarMode="showOnDemand"/>
2730 <widget render="Label" source="key_red" position="0,0" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2731 <widget render="Label" source="key_green" position="140,0" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2733 def __init__(self, session, initDir):
2734 Screen.__init__(self, session)
2735 inhibitDirs = ["/bin", "/boot", "/dev", "/etc", "/lib", "/proc", "/sbin", "/sys", "/usr", "/var"]
2737 self["filelist"] = FileList(initDir, showDirectories = True, showFiles = False, inhibitMounts = inhibitMounts, inhibitDirs = inhibitDirs)
2738 self["target"] = Label()
2739 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EPGSelectActions"],
2741 "back": self.cancel,
2743 "right": self.right,
2747 "green": self.green,
2751 self["key_red"] = StaticText(_("Cancel"))
2752 self["key_green"] = StaticText(_("OK"))
2758 self.close(self["filelist"].getSelection()[0])
2761 self["filelist"].up()
2765 self["filelist"].down()
2769 self["filelist"].pageUp()
2773 self["filelist"].pageDown()
2777 if self["filelist"].canDescent():
2778 self["filelist"].descent()
2781 def updateTarget(self):
2782 currFolder = self["filelist"].getSelection()[0]
2783 if currFolder is not None:
2784 self["target"].setText(currFolder)
2786 self["target"].setText(_("Invalid Location"))
2789 class MerlinMusicPlayerLCDScreen(Screen):
2791 <screen position="0,0" size="132,64">
2792 <widget source="session.CurrentService" render="Label" position="4,0" size="132,12" valign="top" font="Regular;10" halign="center">
2793 <convert type="ServicePosition">Position,ShowHours</convert>
2795 <widget name="text1" position="4,14" size="132,35" halign="center" valign="top" font="Regular;14"/>
2796 <widget name="text4" position="4,51" size="132,12" halign="center" valign="top" font="Regular;10"/>
2799 def __init__(self, session, parent):
2800 Screen.__init__(self, session)
2801 self["text1"] = Label()
2802 self["text4"] = Label()
2804 def setText(self, text, line):
2806 self["text1"].setText(text)
2808 self["text4"].setText(text)
2810 class MerlinMusicPlayerLCDScreenText(Screen):
2812 <screen position="0,0" size="132,64">
2813 <widget name="text3" position="4,0" size="132,14" font="Regular;10"/>
2814 <widget name="text1" position="4,14" size="132,35" font="Regular;14"/>
2815 <widget name="text4" position="4,49" size="132,14" font="Regular;10"/>
2818 def __init__(self, session, parent):
2819 Screen.__init__(self, session)
2820 self["text1"] = Label()
2821 self["text3"] = Label()
2822 self["text4"] = Label()
2824 def setText(self, text, line):
2826 text = text + textleer*10
2828 self["text1"].setText(text)
2830 self["text3"].setText(text)
2832 self["text4"].setText(text)
2835 class MerlinMusicPlayerSetup(Screen, ConfigListScreen):
2837 sz_w = getDesktop(0).size().width()
2840 <screen position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="Merlin Music Player Setup" >
2841 <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmpborderHD.png" position="128,72" size="1024,576"/>
2842 <ePixmap position="178,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
2843 <ePixmap position="328,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
2844 <widget render="Label" source="key_red" position="178,102" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2845 <widget render="Label" source="key_green" position="328,102" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2846 <widget name="config" position="178,152" size="924,350" backgroundColor="#00000000" scrollbarMode="showOnDemand" />
2851 <screen position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="Merlin Music Player Setup" >
2852 <ePixmap position="50,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
2853 <ePixmap position="200,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
2854 <widget render="Label" source="key_red" position="50,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2855 <widget render="Label" source="key_green" position="200,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2856 <widget name="config" position="50,80" size="924,350" backgroundColor="#00000000" scrollbarMode="showOnDemand" />
2860 <screen position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="Merlin Music Player Setup">
2861 <ePixmap position="50,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
2862 <ePixmap position="200,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
2863 <widget render="Label" source="key_red" position="50,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2864 <widget render="Label" source="key_green" position="200,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2865 <widget name="config" position="50,80" size="620,350" backgroundColor="#00000000" scrollbarMode="showOnDemand" />
2869 def __init__(self, session, databasePath):
2870 Screen.__init__(self, session)
2872 self["key_red"] = StaticText(_("Cancel"))
2873 self["key_green"] = StaticText(_("OK"))
2876 if HardwareInfo().get_device_name() != "dm7025":
2877 self.list.append(getConfigListEntry(_("Use hardware-decoder for MP3"), config.plugins.merlinmusicplayer.hardwaredecoder))
2878 self.list.append(getConfigListEntry(_("Play last used songlist after starting"), config.plugins.merlinmusicplayer.startlastsonglist))
2880 self.database = getConfigListEntry(_("iDream database path"), config.plugins.merlinmusicplayer.databasepath)
2881 self.list.append(self.database)
2883 self.database = None
2884 self.list.append(getConfigListEntry(_("Use google-images for cover art"), config.plugins.merlinmusicplayer.usegoogleimage))
2885 self.googleimage = getConfigListEntry(_("Google image path"), config.plugins.merlinmusicplayer.googleimagepath)
2886 self.list.append(self.googleimage)
2887 self.list.append(getConfigListEntry(_("Activate screensaver"), config.plugins.merlinmusicplayer.usescreensaver))
2888 self.list.append(getConfigListEntry(_("Wait for screensaver (in min)"), config.plugins.merlinmusicplayer.screensaverwait))
2889 self.list.append(getConfigListEntry(_("Remember last path of filebrowser"), config.plugins.merlinmusicplayer.rememberlastfilebrowserpath))
2890 self.defaultFileBrowserPath = getConfigListEntry(_("Filebrowser startup path"), config.plugins.merlinmusicplayer.defaultfilebrowserpath)
2891 self.list.append(self.defaultFileBrowserPath)
2892 self.list.append(getConfigListEntry(_("Show iDream in extended-pluginlist"), config.plugins.merlinmusicplayer.idreamextendedpluginlist))
2893 self.list.append(getConfigListEntry(_("Show Merlin Music Player in extended-pluginlist"), config.plugins.merlinmusicplayer.merlinmusicplayerextendedpluginlist))
2894 self.list.append(getConfigListEntry(_("Show iDream in mainmenu"), config.plugins.merlinmusicplayer.idreammainmenu))
2895 self.list.append(getConfigListEntry(_("Show Merlin Music Player in mainmenu"), config.plugins.merlinmusicplayer.merlinmusicplayermainmenu))
2897 ConfigListScreen.__init__(self, self.list, session)
2898 self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
2900 "green": self.keySave,
2901 "cancel": self.keyClose,
2902 "ok": self.keySelect,
2905 def keySelect(self):
2906 cur = self["config"].getCurrent()
2907 if cur == self.database:
2908 self.session.openWithCallback(self.pathSelectedDatabase,SelectPath,config.plugins.merlinmusicplayer.databasepath.value)
2909 elif cur == self.defaultFileBrowserPath:
2910 self.session.openWithCallback(self.pathSelectedFilebrowser,SelectPath,config.plugins.merlinmusicplayer.defaultfilebrowserpath.value)
2911 elif cur == self.googleimage:
2912 self.session.openWithCallback(self.pathSelectedGoogleImage,SelectPath,config.plugins.merlinmusicplayer.googleimagepath.value)
2914 def pathSelectedGoogleImage(self, res):
2916 config.plugins.merlinmusicplayer.googleimagepath.value = res
2918 def pathSelectedDatabase(self, res):
2920 config.plugins.merlinmusicplayer.databasepath.value = res
2922 def pathSelectedFilebrowser(self, res):
2924 config.plugins.merlinmusicplayer.defaultfilebrowserpath.value = res
2927 for x in self["config"].list:
2933 for x in self["config"].list:
2939 class MerlinMusicPlayerFileList(Screen):
2941 sz_w = getDesktop(0).size().width()
2944 <screen name="MerlinMusicPlayerFileList" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
2945 <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmpborderHD.png" position="128,72" size="1024,576"/>
2946 <eLabel backgroundColor="#999999" position="178,112" size="924,2" zPosition="1"/>
2947 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="178,104" size="250,20" text="MERLIN MUSIC PLAYER" valign="center" zPosition="2"/>
2948 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="852,104" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
2949 <widget name="headertext" position="178,145" zPosition="1" size="900,23" font="Regular;20" transparent="1" foregroundColor="#fcc000" backgroundColor="#00000000"/>
2950 <widget name="list" position="178,182" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0" backgroundColor="#00000000"/>
2954 <screen name="MerlinMusicPlayerFileList" position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
2955 <eLabel backgroundColor="#999999" position="50,40" size="924,2" zPosition="1"/>
2956 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,32" size="250,20" text="MERLIN MUSIC PLAYER" valign="center" zPosition="2"/>
2957 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="724,32" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
2958 <widget name="headertext" position="50,73" zPosition="1" size="900,23" font="Regular;20" transparent="1" foregroundColor="#fcc000" backgroundColor="#00000000"/>
2959 <widget name="list" position="50,110" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0" backgroundColor="#00000000"/>
2963 <screen name="MerlinMusicPlayerFileList" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
2964 <eLabel backgroundColor="#999999" position="50,50" size="620,2" zPosition="1"/>
2965 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,40" size="250,20" text="MERLIN MUSIC PLAYER" valign="center" zPosition="2"/>
2966 <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="420,40" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
2968 <widget name="headertext" position="50,73" zPosition="1" size="620,23" font="Regular;20" transparent="1" foregroundColor="#fcc000" backgroundColor="#00000000"/>
2969 <widget name="list" position="50,110" zPosition="2" size="620,350" scrollbarMode="showOnDemand" transparent="0" backgroundColor="#00000000"/>
2973 def __init__(self, session, servicelist):
2974 self.session = session
2975 Screen.__init__(self, session)
2976 self["list"] = FileList(config.plugins.merlinmusicplayer.defaultfilebrowserpath.value, showDirectories = True, showFiles = True, matchingPattern = "(?i)^.*\.(mp3|m4a|flac|ogg|m3u|pls|cue)", useServiceRef = False)
2979 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EPGSelectActions"],
2983 "input_date_time": self.menu_pressed,
2984 "info" : self.info_pressed,
2985 "green": self.green_pressed,
2987 "down": self.movedown,
2988 "right": self.moveright,
2989 "left" : self.moveleft,
2990 "blue" : self.appendFileToSongList,
2991 "yellow" : self.insertFileToSongList,
2992 "red" : self.stopPlayingAndAppendFileToSongList,
2994 self.serviceList = servicelist
2995 self["headertext"] = Label()
2997 self.onClose.append(self.__onClose)
2998 self.onLayoutFinish.append(self.startRun)
2999 self.onShown.append(self.updateTarget)
3000 self.currentService = self.session.nav.getCurrentlyPlayingServiceReference()
3001 self.session.nav.stopService()
3003 self.startMerlinPlayerScreenTimer = eTimer()
3004 self.startMerlinPlayerScreenTimer.timeout.get().append(self.info_pressed)
3007 if config.plugins.merlinmusicplayer.startlastsonglist.value:
3008 self.startPlayerTimer = eTimer()
3009 self.startPlayerTimer.callback.append(self.startPlayerTimerCallback)
3010 self.startPlayerTimer.start(0,1)
3012 def startPlayerTimerCallback(self):
3013 connection = OpenDatabase()
3014 if connection is not None:
3015 connection.text_factory = str
3016 cursor = connection.cursor()
3019 cursor.execute("select song_id, filename, title, artist, album, genre, bitrate, length, track, date, PTS from CurrentSongList;")
3021 SongList.append((Item(songID = row[0], text = os_path.basename(row[1]), filename = row[1], title = row[2], artist = row[3], album = row[4], genre = row[5], bitrate = row[6], length = row[7], track = row[8], date = row[9], PTS = row[10], join = False),))
3026 if self.player is not None:
3027 self.player.doClose()
3029 self.startMerlinPlayerScreenTimer.stop()
3030 count = len(SongList)
3032 # just to be sure, check the index , it's critical
3033 index = config.plugins.merlinmusicplayer.lastsonglistindex.value
3036 self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,SongList, index, iDreamMode, self.currentService, self.serviceList)
3037 self.session.execDialog(self.player)
3039 def readCUE(self, filename):
3043 cuefile = open(filename, "r")
3047 performer_re = re.compile(r"""PERFORMER "(?P<performer>.*?)"(?:=\r\n|\r|\n|$)""")
3048 title_re = re.compile(r"""TITLE "(?P<title>.*?)"(?:=\r\n|\r|\n|$)""")
3049 filename_re = re.compile(r"""FILE "(?P<filename>.+?)".*(?:=\r\n|\r|\n|$)""", re.DOTALL)
3050 track_re = re.compile(r"""TRACK (?P<track_number>[^ ]+?)(?:[ ]+.*?)(?:=\r\n|\r|\n|$)""")
3051 index_re = re.compile(r"""INDEX (?P<index_nr>[^ ]+?)[ ]+(?P<track_index>[^ ]+?)(?:=\r\n|\r|\n|$)""")
3052 msts_re = re.compile("""^(?P<mins>[0-9]{1,}):(?P<secs>[0-9]{2}):(?P<ms>[0-9]{2})$""")
3059 for line in cuefile.readlines():
3060 entry = line.strip()
3061 m = filename_re.search(entry)
3063 if m.group('filename')[0] == "/":
3064 songfilename = m.group('filename')
3066 songfilename = os_path.join(os_path.dirname(filename), m.group('filename'))
3067 m = title_re.search(entry)
3070 album = m.group('title')
3072 title = m.group('title')
3073 m = performer_re.search(entry)
3075 performer = m.group('performer')
3076 m = track_re.search(entry)
3079 m = index_re.search(entry)
3081 if int(m.group('index_nr')) == 1:
3082 m1 = msts_re.search(m.group('track_index'))
3084 pts = (int(m1.group('mins')) * 60 + int(m1.group('secs'))) * 90000
3085 SongList.append((Item(text = title, filename = songfilename, title = title, artist = performer, album = album,join = False, PTS = pts),))
3089 def readM3U(self, filename):
3093 m3ufile = open(filename, "r")
3096 for line in m3ufile.readlines():
3097 entry = line.strip()
3099 if entry.startswith("#EXTINF:"):
3100 extinf = entry.split(',',1)
3102 displayname = extinf[1]
3103 elif entry[0] != "#":
3105 songfilename = entry
3107 songfilename = os_path.join(os_path.dirname(filename),entry)
3113 SongList.append((Item(text = text, filename = songfilename),))
3117 def readPLS(self, filename):
3121 plsfile = open(filename, "r")
3124 entry = plsfile.readline().strip()
3125 if entry == "[playlist]":
3127 entry = plsfile.readline().strip()
3130 if entry[0:4] == "File":
3131 pos = entry.find('=') + 1
3132 newentry = entry[pos:]
3133 SongList.append((Item(text = newentry, filename = newentry),))
3135 SongList = self.readM3U(filename)
3139 def green_pressed(self):
3142 for root, subFolders, files in os_walk(self["list"].getCurrentDirectory()):
3144 for filename in files:
3145 if filename.lower().endswith(".mp3") or filename.lower().endswith(".flac") or filename.lower().endswith(".m4a") or filename.lower().endswith(".ogg"):
3146 SongList.append((Item(text = filename, filename = os_path.join(root,filename)),))
3147 if self.player is not None:
3148 self.player.doClose()
3150 self.startMerlinPlayerScreenTimer.stop()
3151 count = len(SongList)
3153 self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,SongList, 0, False, self.currentService, self.serviceList)
3154 self.session.execDialog(self.player)
3156 self.session.open(MessageBox, _("No music files found!"), type = MessageBox.TYPE_INFO,timeout = 20 )
3159 if self["list"].canDescent():
3160 self["list"].descent()
3167 currentFilename = self["list"].getFilename()
3168 if currentFilename.lower().endswith(".m3u"):
3169 SongList = self.readM3U(os_path.join(self["list"].getCurrentDirectory(),currentFilename))
3170 elif currentFilename.lower().endswith(".pls"):
3171 SongList = self.readPLS(os_path.join(self["list"].getCurrentDirectory(),currentFilename))
3172 elif currentFilename.lower().endswith(".cue"):
3173 SongList = self.readCUE(os_path.join(self["list"].getCurrentDirectory(),currentFilename))
3175 files = os_listdir(self["list"].getCurrentDirectory())
3177 for filename in files:
3178 if filename.lower().endswith(".mp3") or filename.lower().endswith(".flac") or filename.lower().endswith(".m4a") or filename.lower().endswith(".ogg"):
3179 SongList.append((Item(text = filename, filename = os_path.join(self["list"].getCurrentDirectory(),filename)),))
3180 if self["list"].getFilename() == filename:
3184 if self.player is not None:
3185 self.player.doClose()
3187 self.startMerlinPlayerScreenTimer.stop()
3188 count = len(SongList)
3190 self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,SongList, foundIndex, False, self.currentService, self.serviceList)
3191 self.session.execDialog(self.player)
3193 self.session.open(MessageBox, _("No music files found!"), type = MessageBox.TYPE_INFO,timeout = 20 )
3196 self.startMerlinPlayerScreenTimer.stop()
3197 self.session.open(MerlinMusicPlayerSetup, True)
3199 def menu_pressed(self):
3200 self.startMerlinPlayerScreenTimer.stop()
3201 options = [(_("Configuration"), self.config),]
3202 if not self["list"].canDescent():
3203 filename = self["list"].getFilename()
3204 if filename.lower().endswith(".mp3") or filename.lower().endswith(".flac") or filename.lower().endswith(".m4a") or filename.lower().endswith(".ogg"):
3205 options.extend(((_("Clear current songlist and play selected entry"), self.stopPlayingAndAppendFileToSongList),))
3206 options.extend(((_("Append file to current songlist"), self.appendFileToSongList),))
3207 if self.player is not None and self.player.songList:
3208 options.extend(((_("Insert file to current songlist and play next"), self.insertFileToSongList),))
3209 self.session.openWithCallback(self.menuCallback, ChoiceBox,list = options)
3211 def menuCallback(self, ret):
3214 def stopPlayingAndAppendFileToSongList(self):
3215 self.startMerlinPlayerScreenTimer.stop()
3216 if self.player is not None:
3217 self.player.doClose()
3219 self.appendFileToSongList()
3220 self.startMerlinPlayerScreenTimer.start(START_MERLIN_PLAYER_SCREEN_TIMER_VALUE)
3222 def appendFileToSongList(self):
3223 playerAvailable = self.player is not None and self.player.songList
3224 filename = self["list"].getFilename()
3225 if filename.lower().endswith(".mp3") or filename.lower().endswith(".flac") or filename.lower().endswith(".m4a") or filename.lower().endswith(".ogg"):
3227 a = Item(text = filename, filename = os_path.join(self["list"].getCurrentDirectory(),filename))
3229 self.player.songList.append((a,))
3230 self.player.origSongList.append((a,))
3232 SongList.append((a,))
3233 if not playerAvailable:
3234 if self.player is not None:
3235 self.player.doClose()
3237 self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,SongList, 0, False, self.currentService, self.serviceList)
3238 self.player.playSong(self.player.songList[self.player.currentIndex][0].filename)
3239 self.player["coverArt"].onShow()
3240 self.player.init = 1
3242 self.player["nextTitle"].setText(self.player.getNextTitle())
3243 self.session.open(MessageBox, _("%s\nappended to songlist")%a.text, type = MessageBox.TYPE_INFO,timeout = 3 )
3245 def insertFileToSongList(self):
3246 if self.player is not None and self.player.songList:
3247 index = self.player.currentIndex
3248 filename = self["list"].getFilename()
3249 if filename.lower().endswith(".mp3") or filename.lower().endswith(".flac") or filename.lower().endswith(".m4a") or filename.lower().endswith(".ogg"):
3250 a = Item(text = filename, filename = os_path.join(self["list"].getCurrentDirectory(),filename))
3251 self.player.songList.insert(index+1,(a,))
3252 self.player.origSongList.insert(index+1,(a,))
3253 self.player["nextTitle"].setText(self.player.getNextTitle())
3254 self.session.open(MessageBox, _("%s\ninserted and will be played as next song")%a.text, type = MessageBox.TYPE_INFO,timeout = 3 )
3256 self.appendFileToSongList()
3258 def info_pressed(self):
3259 self.startMerlinPlayerScreenTimer.stop()
3260 if self.player is not None:
3261 if self.player.songList:
3262 self.session.execDialog(self.player)
3264 def moveright(self):
3265 self["list"].pageDown()
3269 self["list"].pageUp()
3280 def updateTarget(self):
3281 currFolder = self["list"].getCurrentDirectory()
3282 if currFolder is None:
3283 currFolder = ("Invalid Location")
3284 self["headertext"].setText(_("Filelist: %s") % currFolder)
3287 def lcdupdate(self):
3288 self.startMerlinPlayerScreenTimer.start(START_MERLIN_PLAYER_SCREEN_TIMER_VALUE)
3289 index = self["list"].getSelectionIndex()
3290 sel = self["list"].list[index]
3292 if sel[0][1] == True:
3294 self.summaries.setText(text,1)
3298 index = len(self["list"].list) -1
3299 sel = self["list"].list[index]
3301 if sel[0][1] == True:
3303 self.summaries.setText(text,3)
3305 index = self["list"].getSelectionIndex() + 1
3306 if index > (len(self["list"].list) -1):
3308 sel = self["list"].list[index]
3310 if sel[0][1] == True:
3312 self.summaries.setText(text,4)
3314 def __onClose(self):
3315 self.startMerlinPlayerScreenTimer.stop()
3316 if self.player is not None:
3317 self.player.closePlayer()
3318 self.player.doClose()
3320 if self.serviceList is None:
3321 self.session.nav.playService(self.currentService)
3323 current = ServiceReference(self.serviceList.getCurrentSelection())
3324 self.session.nav.playService(current.ref)
3325 if config.plugins.merlinmusicplayer.rememberlastfilebrowserpath.value:
3327 config.plugins.merlinmusicplayer.defaultfilebrowserpath.value = self["list"].getCurrentDirectory()
3328 config.plugins.merlinmusicplayer.defaultfilebrowserpath.save()
3332 def createSummary(self):
3333 return MerlinMusicPlayerLCDScreenText
3335 def main(session,**kwargs):
3336 if kwargs.has_key("servicelist"):
3337 servicelist = kwargs["servicelist"]
3340 session.open(iDreamMerlin, servicelist)
3342 def merlinmusicplayerfilelist(session,**kwargs):
3343 if kwargs.has_key("servicelist"):
3344 servicelist = kwargs["servicelist"]
3347 session.open(MerlinMusicPlayerFileList, servicelist)
3349 def menu_merlinmusicplayerfilelist(menuid, **kwargs):
3350 if menuid == "mainmenu":
3351 return [(_("Merlin Music Player"), merlinmusicplayerfilelist, "merlin_music_player", 46)]
3354 def menu_idream(menuid, **kwargs):
3355 if menuid == "mainmenu":
3356 return [(_("iDream"), main, "idream", 47)]
3359 def Plugins(**kwargs):
3361 list = [PluginDescriptor(name="Merlin iDream", description=_("Dreambox Music Database"), where = [PluginDescriptor.WHERE_PLUGINMENU], icon = "iDream.png", fnc=main)]
3362 list.append(PluginDescriptor(name="Merlin Music Player", description=_("Merlin Music Player"), where = [PluginDescriptor.WHERE_PLUGINMENU], icon = "MerlinMusicPlayer.png", fnc=merlinmusicplayerfilelist))
3363 if config.plugins.merlinmusicplayer.idreamextendedpluginlist.value:
3364 list.append(PluginDescriptor(name="iDream", description=_("Dreambox Music Database"), where = [PluginDescriptor.WHERE_EXTENSIONSMENU], fnc=main))
3365 if config.plugins.merlinmusicplayer.merlinmusicplayerextendedpluginlist.value:
3366 list.append(PluginDescriptor(name="Merlin Music Player", description=_("Merlin Music Player"), where = [PluginDescriptor.WHERE_EXTENSIONSMENU], fnc=merlinmusicplayerfilelist))
3367 if config.plugins.merlinmusicplayer.merlinmusicplayermainmenu.value:
3368 list.append(PluginDescriptor(name="Merlin Music Player", description=_("Merlin Music Player"), where = [PluginDescriptor.WHERE_MENU], fnc=menu_merlinmusicplayerfilelist))
3369 if config.plugins.merlinmusicplayer.idreammainmenu.value:
3370 list.append(PluginDescriptor(name="iDream", description=_("iDream"), where = [PluginDescriptor.WHERE_MENU], fnc=menu_idream))