Merlin Music Player and iDream - initial checkin
[enigma2-plugins.git] / merlinmusicplayer / src / plugin.py
1 #
2 #  Merlin Music Player E2
3 #
4 #
5 #  Coded by Dr.Best (c) 2010
6 #  Support: www.dreambox-tools.info
7 #
8 #  This plugin is licensed under the Creative Commons 
9 #  Attribution-NonCommercial-ShareAlike 3.0 Unported 
10 #  License. To view a copy of this license, visit
11 #  http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
12 #  Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
13 #
14 #  Alternatively, this plugin may be distributed and executed on hardware which
15 #  is licensed by Dream Multimedia GmbH.
16
17 #  This plugin is NOT free software. It is open source, you are allowed to
18 #  modify it (if you keep the license), but it may not be commercially 
19 #  distributed other than under the conditions noted above.
20 #
21
22 from Plugins.Plugin import PluginDescriptor
23 from Screens.Screen import Screen
24 from Components.ActionMap import ActionMap, NumberActionMap
25 from Components.Label import Label
26 from enigma import RT_VALIGN_CENTER, RT_HALIGN_LEFT, RT_HALIGN_RIGHT, RT_HALIGN_CENTER, gFont, eListbox,ePoint, eListboxPythonMultiContent
27
28 # merlin mp3 player
29 import merlinmp3player
30 ENIGMA_MERLINPLAYER_ID = 0x1014
31
32 from Components.FileList import FileList
33 from enigma import eServiceReference, eTimer
34 from os import path as os_path, mkdir as os_mkdir, listdir as os_listdir, walk as os_walk
35 from Components.ProgressBar import ProgressBar
36 from twisted.internet import reactor, defer
37 from twisted.web import client
38 from twisted.web.client import HTTPClientFactory, downloadPage
39 from enigma import getDesktop
40 from Screens.MessageBox import MessageBox
41 from Components.GUIComponent import GUIComponent
42 from enigma import ePicLoad
43 from xml.etree.cElementTree import fromstring as cet_fromstring
44 from urllib import quote
45 from Components.ScrollLabel import ScrollLabel
46 from Components.AVSwitch import AVSwitch
47 from Tools.Directories import fileExists, resolveFilename, SCOPE_CURRENT_SKIN
48 from Tools.LoadPixmap import LoadPixmap
49 from Components.Pixmap import Pixmap, MultiPixmap
50 from Components.ServicePosition import ServicePositionGauge
51 from Screens.InfoBarGenerics import  InfoBarSeek, InfoBarNotifications
52 from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
53 from enigma import iPlayableService, iServiceInformation
54 from Components.Sources.StaticText import StaticText
55 from Screens.ChoiceBox import ChoiceBox
56 from Screens.VirtualKeyBoard import VirtualKeyBoard
57 from Tools.BoundFunction import boundFunction
58 from sqlite3 import dbapi2 as sqlite
59 from mutagen.flac import FLAC
60 from mutagen.mp3 import MP3
61 from mutagen.id3 import ID3
62 from mutagen.easyid3 import EasyID3
63 from mutagen.easymp4 import EasyMP4
64 from mutagen.oggvorbis import OggVorbis
65 import datetime
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
70
71
72 config.plugins.merlinmusicplayer = ConfigSubsection()
73 config.plugins.merlinmusicplayer.hardwaredecoder = ConfigYesNo(default = True)
74 config.plugins.merlinmusicplayer.startlastsonglist = ConfigYesNo(default = True)
75 config.plugins.merlinmusicplayer.lastsonglistindex = ConfigInteger(-1)
76 config.plugins.merlinmusicplayer.databasepath = ConfigDirectory(default = "/hdd/")
77 config.plugins.merlinmusicplayer.usegoogleimage = ConfigYesNo(default = True)
78 config.plugins.merlinmusicplayer.googleimagepath = ConfigDirectory(default = "/hdd/")
79 config.plugins.merlinmusicplayer.usescreensaver = ConfigYesNo(default = True)
80 config.plugins.merlinmusicplayer.screensaverwait = ConfigInteger(1,limits = (1, 60))
81 config.plugins.merlinmusicplayer.idreamextendedpluginlist = ConfigYesNo(default = True)
82 config.plugins.merlinmusicplayer.merlinmusicplayerextendedpluginlist = ConfigYesNo(default = True)
83 config.plugins.merlinmusicplayer.defaultfilebrowserpath = ConfigDirectory(default = "/hdd/")
84 config.plugins.merlinmusicplayer.rememberlastfilebrowserpath = ConfigYesNo(default = True)
85
86 from enigma import ePythonMessagePump
87 from threading import Thread, Lock
88
89 class ThreadQueue:
90         def __init__(self):
91                 self.__list = [ ]
92                 self.__lock = Lock()
93
94         def push(self, val):
95                 lock = self.__lock
96                 lock.acquire()
97                 self.__list.append(val)
98                 lock.release()
99
100         def pop(self):
101                 lock = self.__lock
102                 lock.acquire()
103                 ret = self.__list.pop()
104                 lock.release()
105                 return ret
106
107 THREAD_WORKING = 1
108 THREAD_FINISHED = 2
109
110 class PathToDatabase(Thread):
111         def __init__(self):
112                 Thread.__init__(self)
113                 self.__running = False
114                 self.__cancel = False
115                 self.__path = None
116                 self.__messages = ThreadQueue()
117                 self.__messagePump = ePythonMessagePump()
118
119         def __getMessagePump(self):
120                 return self.__messagePump
121
122         def __getMessageQueue(self):
123                 return self.__messages
124
125         def __getRunning(self):
126                 return self.__running
127
128         def Cancel(self):
129                 self.__cancel = True
130
131         MessagePump = property(__getMessagePump)
132         Message = property(__getMessageQueue)
133         isRunning = property(__getRunning)
134
135         def Start(self, path):
136                 if not self.__running:
137                         self.__path = path
138                         self.start()
139
140         def run(self):
141                 mp = self.__messagePump
142                 self.__running = True
143                 self.__cancel = False
144                 if self.__path:
145                         connection = OpenDatabase()
146                         connection.text_factory = str
147                         cursor = connection.cursor()
148                         counter = 0
149                         for root, subFolders, files in os_walk(self.__path):
150                                 if self.__cancel:
151                                         break
152                                 for filename in files:
153                                         if self.__cancel:
154                                                 break
155                                         audio, isAudio, title, genre,artist,album,tracknr,track,date,length,bitrate = getID3Tags(root,filename)
156                                         if  audio:      
157                                                 # 1. Artist
158                                                 artistID = -1
159                                                 cursor.execute("""SELECT artist_id FROM Artists WHERE artist = "%s";""" % (artist))
160                                                 row = cursor.fetchone()
161                                                 if row is None:
162                                                                 cursor.execute("""INSERT INTO Artists (artist) VALUES("%s");""" % (artist))
163                                                                 artistID = cursor.lastrowid
164                                                 else:
165                                                                 artistID = row[0]
166                                                 # 2. Album
167                                                 albumID = -1
168                                                 cursor.execute("""SELECT album_id FROM Album WHERE album_text = "%s";""" % (album))
169                                                 row = cursor.fetchone()
170                                                 if row is None:
171                                                                 cursor.execute("""INSERT INTO Album (album_text) VALUES("%s");""" % (album))
172                                                                 albumID = cursor.lastrowid
173                                                 else:
174                                                                 albumID = row[0]
175
176                                                 # 3. Genre
177                                                 genreID = -1            
178                                                 cursor.execute("""SELECT genre_id FROM Genre WHERE genre_text = "%s";""" % (genre))
179                                                 row = cursor.fetchone()
180                                                 if row is None:
181                                                                 cursor.execute("""INSERT INTO Genre (genre_text) VALUES("%s");""" % (genre))
182                                                                 genreID = cursor.lastrowid
183                                                 else:
184                                                                 genreID = row[0]
185                                                         
186                                                 # 4. Songs
187                                                 try:
188                                                         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))
189                                                         self.__messages.push((THREAD_WORKING, _("%s\n added to database") % os_path.join(root,filename)))
190                                                         mp.send(0)
191                                                         counter +=1
192                                                 except sqlite.IntegrityError:
193                                                         self.__messages.push((THREAD_WORKING, _("%s\n already exists in database!") % os_path.join(root,filename)))
194                                                         mp.send(0)
195                                                 audio = None
196                         if not self.__cancel:
197                                 connection.commit()
198                         cursor.close()  
199                         connection.close()
200                         if self.__cancel:
201                                 self.__messages.push((THREAD_FINISHED, _("Process aborted.\n 0 files added to database!\nPress OK to close.") ))
202                         else:   
203                                 self.__messages.push((THREAD_FINISHED, _("%d files added to database!\nPress OK to close." % counter)))
204                         mp.send(0)
205                         self.__running = False
206                         Thread.__init__(self)
207
208 pathToDatabase = PathToDatabase()
209
210
211 class iDreamAddToDatabase(Screen):
212         skin = """<screen name="iDreamAddToDatabase" position="center,center" size="560,320" title="Add music files to iDream database">
213                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
214                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
215                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
216                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
217                         <widget name="output" position="10,10" size="540,300" valign="center" halign="center" font="Regular;22" />
218                         <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" />
219                         <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" />
220                 </screen>"""
221         def __init__(self, session, initDir):
222                 Screen.__init__(self, session)
223                 self["actions"] = ActionMap(["WizardActions", "ColorActions"],
224                 {
225                         "back": self.cancel,
226                         "green": self.green,
227                         "red": self.cancel,
228                         "ok": self.green,
229                         
230                 }, -1)
231                 self["key_red"] = StaticText(_("Cancel"))
232                 self["key_green"] = StaticText("Close")
233                 self["output"] = Label()
234                 self.onClose.append(self.__onClose)
235                 pathToDatabase.MessagePump.recv_msg.get().append(self.gotThreadMsg)     
236                 if not pathToDatabase.isRunning and initDir:
237                         pathToDatabase.Start(initDir)
238
239         def gotThreadMsg(self, msg):
240                 msg = pathToDatabase.Message.pop()
241                 self["output"].setText(msg[1])
242                 if msg[0] == THREAD_FINISHED:
243                         self["key_red"].setText("")
244         
245         def green(self):
246                 self.close()
247         
248         def cancel(self):
249                 if pathToDatabase.isRunning:
250                         pathToDatabase.Cancel()
251
252         def __onClose(self):
253                 pathToDatabase.MessagePump.recv_msg.get().remove(self.gotThreadMsg)     
254                 
255
256 class myHTTPClientFactory(HTTPClientFactory):
257         def __init__(self, url, method='GET', postdata=None, headers=None,
258         agent="SHOUTcast", timeout=0, cookies=None,
259         followRedirect=1, lastModified=None, etag=None):
260                 HTTPClientFactory.__init__(self, url, method=method, postdata=postdata,
261                 headers=headers, agent=agent, timeout=timeout, cookies=cookies,followRedirect=followRedirect)
262
263 def sendUrlCommand(url, contextFactory=None, timeout=60, *args, **kwargs):
264         scheme, host, port, path = client._parse(url)
265         factory = myHTTPClientFactory(url, *args, **kwargs)
266         reactor.connectTCP(host, port, factory, timeout=timeout)
267         return factory.deferred
268
269
270 class MethodArguments:
271         def __init__(self, method = None, arguments = None):
272                 self.method = method
273                 self.arguments = arguments
274
275 class CacheList:
276         def __init__(self, cache = True, index = 0, listview = [], headertext = "", methodarguments = None):
277                 self.cache = cache
278                 self.index = index
279                 self.listview = listview
280                 self.headertext = headertext
281                 self.methodarguments = methodarguments
282
283 class Item:
284         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):
285                 self.text = text
286                 self.mode = mode
287                 self.navigator = navigator
288                 self.artistID = artistID
289                 self.albumID = albumID
290                 self.title = title
291                 self.artist = artist
292                 self.filename = filename
293                 if bitrate is not None:
294                         if join:
295                                 self.bitrate = "%d Kbps" % bitrate
296                         else:
297                                 self.bitrate = bitrate
298                 else:
299                         self.bitrate = ""
300                 self.length = length
301                 self.genre = genre
302                 if track is not None:
303                         self.track = "Track %s" % track
304                 else:
305                         self.track = ""
306                 if date is not None:
307                         if join:
308                                 self.date = " (%s)" % date
309                         else:
310                                 self.date = date
311                 else:
312                         self.date = ""
313                 self.album = album
314                 self.playlistID = playlistID
315                 self.genreID = genreID
316                 self.songID = songID
317                 self.PTS = PTS
318
319
320 def OpenDatabase():
321                 connectstring = os_path.join(config.plugins.merlinmusicplayer.databasepath.value ,"iDream.db")
322                 db_exists = False
323                 if os_path.exists(connectstring):
324                         db_exists = True
325                 connection = sqlite.connect(connectstring)
326                 if not db_exists :
327                                 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);')
328                                 connection.execute('CREATE TABLE IF NOT EXISTS Artists (artist_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, artist TEXT NOT NULL UNIQUE);')
329                                 connection.execute('CREATE TABLE IF NOT EXISTS Album (album_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, album_text TEXT NOT NULL UNIQUE);')
330                                 connection.execute('CREATE TABLE IF NOT EXISTS Genre (genre_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, genre_text TEXT NOT NULL UNIQUE);')
331                                 connection.execute('CREATE TABLE IF NOT EXISTS Playlists (playlist_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, playlist_text TEXT NOT NULL);')
332                                 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);')
333                                 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);')
334                 return connection
335
336 def getID3Tags(root,filename):
337         audio = None
338         isFlac = False
339         isAudio = True
340         title = ""
341         genre = ""
342         artist = ""
343         album = ""
344         tracknr = -1
345         track = None
346         date = None
347         length = ""
348         bitrate = None
349         if filename.lower().endswith(".mp3"):
350                 try: audio = MP3(os_path.join(root,filename), ID3 = EasyID3)
351                 except: audio = None
352         elif filename.lower().endswith(".flac"):
353                 try: 
354                         audio = FLAC(os_path.join(root,filename))
355                         isFlac = True
356                 except: audio = None
357         elif filename.lower().endswith(".m4a"):
358                 try: audio = EasyMP4(os_path.join(root,filename))
359                 except: audio = None
360         elif filename.lower().endswith(".ogg"):
361                 try: audio = OggVorbis(os_path.join(root,filename))
362                 except: audio = None
363         else:
364                 isAudio = False
365         if audio:
366                 title = audio.get('title', [filename])[0]
367                 genre = audio.get('genre', ['n/a'])[0]
368                 artist = audio.get('artist', ['n/a'])[0]
369                 album = audio.get('album', ['n/a'])[0]
370                 tracknr = int(audio.get('tracknumber', ['-1'])[0].split("/")[0])
371                 track = audio.get('tracknumber', [None])[0]
372                 date = audio.get('date', [None])[0]
373                 
374                 length = str(datetime.timedelta(seconds=int(audio.info.length)))
375                 if not isFlac:
376                         bitrate = audio.info.bitrate / 1000
377                 else:
378                         bitrate = None
379         else:
380                 if isAudio:
381                         title = os_path.splitext(os_path.basename(filename))[0]
382                         genre = "n/a"
383                         artist = "n/a"
384                         album = "n/a"
385                         tracknr = -1
386                         track = None
387                         date = None
388                         length = ""
389                         bitrate = None
390
391         return audio, isAudio, title.encode("utf-8", 'ignore'), genre.encode("utf-8", 'ignore'),artist.encode("utf-8", 'ignore'),album.encode("utf-8", 'ignore'),tracknr,track,date,length.encode("utf-8", 'ignore'),bitrate
392
393 class MerlinMusicPlayerScreenSaver(Screen):
394
395         sz_w = getDesktop(0).size().width()
396         if sz_w == 1280:
397                 skin = """
398                         <screen name="MerlinMusicPlayerScreenSaver" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="MerlinMusicPlayerScreenSaver">
399                         <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" />
400                         <widget name="display" position="200,315" size="1280,24" zPosition="1" transparent="1" font="Regular;20" foregroundColor="#fcc000" />
401                         </screen>"""
402         elif sz_w == 1024:
403                 skin = """
404                         <screen name="MerlinMusicPlayerScreenSaver" position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="MerlinMusicPlayerScreenSaver">
405                         <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" />
406                         <widget name="display" position="200,315" size="1024,24" zPosition="1" transparent="1" font="Regular;20" foregroundColor="#fcc000" />
407                         </screen>"""
408
409         else:
410                 skin = """
411                         <screen name="MerlinMusicPlayerScreenSaver" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="MerlinMusicPlayerScreenSaver">
412                         <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" />
413                         <widget name="display" position="200,315" size="720,24" zPosition="1" transparent="1" font="Regular;20" foregroundColor="#fcc000" />
414                         </screen>"""
415                 
416         
417         def __init__(self, session):
418                 self.session = session
419                 Screen.__init__(self, session)
420                 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EventViewActions"],
421                 {
422                         "back": self.close,
423                         "right": self.close,
424                         "left": self.close,
425                         "up": self.close,
426                         "down": self.close,
427                         "ok": self.close,
428                         "pageUp": self.close,
429                         "pageDown": self.close,
430                         "yellow": self.close,
431                         "blue": self.close,
432                         "red": self.close,
433                         "green": self.close,
434                         "right": self.close,
435                         "left": self.close,
436                         "prevBouquet": self.close,
437                         "nextBouquet": self.close,
438                         "info": self.close,
439
440                 }, -1)
441                 self["coverArt"] = MerlinMediaPixmap()
442                 self.coverMoveTimer = eTimer()
443                 self.coverMoveTimer.timeout.get().append(self.moveCoverArt)
444                 self.coverMoveTimer.start(1)
445                 self["display"] = Label()
446
447         def updateDisplayText(self, text):
448                 self["display"].setText(text)
449
450         def updateLCD(self, text, line):
451                 self.summaries.setText(text,line)
452
453         def updateCover(self, filename = None, modus = 0):
454                 print "[MerlinMusicPlayerScreenSaver] updating coverart with filename = %s and modus = %d" % (filename, modus)
455                 if modus == 0:
456                         if filename:
457                                 self["coverArt"].showCoverFromFile(filename)
458                         else:
459                                 self["coverArt"].showDefaultCover()
460                 elif modus == 1:
461                         self["coverArt"].showDefaultCover()
462                 elif modus == 2:
463                         self["coverArt"].embeddedCoverArt()
464                 elif modus == 3:
465                         self["coverArt"].updateCoverArt(filename)
466                 elif modus == 4:
467                         self["coverArt"].showCoverFromFile(filename)
468
469         def moveCoverArt(self):
470                 x = randrange(getDesktop(0).size().width()-238)
471                 y = randrange(getDesktop(0).size().height()-238-28)
472                 self["coverArt"].move(ePoint(x,y))
473                 self["display"].move(ePoint(x,y+240))
474                 self.coverMoveTimer.start(15000)
475
476         def createSummary(self):
477                 return MerlinMusicPlayerLCDScreen
478
479 class MerlinMusicPlayerScreen(Screen, InfoBarBase, InfoBarSeek, InfoBarNotifications):
480         
481         sz_w = getDesktop(0).size().width()
482         if sz_w == 1280:
483                 skin = """
484                         <screen name="MerlinMusicPlayerScreen" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
485                         <eLabel backgroundColor="#999999" position="178,112" size="924,2" zPosition="1"/>
486                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="178,104" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>
487                         <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"/>
488                         <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmp3pHD.png" position="128,72" size="1024,576"/>
489                         <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" />
490                         <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr.png" position="688,232" size="150,20" transparent="1" zPosition="1"/>
491                         <widget name="title" position="362,415" size="600,28" zPosition="1" transparent="1" font="Regular;24" foregroundColor="#fcc000" />
492                         <widget name="album" position="362,462" size="600,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
493                         <widget name="artist" position="362,492" size="600,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
494                         <widget name="genre" position="362,522" size="600,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
495                         <widget name="nextTitle" position="362,562" size="600,22" zPosition="1" transparent="1" font="Regular;16" foregroundColor="#f0f0f0" />
496                         <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"/>
497                         <widget source="session.CurrentService" render="Label" position="873,267" size="116,18" zPosition="1" font="Regular;18" halign="left" foregroundColor="#999999" transparent="1" >
498                                         <convert type="ServicePosition">Length,ShowHours</convert>
499                         </widget>
500                         <widget source="session.CurrentService" render="Label" position="684,292" size="198,20" zPosition="1" font="Regular;20" halign="left" foregroundColor="#fcc000" transparent="1" >
501                                         <convert type="ServicePosition">Position,ShowHours</convert>
502                         </widget>
503                         <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"/>
504                         <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"/>
505                         <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"/>
506                         </screen>"""
507         elif sz_w == 1024:
508                 skin = """
509                         <screen name="MerlinMusicPlayerScreen" position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
510                         <eLabel backgroundColor="#999999" position="50,40" size="924,2" zPosition="1"/>
511                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,32" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>
512                         <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"/>
513                         <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmp3pHD.png" position="0,0" size="1024,576"/>
514                         <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" />
515                         <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr.png" position="560,160" size="150,20" transparent="1" zPosition="1"/>
516                         <widget name="title" position="234,343" size="600,28" zPosition="1" transparent="1" font="Regular;24" foregroundColor="#fcc000" />
517                         <widget name="album" position="234,390" size="600,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
518                         <widget name="artist" position="234,420" size="600,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
519                         <widget name="genre" position="234,450" size="600,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
520                         <widget name="nextTitle" position="234,490" size="600,22" zPosition="1" transparent="1" font="Regular;16" foregroundColor="#f0f0f0" />
521                         <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"/>
522                         <widget source="session.CurrentService" render="Label" position="745,195" size="116,18" zPosition="1" font="Regular;18" halign="left" foregroundColor="#999999" transparent="1" >
523                                         <convert type="ServicePosition">Length,ShowHours</convert>
524                         </widget>
525                         <widget source="session.CurrentService" render="Label" position="556,220" size="198,20" zPosition="1" font="Regular;20" halign="left" foregroundColor="#fcc000" transparent="1" >
526                                         <convert type="ServicePosition">Position,ShowHours</convert>
527                         </widget>
528                         <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"/>
529                         <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"/>
530                         <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"/>
531                         </screen>"""
532         else:
533                 skin = """
534                         <screen name="MerlinMusicPlayerScreen" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
535                         <eLabel backgroundColor="#999999" position="50,50" size="620,2" zPosition="1"/>\r
536                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,40" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>\r
537                         <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"/>
538                         <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmp3p.png" position="120,350" size="33,162"/>
539                         <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" />
540                         <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/dvr.png" position="410,160" size="150,20" transparent="1" zPosition="1"/>
541                         <widget name="title" position="160,345" size="550,28" zPosition="1" transparent="1" font="Regular;24" foregroundColor="#fcc000" />
542                         <widget name="album" position="160,392" size="550,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
543                         <widget name="artist" position="160,422" size="550,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
544                         <widget name="genre" position="160,455" size="550,22" zPosition="1" transparent="1" font="Regular;18" foregroundColor="#999999" />
545                         <widget name="nextTitle" position="160,492" size="550,22" zPosition="1" transparent="1" font="Regular;16" foregroundColor="#f0f0f0" />
546                         <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"/>
547                         <widget source="session.CurrentService" render="Label" position="595,193" size="116,18" zPosition="1" font="Regular;18" halign="left" foregroundColor="#999999" transparent="1" >
548                                         <convert type="ServicePosition">Length,ShowHours</convert>
549                         </widget>
550                         <widget source="session.CurrentService" render="Label" position="406,220" size="198,20" zPosition="1" font="Regular;20" halign="left" foregroundColor="#fcc000" transparent="1" >
551                                         <convert type="ServicePosition">Position,ShowHours</convert>
552                         </widget>
553                         <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"/>
554                         <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"/>
555                         <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"/>
556                         </screen>"""
557                 
558         
559         def __init__(self, session, songlist, index, idreammode):
560                 self.session = session
561                 Screen.__init__(self, session)
562                 InfoBarNotifications.__init__(self)
563                 InfoBarBase.__init__(self)
564                 self["actions"] = ActionMap(["WizardActions", "MediaPlayerActions", "EPGSelectActions", "MediaPlayerSeekActions", "ColorActions"],
565                 {
566                         "back": self.closePlayer,
567                         "pause": self.pauseEntry,
568                         "stop": self.stopEntry,
569                         "right": self.playNext,
570                         "left": self.playPrevious,
571                         "up": self.showPlaylist,
572                         "down" : self.showPlaylist,
573                         "prevBouquet": self.shuffleList,
574                         "nextBouquet": self.repeatSong,
575                         "info" : self.showLyrics,
576                         "yellow": self.pauseEntry,
577                         "green": self.play,
578                         "input_date_time": self.config,
579                 }, -1)
580
581                 self.onClose.append(self.__onClose)
582                 self.session.nav.stopService()
583                 self["PositionGauge"] = ServicePositionGauge(self.session.nav)
584                 self["coverArt"] = MerlinMediaPixmap()
585                 self["repeat"] = MultiPixmap()
586                 self["shuffle"] = MultiPixmap()
587                 self["dvrStatus"] = MultiPixmap()
588                 self["title"] = Label()
589                 self["album"] = Label()
590                 self["artist"] = Label()
591                 self["genre"] = Label()
592                 self["nextTitle"] = Label()
593                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
594                         {
595                                 iPlayableService.evUpdatedInfo: self.__evUpdatedInfo,
596                                 iPlayableService.evUser+10: self.__evAudioDecodeError,
597                                 iPlayableService.evUser+12: self.__evPluginError,
598                                 iPlayableService.evUser+13: self.embeddedCoverArt,
599                                 iPlayableService.evStart: self.__serviceStarted,
600                         })
601
602                 InfoBarSeek.__init__(self, actionmap = "MediaPlayerSeekActions")
603                 self.songList = songlist
604                 self.origSongList = songlist[:]
605                 self.currentIndex = index
606                 self.shuffle = False
607                 self.repeat = False
608                 self.currentFilename = ""
609                 self.currentGoogleCoverFile = ""
610                 self.googleDownloadDir = os_path.join(config.plugins.merlinmusicplayer.googleimagepath.value, "downloaded_covers/" )
611                 if not os_path.exists(self.googleDownloadDir):
612                         os_mkdir(self.googleDownloadDir)
613                 self.init = 0
614                 self.onShown.append(self.__onShown)
615                 # for lcd
616                 self.currentTitle = ""
617                 self.nextTitle = ""
618                 self.screenSaverTimer = eTimer()
619                 self.screenSaverTimer.timeout.get().append(self.screenSaverTimerTimeout)
620                 self.screenSaverScreen = None
621
622                 self.iDreamMode = idreammode
623
624         def embeddedCoverArt(self):             
625                 self["coverArt"].embeddedCoverArt()
626                 if self.screenSaverScreen:
627                         self.screenSaverScreen.updateCover(modus = 2)
628
629         def screenSaverTimerTimeout(self):
630                 if config.plugins.merlinmusicplayer.usescreensaver.value:
631                         if self.screenSaverTimer.isActive():
632                                 self.screenSaverTimer.stop()
633                         if not self.screenSaverScreen:
634                                 self.screenSaverScreen = self.session.instantiateDialog(MerlinMusicPlayerScreenSaver)
635                                 self.session.execDialog(self.screenSaverScreen)
636                                 self.screenSaverScreen.updateLCD(self.currentTitle,1)
637                                 self.screenSaverScreen.updateLCD(self.nextTitle,4)
638                                 album = self["album"].getText()
639                                 if album:
640                                         text = "%s - %s" % (self["title"].getText(), album)
641                                 else:
642                                         text = self["title"].getText()
643                                 self.screenSaverScreen.updateDisplayText(text)
644                                 self.screenSaverScreen.updateCover(self["coverArt"].coverArtFileName, modus = 0)
645
646         def resetScreenSaverTimer(self):
647                 if config.plugins.merlinmusicplayer.usescreensaver.value and config.plugins.merlinmusicplayer.screensaverwait.value != 0:
648                         if self.screenSaverTimer.isActive():
649                                 self.screenSaverTimer.stop()
650                         self.screenSaverTimer.start(config.plugins.merlinmusicplayer.screensaverwait.value * 60000)
651
652         def __onShown(self):
653                 if self.init == 0:
654                         self.init = 1
655                         self["coverArt"].onShow()
656                         self.playSong(self.songList[self.currentIndex][0].filename)
657                 else:
658                         self.summaries.setText(self.currentTitle,1)
659                         self.summaries.setText(self.nextTitle,4)
660                         if self.screenSaverScreen:
661                                 self.screenSaverScreen.doClose()
662                                 self.screenSaverScreen = None
663                 self.resetScreenSaverTimer()
664                 
665         def __onClose(self):
666                 del self["coverArt"].picload
667                 self.seek = None
668
669         def config(self):
670                 if self.screenSaverTimer.isActive():
671                         self.screenSaverTimer.stop()
672                 self.session.openWithCallback(self.setupFinished, MerlinMusicPlayerSetup, False)
673         
674         def setupFinished(self, result):
675                 if result:
676                         self.googleDownloadDir = os_path.join(config.plugins.merlinmusicplayer.googleimagepath.value, "downloaded_covers/" )
677                         if not os_path.exists(self.googleDownloadDir):
678                                 os_mkdir(self.googleDownloadDir)
679                 self.resetScreenSaverTimer()
680
681         def closePlayer(self):  
682                 if config.plugins.merlinmusicplayer.startlastsonglist.value:
683                         config.plugins.merlinmusicplayer.lastsonglistindex.value = self.currentIndex
684                         config.plugins.merlinmusicplayer.lastsonglistindex.save()
685                         connection = OpenDatabase()
686                         connection.text_factory = str
687                         cursor = connection.cursor()
688                         cursor.execute("Delete from CurrentSongList;")
689                         for song in self.origSongList:
690                                 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))
691                         connection.commit()
692                         cursor.close()
693                         connection.close()
694                 if self.screenSaverTimer.isActive():
695                         self.screenSaverTimer.stop()
696                 self.close()
697
698         def playSong(self, filename):
699                 self.session.nav.stopService()
700                 self.seek = None
701                 self.currentFilename = filename
702                 if not config.plugins.merlinmusicplayer.hardwaredecoder.value and self.currentFilename.lower().endswith(".mp3") and self.songList[self.currentIndex][0].PTS is None:
703                         sref = eServiceReference(ENIGMA_MERLINPLAYER_ID, 0, self.currentFilename) # play mp3 file with merlinmp3player lib
704                         self.session.nav.playService(sref)
705                         if self.iDreamMode:
706                                 self.updateMusicInformation( self.songList[self.currentIndex][0].artist, self.songList[self.currentIndex][0].title, 
707                                         self.songList[self.currentIndex][0].album, self.songList[self.currentIndex][0].genre, self.songList[self.currentIndex][0].date, clear = True )
708                         else:
709                                 path,filename = os_path.split(self.currentFilename)
710                                 audio, isAudio, title, genre,artist,album,tracknr,track,date,length,bitrate = getID3Tags(path,filename)
711                                 if audio:
712                                         if date:
713                                                 year = "(%s)" % str(date)
714                                         else:
715                                                 year = ""
716                                         self.updateMusicInformation( artist, title, album, genre, year, clear = True )
717                                 else:
718                                         self.updateMusicInformation( title = title, clear = True)
719                                 audio = None
720                 else:
721                         sref = eServiceReference(4097, 0, self.currentFilename)
722                         self.session.nav.playService(sref)
723                         if self.songList[self.currentIndex][0].PTS is not None:
724                                 service = self.session.nav.getCurrentService()
725                                 if service:
726                                         self.seek = service.seek()
727                                 self.updateMusicInformationCUE()
728                                 self.ptsTimer = eTimer()
729                                 self.ptsTimer.callback.append(self.ptsTimerCallback)
730                                 self.ptsTimer.start(1000)
731                 self["nextTitle"].setText(self.getNextTitle())
732
733         def ptsTimerCallback(self):
734                 if self.seek:
735                         pts = self.seek.getPlayPosition()
736                         index = 0
737                         currentIndex = 0
738                         for songs in self.songList:
739                                 if pts[1] > songs[0].PTS:
740                                         currentIndex = index
741                                 else:
742                                         break
743                                 index +=1
744                         if currentIndex != self.currentIndex:
745                                 self.currentIndex = currentIndex
746                                 self.updateMusicInformationCUE()
747                 self.ptsTimer.start(1000)
748
749         def updateMusicInformationCUE(self):
750                 self.updateSingleMusicInformation("artist", self.songList[self.currentIndex][0].artist, True)
751                 self.updateSingleMusicInformation("title", self.songList[self.currentIndex][0].title, True)
752                 self.updateSingleMusicInformation("album", self.songList[self.currentIndex][0].album, True)
753                 self.summaries.setText(self.songList[self.currentIndex][0].title,1)
754                 if self.screenSaverScreen:
755                         self.screenSaverScreen.updateLCD(self.songList[self.currentIndex][0].title,1)
756                         if self.songList[self.currentIndex][0].album:
757                                 self.screenSaverScreen.updateDisplayText("%s - %s" % (self.songList[self.currentIndex][0].title,self.songList[self.currentIndex][0].album))
758                         else:
759                                 self.screenSaverScreen.updateDisplayText(self.songList[self.currentIndex][0].title)
760                 self.updateCover(self.songList[self.currentIndex][0].artist, self.songList[self.currentIndex][0].album)
761                 self.currentTitle = self.songList[self.currentIndex][0].title
762                 self["nextTitle"].setText(self.getNextTitle())
763
764         def __serviceStarted(self):
765                 self["dvrStatus"].setPixmapNum(0)
766
767         def __evUpdatedInfo(self):
768                 currPlay = self.session.nav.getCurrentService()
769                 if currPlay is not None:
770                         sTitle = currPlay.info().getInfoString(iServiceInformation.sTagTitle)
771                         sAlbum = currPlay.info().getInfoString(iServiceInformation.sTagAlbum)
772                         sArtist = currPlay.info().getInfoString(iServiceInformation.sTagArtist)
773                         sGenre = currPlay.info().getInfoString(iServiceInformation.sTagGenre)
774                         sYear = currPlay.info().getInfoString(iServiceInformation.sTagDate)
775                         if sYear:
776                                 sYear = "(%s)" % sYear
777                         if not sTitle:
778                                 sTitle = os_path.splitext(os_path.basename(self.currentFilename))[0]
779                         
780                         if self.songList[self.currentIndex][0].PTS is None:
781                                 self.updateMusicInformation( sArtist, sTitle, sAlbum, sGenre, sYear, clear = True )
782                         else:
783                                 self.updateSingleMusicInformation("genre", sGenre, True)
784                 else:
785                         self.updateMusicInformation()
786
787         def updateMusicInformation(self, artist = "", title = "", album = "", genre = "", year = "", clear = False):
788                 if year and album:
789                         album = "%s %s" % (album, year)
790                 self.updateSingleMusicInformation("artist", artist, clear)
791                 self.updateSingleMusicInformation("title", title, clear)
792                 self.updateSingleMusicInformation("album", album, clear)
793                 self.updateSingleMusicInformation("genre", genre, clear)
794                 self.currentTitle = title
795                 if not self.iDreamMode and self.songList[self.currentIndex][0].PTS is None:
796                         # for lyrics
797                         self.songList[self.currentIndex][0].title = title
798                         self.songList[self.currentIndex][0].artist = artist
799                 self.summaries.setText(title,1)
800                 if self.screenSaverScreen:
801                         self.screenSaverScreen.updateLCD(title,1)
802                         if album:
803                                 self.screenSaverScreen.updateDisplayText("%s - %s" % (title,album))
804                         else:
805                                 self.screenSaverScreen.updateDisplayText(title)
806                 self.updateCover(artist, album)
807
808         def updateCover(self, artist, album):
809                 hasCover = False
810                 audio = None
811                 audiotype = 0
812                 if self.currentFilename.lower().endswith(".mp3"):
813                         try: 
814                                 audio = ID3(self.currentFilename)
815                                 audiotype = 1
816                         except: audio = None
817                 elif self.currentFilename.lower().endswith(".flac"):
818                         try: 
819                                 audio = FLAC(self.currentFilename)
820                                 audiotype = 2
821                         except: audio = None
822                 elif self.currentFilename.lower().endswith(".m4a"):
823                         try: 
824                                 audio = MP4(self.currentFilename)
825                                 audiotype = 3
826                         except: audio = None
827                 elif self.currentFilename.lower().endswith(".ogg"):
828                         try:
829                                 audio = OggVorbis(self.currentFilename)
830                                 audiotype = 4
831                         except: audio = None
832                 if audio:
833                         if audiotype == 1:
834                                 apicframes = audio.getall("APIC")
835                                 if len(apicframes) >= 1:
836                                         hasCover = True
837                                         if not config.plugins.merlinmusicplayer.hardwaredecoder.value:
838                                                 coverArtFile = file("/tmp/.id3coverart", 'wb')
839                                                 coverArtFile.write(apicframes[0].data)
840                                                 coverArtFile.close()
841                                                 self["coverArt"].embeddedCoverArt()
842                                                 if self.screenSaverScreen:
843                                                         self.screenSaverScreen.updateCover(modus = 2)
844                         elif audiotype == 2:
845                                 if len(audio.pictures) >= 1:
846                                         hasCover = True
847                         elif audiotype == 3:
848                                 if 'covr' in audio.tags:
849                                         hasCover = True
850                         elif audiotype == 4:
851                                 if 'METADATA_BLOCK_PICTURE' in audio.tags:
852                                         hasCover = True
853                         audio = None
854                 if not hasCover:
855                         if not self["coverArt"].updateCoverArt(self.currentFilename):
856                                 if config.plugins.merlinmusicplayer.usegoogleimage.value:
857                                         self.getGoogleCover(artist, album)
858                                 else:
859                                         self["coverArt"].showDefaultCover()
860                                         if self.screenSaverScreen:
861                                                 self.screenSaverScreen.updateCover(modus = 1)
862                         else:
863                                 if self.screenSaverScreen:
864                                         self.screenSaverScreen.updateCover(filename = self.currentFilename, modus = 3)
865                                 self.currentGoogleCoverFile = ""
866                 else:
867                         self.currentGoogleCoverFile = ""
868
869         def updateSingleMusicInformation(self, name, info, clear):
870                 if info != "" or clear:
871                         if self[name].getText() != info:
872                                 self[name].setText(info)
873
874         def getGoogleCover(self, artist,album):
875                 if artist != "" and album != "":
876                         url = "http://images.google.de/images?q=%s+%s&btnG=Bilder-Suche" % (quote(album),quote(artist))
877                         sendUrlCommand(url, None,10).addCallback(self.googleImageCallback).addErrback(self.coverDownloadFailed)
878                 else:
879                         self["coverArt"].showDefaultCover()
880
881         def googleImageCallback(self, result):
882                 foundPos = result.find("imgres?imgurl=")
883                 foundPos2 = result.find("&imgrefurl=")
884                 if foundPos != -1 and foundPos2 != -1:
885                         url = result[foundPos+14:foundPos2]
886                         parts = url.split("/")
887                         filename = parts[-1]
888                         if filename != self.currentGoogleCoverFile:
889                                 self.currentGoogleCoverFile = filename
890                                 filename = self.googleDownloadDir + parts[-1]
891                                 if os_path.exists(filename):
892                                         print "[MerlinMusicPlayer] using cover from %s " % filename
893                                         self["coverArt"].showCoverFromFile(filename)
894                                         if self.screenSaverScreen:
895                                                 self.screenSaverScreen.updateCover(filename = filename, modus = 4)
896                                 else:
897                                         print "[MerlinMusicPlayer] downloading cover from %s " % url
898                                         downloadPage(url , self.googleDownloadDir + parts[-1]).addCallback(boundFunction(self.coverDownloadFinished, filename)).addErrback(self.coverDownloadFailed)
899
900         def coverDownloadFailed(self,result):
901                 print "[MerlinMusicPlayer] cover download failed: %s " % result
902                 self["coverArt"].showDefaultCover()
903                 if self.screenSaverScreen:
904                         self.screenSaverScreen.updateCover(modus = 1)
905
906         def coverDownloadFinished(self,filename, result):
907                 print "[MerlinMusicPlayer] cover download finished"
908                 self["coverArt"].showCoverFromFile(filename)
909                 if self.screenSaverScreen:
910                         self.screenSaverScreen.updateCover(filename = filename, modus = 4)
911
912         def __evAudioDecodeError(self):
913                 currPlay = self.session.nav.getCurrentService()
914                 sAudioType = currPlay.info().getInfoString(iServiceInformation.sUser+10)
915                 print "[MerlinMusicPlayer] audio-codec %s can't be decoded by hardware" % (sAudioType)
916                 self.session.open(MessageBox, _("This Dreambox can't decode %s streams!") % sAudioType, type = MessageBox.TYPE_INFO,timeout = 20 )
917
918         def __evPluginError(self):
919                 currPlay = self.session.nav.getCurrentService()
920                 message = currPlay.info().getInfoString(iServiceInformation.sUser+12)
921                 print "[MerlinMusicPlayer]" , message
922                 self.session.open(MessageBox, message, type = MessageBox.TYPE_INFO,timeout = 20 )
923
924         def doEofInternal(self, playing):
925                 if playing:
926                         self.playNext()
927
928         def checkSkipShowHideLock(self):
929                 self.updatedSeekState()
930
931         def updatedSeekState(self):
932                 if self.seekstate == self.SEEK_STATE_PAUSE:
933                         self["dvrStatus"].setPixmapNum(1)
934                 elif self.seekstate == self.SEEK_STATE_PLAY:
935                         self["dvrStatus"].setPixmapNum(0)
936
937         def pauseEntry(self):
938                 self.pauseService()
939                 self.resetScreenSaverTimer()
940
941         def play(self):
942                 #play the current song from beginning again
943                 if self.songList[self.currentIndex][0].PTS is None:
944                         self.playSong(self.songList[self.currentIndex][0].filename)
945                 else:
946                         if self.seek:
947                                 self.seek.seekTo(self.songList[self.currentIndex][0].PTS)
948                                 self.updatedSeekState()
949                 self.resetScreenSaverTimer()            
950
951         def unPauseService(self):
952                 self.setSeekState(self.SEEK_STATE_PLAY)
953
954         def stopEntry(self):
955                 self.seek = None
956                 self.session.nav.stopService()
957                 self.origSongList = []
958                 self.songList = []
959                 if config.plugins.merlinmusicplayer.startlastsonglist.value:
960                         config.plugins.merlinmusicplayer.lastsonglistindex.value = -1
961                         config.plugins.merlinmusicplayer.lastsonglistindex.save()
962                         connection = OpenDatabase()
963                         connection.text_factory = str
964                         cursor = connection.cursor()
965                         cursor.execute("Delete from CurrentSongList;")
966                         connection.commit()
967                         cursor.close()
968                         connection.close()
969                 self.resetScreenSaverTimer()
970                 self.close()
971
972         def playNext(self):
973                 if not self.repeat:
974                         if self.currentIndex +1 > len(self.songList) -1:
975                                 self.currentIndex = 0
976                         else:
977                                 self.currentIndex += 1
978                 if self.songList[self.currentIndex][0].PTS is None:
979                         self.playSong(self.songList[self.currentIndex][0].filename)
980                 else:
981                         self.playCUETrack()
982                 if not self.screenSaverScreen:
983                         self.resetScreenSaverTimer()
984
985         def playPrevious(self):
986                 if not self.repeat:
987                         if self.currentIndex - 1 < 0:
988                                 self.currentIndex = len(self.songList) - 1
989                         else:
990                                 self.currentIndex -= 1
991
992                 if self.songList[self.currentIndex][0].PTS is None:
993                         self.playSong(self.songList[self.currentIndex][0].filename)
994                 else:
995                         self.playCUETrack()
996                 self.resetScreenSaverTimer()
997
998         def getNextTitle(self):
999                 if self.repeat:
1000                         index = self.currentIndex
1001                 else:
1002                         if self.currentIndex + 1 > len(self.songList) -1:
1003                                 index = 0
1004                         else:
1005                                 index = self.currentIndex + 1
1006                 if self.iDreamMode or self.songList[index][0].PTS is not None:
1007                         text = "%s - %s" % (self.songList[index][0].title, self.songList[index][0].artist)
1008                 else:
1009                         if self.songList[index][0].filename.lower().startswith("http://"):
1010                                 text = self.songList[index][0].filename
1011                         else:
1012                                 path,filename = os_path.split(self.songList[index][0].filename)
1013                                 audio, isAudio, title, genre,artist,album,tracknr,track,date,length,bitrate = getID3Tags(path,filename)
1014                                 if audio:
1015                                         if artist:
1016                                                 text = "%s - %s" % (title, artist)
1017                                         else:
1018                                                 text = title
1019                                 else:
1020                                         text = title
1021                                 audio = None
1022                 self.nextTitle = text
1023                 self.summaries.setText(text,4)
1024                 if self.screenSaverScreen:
1025                         self.screenSaverScreen.updateLCD(text,4)
1026                 return str(text)
1027
1028         def shuffleList(self):
1029                 if self.songList[self.currentIndex][0].PTS is None: # not implemented for cue files yet
1030                         self.shuffle = not self.shuffle
1031                         if self.shuffle:
1032                                 self["shuffle"].setPixmapNum(1)
1033                                 shuffle(self.songList)
1034                         else:
1035                                 self.songList = self.origSongList[:]
1036                                 self["shuffle"].setPixmapNum(0)
1037                         index = 0
1038                         for x in self.songList:
1039                                 if x[0].filename == self.currentFilename:
1040                                         self.currentIndex = index
1041                                         break
1042                                 index += 1
1043                         self["nextTitle"].setText(self.getNextTitle())
1044                 else:
1045                         self.session.open(MessageBox, _("Shuffle is not available yet with cue-files!"), type = MessageBox.TYPE_INFO,timeout = 20 )
1046                 self.resetScreenSaverTimer()
1047
1048         def repeatSong(self):
1049                 if self.songList[self.currentIndex][0].PTS is None: # not implemented for cue files yet
1050                         self.repeat = not self.repeat
1051                         if self.repeat:
1052                                 self["repeat"].setPixmapNum(1)
1053                         else:
1054                                 self["repeat"].setPixmapNum(0)
1055                         self["nextTitle"].setText(self.getNextTitle())
1056                 else:
1057                         self.session.open(MessageBox, _("Repeat is not available yet with cue-files!"), type = MessageBox.TYPE_INFO,timeout = 20 )
1058                 self.resetScreenSaverTimer()
1059
1060         def showPlaylist(self):
1061                 if self.screenSaverTimer.isActive():
1062                         self.screenSaverTimer.stop()
1063                 self.session.openWithCallback(self.showPlaylistCallback, MerlinMusicPlayerSongList, self.songList, self.currentIndex, self.iDreamMode)
1064
1065         def showPlaylistCallback(self, index):
1066                 if index != -1:
1067                         self.currentIndex = index
1068
1069                         if self.songList[self.currentIndex][0].PTS is None:
1070                                 self.playSong(self.songList[self.currentIndex][0].filename)
1071                         else:
1072                                 self.playCUETrack()             
1073
1074                 self.resetScreenSaverTimer()
1075
1076         def playCUETrack(self):
1077                 if self.ptsTimer.isActive():
1078                         self.ptsTimer.stop()
1079                 if self.seek:
1080                         self.seek.seekTo(self.songList[self.currentIndex][0].PTS)
1081                         self.updatedSeekState()
1082                         self.updateMusicInformationCUE()
1083                         self.ptsTimer.start(1000)
1084
1085         def showLyrics(self):
1086                 if self.screenSaverTimer.isActive():
1087                         self.screenSaverTimer.stop()
1088                 self.session.openWithCallback(self.resetScreenSaverTimer, MerlinMusicPlayerLyrics, self.songList[self.currentIndex][0])
1089
1090         def createSummary(self):
1091                 return MerlinMusicPlayerLCDScreen
1092
1093 class MerlinMusicPlayerLyrics(Screen):
1094
1095         sz_w = getDesktop(0).size().width()
1096         if sz_w == 1280:
1097                 skin = """
1098                         <screen name="MerlinMusicPlayerLyrics" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="Merlin Music Player Lyrics">
1099                         <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmpborderHD.png" position="128,72" size="1024,576"/>
1100                         <eLabel backgroundColor="#999999" position="178,112" size="924,2" zPosition="1"/>
1101                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="178,104" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>
1102                         <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"/>
1103                         <widget name="headertext" position="178,145" zPosition="1" size="900,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
1104                         <widget name="resulttext" position="178,172" zPosition="1" size="900,20" font="Regular;16" transparent="1"   backgroundColor="#00000000"/>
1105                         <widget name="lyric_text" position="178,222" zPosition="2" size="940,350" font="Regular;18" transparent="0"  backgroundColor="#00000000"/>
1106                         </screen>"""
1107         elif sz_w == 1024:
1108                 skin = """
1109                         <screen name="MerlinMusicPlayerLyrics" position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="Merlin Music Player Lyrics">
1110                         <eLabel backgroundColor="#999999" position="50,40" size="924,2" zPosition="1"/>
1111                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,32" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>
1112                         <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"/>
1113                         <widget name="headertext" position="50,73" zPosition="1" size="900,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
1114                         <widget name="resulttext" position="50,100" zPosition="1" size="900,20" font="Regular;16" transparent="1"   backgroundColor="#00000000"/>
1115                         <widget name="lyric_text" position="50,150" zPosition="2" size="940,350" font="Regular;18" transparent="0"  backgroundColor="#00000000"/>
1116                         </screen>"""
1117         else:
1118                 skin = """
1119                         <screen name="MerlinMusicPlayerLyrics" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="Merlin Music Player Lyrics">
1120                         <eLabel backgroundColor="#999999" position="50,50" size="620,2" zPosition="1"/>\r
1121                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,40" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>\r
1122                         <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"/>
1123                         <widget name="headertext" position="50,73" zPosition="1" size="620,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
1124                         <widget name="resulttext" position="50,100" zPosition="1" size="620,20" font="Regular;16" transparent="1"   backgroundColor="#00000000"/>
1125                         <widget name="lyric_text" position="50,150" zPosition="2" size="620,350" font="Regular;18" transparent="0"  backgroundColor="#00000000"/>
1126                         </screen>"""
1127                 
1128         
1129         def __init__(self, session, currentsong):
1130                 self.session = session
1131                 Screen.__init__(self, session)
1132                 self["headertext"] = Label(_("Merlin Music Player Lyrics"))
1133                 self["resulttext"] = Label(_("Getting lyrics from api.leoslyrics.com..."))
1134                 self["actions"] = ActionMap(["WizardActions", "DirectionActions"],
1135                 {
1136                         "back": self.close,
1137                         "upUp": self.pageUp,
1138                         "leftUp": self.pageUp,
1139                         "downUp": self.pageDown,
1140                         "rightUp": self.pageDown,
1141                 }, -1)
1142                 self["lyric_text"] = ScrollLabel()
1143                 self.currentSong = currentsong
1144                 self.onLayoutFinish.append(self.startRun)
1145
1146         def startRun(self):
1147                 url = "http://api.leoslyrics.com/api_search.php?auth=duane&artist=%s&songtitle=%s" % (quote(self.currentSong.artist), quote(self.currentSong.title))
1148                 sendUrlCommand(url, None,10).addCallback(self.getHID).addErrback(self.urlError)
1149         
1150         def urlError(self, error = None):
1151                 if error is not None:
1152                         self["resulttext"].setText(str(error.getErrorMessage()))
1153
1154         def getHID(self, xmlstring):
1155                 root = cet_fromstring(xmlstring)
1156                 url = ""
1157                 child = root.find("searchResults")
1158                 if child:
1159                         child2 = child.find("result")
1160                         if child2:
1161                                 url = "http://api.leoslyrics.com/api_lyrics.php?auth=duane&hid=%s" % quote(child2.get("hid"))
1162                                 sendUrlCommand(url, None,10).addCallback(self.getLyrics).addErrback(self.urlError)
1163                 if not url:
1164                         self["resulttext"].setText(_("No lyrics found"))
1165
1166         def getLyrics(self, xmlstring):
1167                 root = cet_fromstring(xmlstring)
1168                 lyrictext = ""
1169                 child = root.find("lyric")
1170                 if child:
1171                         title = child.findtext("title").encode("utf-8", 'ignore')
1172                         child2 = child.find("artist")
1173                         if child2:
1174                                 artist = child2.findtext("name").encode("utf-8", 'ignore')
1175                         else:
1176                                 artist = ""
1177                         lyrictext = child.findtext("text").encode("utf-8", 'ignore')
1178                         self["lyric_text"].setText(lyrictext)
1179                         result = _("Response -> lyrics for: %s (%s)") % (title,artist)
1180                         self["resulttext"].setText(result)
1181                 if not lyrictext:
1182                         self["resulttext"].setText(_("No lyrics found"))
1183
1184         def pageUp(self):
1185                 self["lyric_text"].pageUp()
1186
1187         def pageDown(self):
1188                 self["lyric_text"].pageDown()   
1189
1190 class MerlinMusicPlayerSongList(Screen):
1191         
1192         sz_w = getDesktop(0).size().width()
1193         if sz_w == 1280:
1194                 skin = """
1195                         <screen name="MerlinMusicPlayerSongList" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="Songlist">
1196                         <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmpborderHD.png" position="128,72" size="1024,576"/>
1197                         <eLabel backgroundColor="#999999" position="178,112" size="924,2" zPosition="1"/>
1198                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="178,104" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>
1199                         <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"/>
1200                         <widget name="headertext" position="178,145" zPosition="1" size="900,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
1201                         <widget name="list" position="178,182" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
1202                         </screen>"""
1203         elif sz_w == 1024:
1204                 skin = """
1205                         <screen name="MerlinMusicPlayerSongList" position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="Songlist">
1206                         <eLabel backgroundColor="#999999" position="50,40" size="924,2" zPosition="1"/>
1207                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,32" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>
1208                         <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"/>
1209                         <widget name="headertext" position="50,73" zPosition="1" size="900,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
1210                         <widget name="list" position="50,110" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
1211                         </screen>"""
1212         else:
1213                 skin = """
1214                         <screen name="MerlinMusicPlayerSongList" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="Songlist">
1215                         <eLabel backgroundColor="#999999" position="50,50" size="620,2" zPosition="1"/>\r
1216                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,40" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>\r
1217                         <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"/>
1218                         <widget name="headertext" position="50,73" zPosition="1" size="620,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
1219                         <widget name="list" position="50,110" zPosition="2" size="620,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
1220                         </screen>"""
1221                 
1222         
1223         def __init__(self, session, songlist, index, idreammode):
1224                 self.session = session
1225                 Screen.__init__(self, session)
1226                 self["headertext"] = Label(_("Merlin Music Player Songlist"))
1227                 self["list"] = iDreamList()
1228                 self["list"].connectSelChanged(self.lcdUpdate)
1229                 self["actions"] = ActionMap(["WizardActions"],
1230                 {
1231                         "ok": self.ok,
1232                         "back": self.closing,
1233                 }, -1)
1234                 self.songList = songlist
1235                 self.index = index
1236                 self.iDreamMode = idreammode
1237                 self.onLayoutFinish.append(self.startRun)
1238                 self.onShown.append(self.lcdUpdate)
1239
1240         def startRun(self):
1241                 if self.iDreamMode:
1242                         self["list"].setMode(10) # songlist
1243                 self["list"].setList(self.songList)
1244                 self["list"].moveToIndex(self.index)
1245
1246         def ok(self):
1247                 self.close(self["list"].getCurrentIndex())
1248
1249         def closing(self):
1250                 self.close(-1)
1251
1252         def lcdUpdate(self):
1253                 try:
1254                         index = self["list"].getCurrentIndex()
1255                         songlist = self["list"].getList()
1256                         self.summaries.setText(songlist[index][0].title,1)
1257                         count = self["list"].getItemCount()
1258                         # voheriges
1259                         index -= 1
1260                         if index < 0:
1261                                 index = count
1262                         self.summaries.setText(songlist[index][0].title,3)
1263                         # naechstes
1264                         index = self["list"].getCurrentIndex() + 1
1265                         if index > count:
1266                                 index = 0
1267                         self.summaries.setText(songlist[index][0].title,4)
1268                 except: pass
1269
1270         def createSummary(self):
1271                 return MerlinMusicPlayerLCDScreenText
1272
1273 class iDreamMerlin(Screen):
1274         
1275
1276         sz_w = getDesktop(0).size().width()
1277         if sz_w == 1280:
1278                 skin = """
1279                         <screen name="iDreamMerlin" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
1280                                 <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmpborderHD.png" position="128,72" size="1024,576"/>
1281                                 <ePixmap position="178,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1282                                 <ePixmap position="328,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1283                                 <ePixmap position="478,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1284                                 <ePixmap position="628,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
1285                                 <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" />
1286                                 <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" />
1287                                 <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" />
1288                                 <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" />
1289                                 <widget name="headertext" position="178,149" zPosition="1" size="900,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
1290                                 <widget name="list" position="178,182" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
1291                         </screen>"""
1292         elif sz_w == 1024:
1293                 skin = """
1294                         <screen name="iDreamMerlin" position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
1295                                 <ePixmap position="50,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1296                                 <ePixmap position="200,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1297                                 <ePixmap position="350,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1298                                 <ePixmap position="500,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
1299                                 <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" />
1300                                 <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" />
1301                                 <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" />
1302                                 <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" />
1303                                 <widget name="headertext" position="50,77" zPosition="1" size="900,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
1304                                 <widget name="list" position="50,110" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
1305                         </screen>"""
1306         else:
1307                 skin = """
1308                         <screen name="iDreamMerlin" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
1309                                 <ePixmap position="50,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1310                                 <ePixmap position="200,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1311                                 <ePixmap position="350,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1312                                 <ePixmap position="500,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
1313                                 <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" />
1314                                 <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" />
1315                                 <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" />
1316                                 <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" />
1317                                 <widget name="headertext" position="50,77" zPosition="1" size="620,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
1318                                 <widget name="list" position="50,110" zPosition="2" size="620,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
1319                         </screen>"""
1320                 
1321         
1322         def __init__(self, session):
1323                 self.session = session
1324                 Screen.__init__(self, session)
1325                 self["list"] = iDreamList()
1326                 self["list"].connectSelChanged(self.lcdUpdate)
1327
1328
1329                 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EPGSelectActions"],
1330                 {
1331                         "ok": self.ok,
1332                         "back": self.closing,
1333                         "red": self.red_pressed,
1334                         "green": self.green_pressed,
1335                         "yellow": self.yellow_pressed,
1336                         "blue": self.blue_pressed,
1337                         "input_date_time": self.menu_pressed,
1338                         "info" : self.info_pressed,
1339                 }, -1)
1340
1341                 self["actions2"] = NumberActionMap(["InputActions"],
1342                 {
1343                         "0": self.keyNumber_pressed,
1344                 }, -1)
1345
1346                 self.onLayoutFinish.append(self.startRun)
1347                 self.onShown.append(self.lcdUpdate)
1348                 self.onClose.append(self.__onClose)
1349                 
1350                 self.CurrentService = self.session.nav.getCurrentlyPlayingServiceReference()
1351                 self.session.nav.stopService()
1352                 
1353                 self.mode = 0
1354                 self.mainMenuList = []
1355                 self.cacheList = []
1356                 self.LastMethod = None
1357                 self.player = None
1358                 
1359                 self["key_red"] = StaticText("")
1360                 self["key_green"] = StaticText("")
1361                 self["key_yellow"] = StaticText("")
1362                 self["key_blue"] = StaticText("")
1363                 self["headertext"] = Label(_("iDream Main Menu"))
1364
1365         def getPlayList(self):
1366                 connection = OpenDatabase()
1367                 connection.text_factory = str
1368                 cursor = connection.cursor()
1369                 playList = []
1370                 cursor.execute("select playlist_id,playlist_text from playlists order by playlist_text;")
1371                 for row in cursor:
1372                         playList.append((row[1], row[0]))
1373                 cursor.close()  
1374                 connection.close()
1375                 return playList
1376
1377         def sqlCommand(self, sqlSatement):
1378                 connection = OpenDatabase()
1379                 cursor = connection.cursor()
1380                 cursor.execute(sqlSatement)
1381                 cursor.close()
1382                 connection.commit()
1383                 connection.close()
1384
1385         def clearCache(self):
1386                 for items in self.cacheList:
1387                         items.cache = False
1388                         items.listview = []
1389                         items.headertext = ""
1390
1391         def getCurrentSelection(self):
1392                 sel = None
1393                 try: sel = self["list"].l.getCurrentSelection()[0]
1394                 except: pass
1395                 return sel
1396
1397         def addListToPlaylistConfirmed(self, methodName, answer):
1398                 if answer:
1399                         playList = self.getPlayList()
1400                         if len(playList):
1401                                 self.session.openWithCallback(methodName, ChoiceBox,list = playList)
1402                         else:
1403                                 self.session.openWithCallback(self.createPlaylistConfirmed, MessageBox, _("There are no playlists defined.\nDo you want to create a new playlist?"))
1404
1405         def menu_pressed(self):
1406                 options = [(_("Configuration"), self.config),(_("Search in iDream database"), self.searchInIDreamDatabase),]
1407                 options.extend(((_("Scan path for music files and add them to database"), self.scanDir),))
1408                 if self.mode != 1:
1409                         options.extend(((_("Create new playlist"), self.createPlaylist),))
1410                 if self["list"].getDisplaySongMode():
1411                         if self.mode == 2:
1412                                 options.extend(((_("Delete song from current playlist"), self.deleteSongFromPlaylist),))
1413                         else:
1414                                 options.extend(((_("Add selected song to a playlist"), self.addSongToPlaylist),))
1415                                 if self.mode == 18:
1416                                         options.extend(((_("Add all songs from selected album to a playlist"), self.addAlbumToPlaylist),))
1417                                 elif self.mode == 19:
1418                                         options.extend(((_("Add all songs from selected artist to a playlist"), self.addArtistToPlaylist),))
1419                                 options.extend(((_("Delete song from database"), self.deleteSongFromDatabase),))
1420                 else:
1421                         if self.mode == 1:
1422                                 options.extend(((_("Delete selected playlist"), self.deletePlaylist),))
1423                         elif self.mode == 4:
1424                                 options.extend(((_("Add all songs from selected artist to a playlist"), self.addArtistToPlaylist),))
1425                         elif self.mode == 5 or self.mode == 7:
1426                                 options.extend(((_("Add all songs from selected album to a playlist"), self.addAlbumToPlaylist),))
1427                         elif self.mode == 13:
1428                                 options.extend(((_("Add all songs from selected genre to a playlist"), self.addGenreToPlaylist),))
1429                 self.session.openWithCallback(self.menuCallback, ChoiceBox,list = options)
1430
1431         def menuCallback(self, ret):
1432                 ret and ret[1]()
1433
1434         def scanDir(self):
1435                 SelectPath
1436                 self.session.openWithCallback(self.pathSelected,SelectPath,"/media/")
1437
1438         def pathSelected(self, res):
1439                 if res is not None:
1440                         self.session.openWithCallback(self.filesAdded, iDreamAddToDatabase,res)
1441
1442         def filesAdded(self):
1443                 if pathToDatabase.isRunning:
1444                         self.close()
1445                 else:
1446                         self.red_pressed()
1447                 
1448
1449
1450
1451         def addGenreToPlaylist(self):
1452                 self.session.openWithCallback(boundFunction(self.addListToPlaylistConfirmed,self.addGenreToPlaylistConfirmedCallback), MessageBox, _("Do you really want to add all songs from that genre to a playlist?"))
1453
1454         def addGenreToPlaylistConfirmedCallback(self, ret):
1455                 if ret:
1456                         sel = self.getCurrentSelection()
1457                         if sel:
1458                                 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))
1459                                 self.clearCache()
1460
1461         def addArtistToPlaylist(self):
1462                 self.session.openWithCallback(boundFunction(self.addListToPlaylistConfirmed, self.addArtistToPlaylistConfirmedCallback), MessageBox, _("Do you really want to add all songs from that artist to a playlist?"))
1463
1464         def addArtistToPlaylistConfirmedCallback(self, ret):
1465                 if ret:
1466                         sel = self.getCurrentSelection()
1467                         if sel:
1468                                 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))
1469                                 self.clearCache()
1470
1471         def addAlbumToPlaylist(self):
1472                 self.session.openWithCallback(boundFunction(self.addListToPlaylistConfirmed, self.addAlbumToPlaylistConfirmedCallback), MessageBox, _("Do you really want to add all songs from that album to a playlist?"))
1473
1474         def addAlbumToPlaylistConfirmedCallback(self, ret):
1475                 if ret:
1476                         sel = self.getCurrentSelection()
1477                         if sel:
1478                                 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))
1479                                 self.clearCache()
1480
1481         def deletePlaylist(self):
1482                 self.session.openWithCallback(self.deletePlaylistConfirmed, MessageBox, _("Do you really want to delete the current playlist?"))
1483
1484         def deletePlaylistConfirmed(self, answer):
1485                 if answer:
1486                         sel = self.getCurrentSelection()
1487                         if sel:
1488                                 self.sqlCommand("delete from playlist_songs where playlist_id = %d" % (sel.playlistID))
1489                                 self.sqlCommand("delete from playlists where playlist_id = %d" % (sel.playlistID))
1490                                 self["list"].removeItem(self["list"].getCurrentIndex())
1491                                 self.clearCache()
1492
1493
1494         def deleteSongFromPlaylist(self):
1495                 self.session.openWithCallback(self.deleteSongFromPlaylistConfirmed, MessageBox, _("Do you really want to delete that song the current playlist?"))
1496
1497         def deleteSongFromPlaylistConfirmed(self, answer):
1498                 if answer:
1499                         sel = self.getCurrentSelection()
1500                         if sel:
1501                                 self.sqlCommand("delete from playlist_songs where song_id = %d" % (sel.songID))
1502                                 self["list"].removeItem(self["list"].getCurrentIndex())
1503                                 self.clearCache()
1504
1505         def deleteSongFromDatabase(self):
1506                 self.session.openWithCallback(self.deleteSongFromDatabaseConfirmed, MessageBox, _("Do you really want to delete that song from the database?"))
1507
1508         def deleteSongFromDatabaseConfirmed(self, answer):
1509                 if answer:
1510                         sel = self.getCurrentSelection()
1511                         if sel:
1512                                 self.sqlCommand("delete from playlist_songs where song_id = %d" % (sel.songID))
1513                                 self.sqlCommand("delete from songs where song_id = %d" % (sel.songID))
1514                                 self["list"].removeItem(self["list"].getCurrentIndex())
1515                                 self.clearCache()
1516                         
1517         def addSongToPlaylist(self):
1518                 playList = self.getPlayList()
1519                 if len(playList):
1520                         self.session.openWithCallback(self.addSongToPlaylistCallback, ChoiceBox,list = playList)
1521                 else:
1522                         self.session.openWithCallback(self.createPlaylistConfirmed, MessageBox, _("There are no playlists defined.\nDo you want to create a new playlist?"))
1523
1524         def createPlaylistConfirmed(self, val):
1525                 if val:
1526                         self.createPlaylist()
1527
1528         def addSongToPlaylistCallback(self,ret):
1529                 if ret:
1530                         sel = self.getCurrentSelection()
1531                         if sel:
1532                                 self.sqlCommand("INSERT INTO Playlist_Songs (playlist_id,song_id) VALUES(%d,%d);" % (ret[1],sel.songID))
1533                                 self.clearCache()
1534
1535         def createPlaylist(self):
1536                 self.session.openWithCallback(self.createPlaylistFinished, VirtualKeyBoard, title = _("Enter name for playlist"))
1537
1538         def createPlaylistFinished(self, text = None):
1539                 if text:
1540                         self.sqlCommand("""INSERT INTO Playlists (playlist_text) VALUES("%s");""" % (text))
1541                         self.clearCache()
1542                         self.menu_pressed()
1543
1544         def searchInIDreamDatabase(self):
1545                 options = [(_("search for title"), 1),
1546                         (_("search for artist"), 2),
1547                         (_("search for album"), 3),
1548                         (_("search in all of them"), 4),]
1549                 self.session.openWithCallback(self.enterSearchText, ChoiceBox,list = options)
1550
1551         def enterSearchText(self, ret):
1552                 if ret:
1553                         self.session.openWithCallback(boundFunction(self.enterSearchTextFinished,ret[1]), VirtualKeyBoard, title = _("Enter search-text"))
1554
1555         def enterSearchTextFinished(self, searchType, searchText = None):
1556                 if searchText:
1557                         search = "%" + searchText + "%"
1558                         if searchType == 1:
1559                                 sql_where = "where title like '%s'" % search
1560                                 text = _("""Search results for "%s" in all titles""") % searchText
1561                         elif searchType == 2:
1562                                 sql_where = "where artists.artist like '%s'" % search
1563                                 text = _("""Search results for "%s" in all artists""") % searchText
1564                         elif searchType == 3:
1565                                 sql_where = "where album_text like '%s'" % search
1566                                 text = _("""Search results for "%s" in all albums""") % searchText
1567                         else:
1568                                 sql_where = "where (title like '%s' or artists.artist like '%s' or album_text like '%s')"  % (search,search,search)
1569                                 text = _("""Search results for "%s" in title, artist or album""") % searchText
1570                         self.setButtons(red = True, yellow = True, blue = True)
1571                         oldmode = self.mode
1572                         self.mode = 20
1573                         self["list"].setMode(self.mode)
1574                         self.buildSearchSongList(sql_where, text, oldmode, True)
1575
1576
1577         def keyNumber_pressed(self, number):
1578                 if number == 0 and self.mode != 0:
1579                         self["list"].moveToIndex(0)
1580                         self.ok()
1581
1582         def ok(self):
1583                 sel = self.getCurrentSelection()
1584                 if sel is None:
1585                         return
1586                 if sel.mode == 99:
1587                         self.green_pressed()
1588                 else:
1589                         self.mode = sel.mode
1590                         self["list"].setMode(self.mode)
1591                         if sel.navigator and len(self.cacheList) > 0:
1592                                 cache = self.cacheList.pop()
1593                         else:
1594                                 cache = CacheList(cache = False, index = -1)
1595                         if sel.navigator: 
1596                                 self["headertext"].setText(cache.headertext)
1597                                 if cache.cache:
1598                                         self["list"].setList(cache.listview)
1599                                         self.LastMethod = MethodArguments(method = cache.methodarguments.method, arguments = cache.methodarguments.arguments)
1600                                 else:
1601                                         cache.methodarguments.method(**cache.methodarguments.arguments)
1602                                 self["list"].moveToIndex(cache.index)
1603                         if self.mode == 0:
1604                                 self.setButtons()
1605                                 if not sel.navigator:
1606                                         self.buildMainMenuList()
1607                         elif self.mode == 1:
1608                                 self.setButtons(red = True)
1609                                 if not sel.navigator:
1610                                         self.buildPlaylistList(addToCache = True)
1611                         elif self.mode == 2:
1612                                 self.setButtons(red = True, green = True, yellow = True, blue = True)
1613                                 if not sel.navigator:
1614                                         self.buildPlaylistSongList(playlistID = sel.playlistID, addToCache = True)
1615                         elif self.mode == 4:
1616                                 self.setButtons(red = True)
1617                                 if not sel.navigator:
1618                                         self.buildArtistList(addToCache = True)
1619                         elif self.mode == 5:
1620                                 self.setButtons(red = True)
1621                                 if not sel.navigator:
1622                                         self.buildArtistAlbumList(sel.artistID, addToCache = True)
1623                         elif self.mode == 6:
1624                                 self.setButtons(red = True, green = True, yellow = True)
1625                                 if not sel.navigator:
1626                                         self.buildAlbumSongList(albumID = sel.albumID, mode = 5, addToCache = True)
1627                         elif self.mode == 7:
1628                                 self.setButtons(red = True)
1629                                 if not sel.navigator:
1630                                         self.buildAlbumList(addToCache = True)
1631                         elif self.mode == 8:
1632                                 self.setButtons(red = True, green = True, yellow = True)
1633                                 if not sel.navigator:
1634                                         self.buildAlbumSongList(albumID = sel.albumID, mode = 7, addToCache = True)
1635                         elif self.mode == 10:
1636                                 self.setButtons(red = True, green = True, yellow = True, blue = True)
1637                                 if not sel.navigator:
1638                                         self.buildSongList(addToCache = True)
1639                         elif self.mode == 13:
1640                                 self.setButtons(red = True)
1641                                 if not sel.navigator:
1642                                         self.buildGenreList(addToCache = True)
1643                         elif self.mode == 14:
1644                                 self.setButtons(red = True, green = True, yellow = True, blue = True)
1645                                 if not sel.navigator:
1646                                         self.buildGenreSongList(genreID = sel.genreID, addToCache = True)
1647                         elif self.mode == 18 or self.mode == 19:
1648                                 if self.mode == 18:
1649                                         self.setButtons(red = True, green = True, yellow = True)
1650                                 if self.mode == 19:
1651                                         self.setButtons(red = True, green = True, blue = True)
1652                                 if not sel.navigator:
1653                                         self.red_pressed() # back to main menu --> normally that can not be happened
1654                         elif self.mode == 20:
1655                                 self.setButtons(red = True, green = True, yellow = True, blue = True)
1656                                 if not sel.navigator:
1657                                         self.red_pressed() # back to main menu --> normally that can not be happened
1658
1659         def buildPlaylistList(self, addToCache):
1660                 if addToCache:
1661                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
1662                 arguments = {}
1663                 arguments["addToCache"] = False
1664                 self.LastMethod = MethodArguments(method = self.buildPlaylistList, arguments = arguments)
1665                 self["headertext"].setText(_("Playlists"))
1666                 connection = OpenDatabase()
1667                 connection.text_factory = str
1668                 cursor = connection.cursor()
1669                 playlistList = []
1670                 playlistList.append((Item(text = _("[back]"), mode = 0, navigator = True),))
1671                 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;")
1672                 for row in cursor:
1673                         playlistList.append((Item(text = "%s (%d)" % (row[1], row[2]), mode = 2, playlistID = row[0]),))
1674                 cursor.close() 
1675                 connection.close()
1676                 self["list"].setList(playlistList)
1677                 if len(playlistList) > 1:
1678                         self["list"].moveToIndex(1)
1679
1680         def buildPlaylistSongList(self, playlistID, addToCache):
1681                 if addToCache:
1682                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
1683                 arguments = {}
1684                 arguments["playlistID"] = playlistID
1685                 arguments["addToCache"] = False
1686                 self.LastMethod = MethodArguments(method = self.buildPlaylistSongList, arguments = arguments)
1687                 connection = OpenDatabase()
1688                 connection.text_factory = str
1689                 cursor = connection.cursor()
1690                 playlistSongList = []
1691                 playlistSongList.append((Item(text = _("[back]"), mode = 1, navigator = True),))
1692                 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))
1693                 for row in cursor:
1694                         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),))
1695                 cursor.execute("SELECT playlist_text from playlists where playlist_id = %d;" % playlistID)
1696                 row = cursor.fetchone()
1697                 self["headertext"].setText(_("Playlist (%s) -> Song List") % row[0])
1698                 cursor.close() 
1699                 connection.close()
1700                 self["list"].setList(playlistSongList)
1701                 if len(playlistSongList) > 1:
1702                         self["list"].moveToIndex(1)
1703                                 
1704         def buildGenreList(self, addToCache):
1705                 if addToCache:
1706                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
1707                 arguments = {}
1708                 arguments["addToCache"] = False
1709                 self.LastMethod = MethodArguments(method = self.buildGenreList, arguments = arguments)
1710                 self["headertext"].setText(_("Genre List"))
1711                 connection = OpenDatabase()
1712                 connection.text_factory = str
1713                 cursor = connection.cursor()
1714                 genreList = []
1715                 genreList.append((Item(text = _("[back]"), mode = 0, navigator = True),))
1716                 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;")
1717                 for row in cursor:
1718                         genreList.append((Item(text = "%s (%d)" % (row[1], row[2]), mode = 14, genreID = row[0]),))
1719                 cursor.close() 
1720                 connection.close()
1721                 self["list"].setList(genreList)
1722                 if len(genreList) > 1:
1723                         self["list"].moveToIndex(1)
1724
1725         def buildGenreSongList(self, genreID, addToCache):
1726                 if addToCache:
1727                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
1728                 arguments = {}
1729                 arguments["genreID"] = genreID
1730                 arguments["addToCache"] = False
1731                 self.LastMethod = MethodArguments(method = self.buildGenreSongList, arguments = arguments)
1732                 connection = OpenDatabase()
1733                 connection.text_factory = str
1734                 cursor = connection.cursor()
1735                 genreSongList = []
1736                 genreSongList.append((Item(text = _("[back]"), mode = 13, navigator = True),))
1737                 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))
1738                 for row in cursor:
1739                         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),))
1740                 cursor.execute("SELECT genre_text from genre where genre_ID = %d;" % genreID)
1741                 row = cursor.fetchone()
1742                 self["headertext"].setText(_("Genre (%s) -> Song List") % row[0])
1743                 cursor.close() 
1744                 connection.close()
1745                 self["list"].setList(genreSongList)
1746                 if len(genreSongList) > 1:
1747                         self["list"].moveToIndex(1)
1748
1749         def setButtons(self, red = False, green = False, yellow = False, blue = False):
1750                 if red:
1751                         self["key_red"].setText("Main Menu")
1752                 else:
1753                         self["key_red"].setText("")
1754                 if green:
1755                         self["key_green"].setText("Play")
1756                 else:
1757                         self["key_green"].setText("")
1758                 if yellow:
1759                         self["key_yellow"].setText("All Artists")
1760                 else:           
1761                         self["key_yellow"].setText("")
1762                 if blue:
1763                         self["key_blue"].setText("Show Album")
1764                 else:
1765                         self["key_blue"].setText("")
1766
1767         def info_pressed(self):
1768                 if self.player is not None:
1769                         if self.player.songList:
1770                                 self.session.execDialog(self.player)
1771
1772         def green_pressed(self):
1773                 sel = self["list"].l.getCurrentSelection()[0]
1774                 if sel is None:
1775                         return
1776                 if sel.songID != 0:
1777                         if self.player is not None:
1778                                 self.player.doClose()
1779                                 self.player = None
1780                         self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,self["list"].getList()[1:], self["list"].getCurrentIndex() -1, True)
1781                         self.session.execDialog(self.player)
1782
1783         def red_pressed(self):
1784                 self.cacheList = []
1785                 self.setButtons()
1786                 self.mode = 0
1787                 self["list"].setMode(self.mode)
1788                 self.buildMainMenuList()
1789         
1790         def yellow_pressed(self):
1791                 sel = self["list"].l.getCurrentSelection()[0]
1792                 if sel.artistID != 0:
1793                         oldmode = self.mode
1794                         self.mode = 19
1795                         self.setButtons(red = True, green = True, blue = True)
1796                         self["list"].setMode(self.mode)
1797                         self.buildArtistSongList(artistID = sel.artistID, mode = oldmode, addToCache = True)
1798                 
1799         def blue_pressed(self):
1800                 sel = self["list"].l.getCurrentSelection()[0]
1801                 if sel.albumID != 0:
1802                         self.setButtons(red = True, green = True, yellow = True)
1803                         oldmode = self.mode
1804                         self.mode = 18
1805                         self["list"].setMode(self.mode)
1806                         self.buildAlbumSongList(albumID = sel.albumID, mode = oldmode, addToCache = True)
1807         
1808         def buildSongList(self, addToCache):
1809                 if addToCache:
1810                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
1811                 arguments = {}
1812                 arguments["addToCache"] = False
1813                 self.LastMethod = MethodArguments(method = self.buildSongList,  arguments = arguments)
1814                 self["headertext"].setText(_("All Songs"))
1815                 connection = OpenDatabase()
1816                 connection.text_factory = str
1817                 cursor = connection.cursor()
1818                 SongList = []
1819                 SongList.append((Item(text = _("[back]"), mode = 0, navigator = True),))
1820                 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;")
1821                 for row in cursor:
1822                         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]),))
1823                 cursor.close() 
1824                 connection.close()
1825                 self["list"].setList(SongList)
1826                 if len(SongList) > 1:
1827                         self["list"].moveToIndex(1)
1828
1829
1830         def buildSearchSongList(self, sql_where, headerText, mode, addToCache):
1831                 if addToCache:
1832                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
1833                 arguments = {}
1834                 arguments["sql_where"] = sql_where
1835                 arguments["headerText"] = headerText
1836                 arguments["mode"] = mode
1837                 arguments["addToCache"] = False
1838                 self.LastMethod = MethodArguments(method = self.buildSearchSongList, arguments = arguments)
1839                 self["headertext"].setText(headerText)
1840                 connection = OpenDatabase()
1841                 connection.text_factory = str
1842                 cursor = connection.cursor()
1843                 SongList = []
1844                 SongList.append((Item(text = _("[back]"), mode = mode, navigator = True),))
1845                 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)
1846                 for row in cursor:
1847                         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]),))
1848                 cursor.close() 
1849                 connection.close()
1850                 self["list"].setList(SongList)
1851                 if len(SongList) > 1:
1852                         self["list"].moveToIndex(1)
1853
1854         
1855         def buildArtistSongList(self, artistID, mode, addToCache):
1856                 if addToCache:
1857                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
1858                 arguments = {}
1859                 arguments["artistID"] = artistID
1860                 arguments["mode"] = mode
1861                 arguments["addToCache"] = False
1862                 self.LastMethod = MethodArguments(method = self.buildArtistSongList, arguments = arguments)
1863                 connection = OpenDatabase()
1864                 connection.text_factory = str
1865                 cursor = connection.cursor()
1866                 artistSongList = []
1867                 artistSongList.append((Item(text = _("[back]"), mode = mode, navigator = True),))
1868                 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))
1869                 for row in cursor:
1870                         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),))
1871                 cursor.execute("SELECT artist from artists where artist_ID = %d;" % artistID)
1872                 row = cursor.fetchone()
1873                 self["headertext"].setText(_("Artist (%s) -> Song List") % row[0])
1874                 cursor.close() 
1875                 connection.close()
1876                 self["list"].setList(artistSongList)
1877                 if len(artistSongList) > 1:
1878                         self["list"].moveToIndex(1)
1879                         
1880         def buildAlbumSongList(self, albumID, mode, addToCache):
1881                 if addToCache:
1882                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
1883                 arguments = {}
1884                 arguments["albumID"] = albumID
1885                 arguments["mode"] = mode
1886                 arguments["addToCache"] = False
1887                 self.LastMethod = MethodArguments(method = self.buildAlbumSongList, arguments = arguments)
1888                 connection = OpenDatabase()
1889                 connection.text_factory = str
1890                 cursor = connection.cursor()
1891                 albumSongList = []
1892                 albumSongList.append((Item(text = _("[back]"), mode = mode, navigator = True),))
1893                 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))
1894                 for row in cursor:
1895                         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),))
1896                 cursor.execute("SELECT album_text from album where album_ID = %d;" % albumID)
1897                 row = cursor.fetchone()
1898                 self["headertext"].setText(_("Album (%s) -> Song List") % row[0])
1899                 cursor.close() 
1900                 connection.close()
1901                 self["list"].setList(albumSongList)
1902                 if len(albumSongList) > 1:
1903                         self["list"].moveToIndex(1)
1904                 
1905         def buildMainMenuList(self, addToCache = True):
1906                 arguments = {}
1907                 arguments["addToCache"] = True
1908                 self.LastMethod = MethodArguments(method = self.buildMainMenuList, arguments = arguments)
1909                 self["headertext"].setText(_("iDream Main Menu"))
1910                 mainMenuList = []
1911                 connection = OpenDatabase()
1912                 connection.text_factory = str
1913                 cursor = connection.cursor()
1914                 # 1. Playlists
1915                 cursor.execute("SELECT COUNT (*) FROM playlists;")
1916                 row = cursor.fetchone()
1917                 mainMenuList.append((Item(text = _("Playlists (%d)") % row[0], mode = 1),))
1918                 # 2. Artists
1919                 cursor.execute("SELECT COUNT (*) FROM artists;")
1920                 row = cursor.fetchone()
1921                 mainMenuList.append((Item(text = _("Artists (%d)") % row[0], mode = 4),))
1922                 # 3. Albums
1923                 cursor.execute("SELECT COUNT (DISTINCT album_text) FROM album;")
1924                 row = cursor.fetchone()
1925                 mainMenuList.append((Item(text = _("Albums (%d)") % row[0], mode = 7),))
1926                 # 4. Songs
1927                 cursor.execute("SELECT COUNT (*) FROM songs;")
1928                 row = cursor.fetchone()
1929                 mainMenuList.append((Item(text = _("Songs (%d)") % row[0], mode = 10),))
1930                 # 5. Genres
1931                 cursor.execute("SELECT COUNT (*) FROM genre;")
1932                 row = cursor.fetchone()
1933                 mainMenuList.append((Item(text = _("Genres (%d)") % row[0], mode = 13),))
1934                 cursor.close()  
1935                 connection.close()
1936                 self["list"].setList(mainMenuList)
1937                 self["list"].moveToIndex(0)
1938                 
1939         def buildArtistList(self, addToCache):
1940                 if addToCache:
1941                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
1942                 arguments = {}
1943                 arguments["addToCache"] = False
1944                 self.LastMethod = MethodArguments(method = self.buildArtistList, arguments = arguments)
1945                 self["headertext"].setText(_("Artists List"))
1946                 connection = OpenDatabase()
1947                 connection.text_factory = str
1948                 cursor = connection.cursor()
1949                 artistList = []
1950                 artistList.append((Item(text = _("[back]"), mode = 0, navigator = True),))
1951                 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;")
1952                 for row in cursor:
1953                         artistList.append((Item(text = "%s (%d)" % (row[1], row[2]), mode = 5, artistID = row[0]),))
1954                 cursor.close() 
1955                 connection.close()
1956                 self["list"].setList(artistList)
1957                 
1958         def buildArtistAlbumList(self, ArtistID, addToCache):
1959                 if addToCache:
1960                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
1961                 arguments = {}
1962                 arguments["ArtistID"] = ArtistID
1963                 arguments["addToCache"] = False
1964                 self.LastMethod = MethodArguments(method = self.buildArtistAlbumList, arguments = arguments)
1965                 connection = OpenDatabase()
1966                 connection.text_factory = str
1967                 cursor = connection.cursor()
1968                 albumArtistList = []
1969                 albumArtistList.append((Item(text = _("[back]"), mode = 4, navigator = True),))
1970                 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)
1971                 for row in cursor:
1972                         cursor2 = connection.cursor()
1973                         cursor2.execute("select count(song_id) from songs where album_id = %d;" % row[0])
1974                         row2 = cursor2.fetchone()
1975                         albumArtistList.append((Item(text = "%s (%d)" % (row[1], row2[0]), mode = 6, albumID = row[0], artistID = ArtistID),))
1976                         cursor2.close()
1977                 cursor.execute("SELECT artist from artists where artist_ID = %d;" % ArtistID)
1978                 row = cursor.fetchone()
1979                 self["headertext"].setText(_("Artist (%s) -> Album List") % row[0])
1980                 cursor.close() 
1981                 connection.close()
1982                 self["list"].setList(albumArtistList)
1983                 if len(albumArtistList) > 1:
1984                         self["list"].moveToIndex(1)
1985                         
1986         def buildAlbumList(self, addToCache):
1987                 if addToCache:
1988                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
1989                 arguments = {}
1990                 arguments["addToCache"] = False
1991                 self.LastMethod = MethodArguments(method = self.buildAlbumList, arguments = arguments)
1992                 self["headertext"].setText(_("Albums List"))
1993                 connection = OpenDatabase()
1994                 connection.text_factory = str
1995                 cursor = connection.cursor()
1996                 albumList = []
1997                 albumList.append((Item(text = _("[back]"), mode = 0, navigator = True),))
1998                 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;")
1999                 for row in cursor:
2000                         albumList.append((Item(text = "%s (%d)" % (row[1], row[2]), mode = 8, albumID = row[0]),))
2001                 cursor.close() 
2002                 connection.close()
2003                 self["list"].setList(albumList)
2004                 if len(albumList) > 1:
2005                         self["list"].moveToIndex(1)
2006                         
2007         def startRun(self):
2008                 if pathToDatabase.isRunning:
2009                         self.showScanner = eTimer()
2010                         self.showScanner.callback.append(self.showScannerCallback)
2011                         self.showScanner.start(0,1)
2012                 else:
2013                         if config.plugins.merlinmusicplayer.startlastsonglist.value:
2014                                 self.startPlayerTimer = eTimer()
2015                                 self.startPlayerTimer.callback.append(self.startPlayerTimerCallback)
2016                                 self.startPlayerTimer.start(0,1)
2017                         self.mode = 0
2018                         self["list"].setMode(self.mode)
2019                         self.buildMainMenuList()
2020
2021         def showScannerCallback(self):
2022                 self.session.openWithCallback(self.filesAdded, iDreamAddToDatabase,None)
2023
2024
2025         def startPlayerTimerCallback(self):
2026                 connection = OpenDatabase()
2027                 connection.text_factory = str
2028                 cursor = connection.cursor()
2029                 iDreamMode = False
2030                 SongList = []
2031                 cursor.execute("select song_id, filename, title, artist, album, genre, bitrate, length,  track, date, PTS from CurrentSongList;")
2032                 for row in cursor:
2033                         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),))
2034                         if row[0] != 0:
2035                                 iDreamMode = True
2036                 cursor.close() 
2037                 connection.close()
2038                 if self.player is not None:
2039                         self.player.doClose()
2040                         self.player = None
2041                 count = len(SongList)
2042                 if count:
2043                         # just to be sure, check the index , it's critical
2044                         index = config.plugins.merlinmusicplayer.lastsonglistindex.value
2045                         if index >= count:
2046                                 index = 0
2047                         self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,SongList, index, iDreamMode)
2048                         self.session.execDialog(self.player)
2049
2050         def config(self):
2051                 self.session.openWithCallback(self.setupFinished, MerlinMusicPlayerSetup, True)
2052
2053         def setupFinished(self, result):
2054                 if result:
2055                         self.red_pressed()
2056
2057         def Error(self, error = None):
2058                 if error is not None:
2059                         self["list"].hide()
2060                         self["statustext"].setText(str(error.getErrorMessage()))
2061                         
2062         def closing(self):
2063                 self.close()
2064                 
2065         def __onClose(self):
2066                 if self.player is not None:
2067                         self.player.doClose()
2068                         self.player = None
2069                 self.session.nav.playService(self.CurrentService)
2070
2071         def lcdUpdate(self):
2072                 try:
2073                         count = self["list"].getItemCount()
2074                         index = self["list"].getCurrentIndex()
2075                         iDreamList = self["list"].getList()
2076                         self.summaries.setText(iDreamList[index][0].title or iDreamList[index][0].text,1)
2077                         # voheriges
2078                         index -= 1
2079                         if index < 0:
2080                                 index = count
2081                         self.summaries.setText(iDreamList[index][0].title or iDreamList[index][0].text,3)
2082                         # naechstes
2083                         index = self["list"].getCurrentIndex() + 1
2084                         if index > count:
2085                                 index = 0
2086                         self.summaries.setText(iDreamList[index][0].title or iDreamList[index][0].text,4)
2087                 except: pass
2088
2089         def createSummary(self):
2090                 return MerlinMusicPlayerLCDScreenText
2091
2092                 
2093 class iDreamList(GUIComponent, object):
2094         def buildEntry(self, item):
2095                 width = self.l.getItemSize().width()
2096                 res = [ None ]
2097                 if self.displaySongMode:
2098                         if item.navigator:
2099                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width , 20, 0, RT_HALIGN_CENTER|RT_VALIGN_CENTER, "%s" % item.text))
2100                         else:
2101                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width - 100 , 20, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "%s - %s" % (item.title, item.artist)))
2102                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, width - 100,3,100, 20, 1, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, "%s" % item.track))
2103                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 26,width -200, 18, 1, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "%s%s" % (item.album, item.date)))
2104                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, width -200, 26,200, 18, 1, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, "%s" % item.length))
2105                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 47,width -200, 18, 1, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "%s" % item.genre))
2106                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, width -200, 47,200, 18, 1, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, "%s" % item.bitrate))
2107                 else:
2108                         if item.navigator:
2109                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width , 20, 0, RT_HALIGN_CENTER|RT_VALIGN_CENTER, "%s" % item.text))
2110                         else:
2111                                 if item.PTS is None:
2112                                         res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width , 20, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "%s" % item.text))
2113                                 else:
2114                                         res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width , 20, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "%s" % item.title))
2115                 
2116                 return res
2117         
2118         def __init__(self):
2119                 GUIComponent.__init__(self)
2120                 self.l = eListboxPythonMultiContent()
2121                 self.l.setBuildFunc(self.buildEntry)
2122                 self.l.setFont(0, gFont("Regular", 20))
2123                 self.l.setFont(1, gFont("Regular", 16))
2124                 self.l.setItemHeight(22)
2125                 self.onSelectionChanged = [ ]
2126                 self.mode = 0
2127                 self.displaySongMode = False
2128                 self.list = []
2129                 self.itemCount = 0
2130
2131         def connectSelChanged(self, fnc):
2132                 if not fnc in self.onSelectionChanged:
2133                         self.onSelectionChanged.append(fnc)
2134
2135         def disconnectSelChanged(self, fnc):
2136                 if fnc in self.onSelectionChanged:
2137                         self.onSelectionChanged.remove(fnc)
2138
2139         def selectionChanged(self):
2140                 for x in self.onSelectionChanged:
2141                         x()
2142         
2143         def getCurrent(self):
2144                 cur = self.l.getCurrentSelection()
2145                 return cur and cur[0]
2146         
2147         GUI_WIDGET = eListbox
2148         
2149         def postWidgetCreate(self, instance):
2150                 instance.setContent(self.l)
2151                 instance.selectionChanged.get().append(self.selectionChanged)
2152
2153         def preWidgetRemove(self, instance):
2154                 instance.setContent(None)
2155                 instance.selectionChanged.get().remove(self.selectionChanged)
2156
2157         def moveToIndex(self, index):
2158                 self.instance.moveSelectionTo(index)
2159
2160         def getCurrentIndex(self):
2161                 return self.instance.getCurrentIndex()
2162
2163         currentIndex = property(getCurrentIndex, moveToIndex)
2164         currentSelection = property(getCurrent)
2165
2166         def setList(self, list):
2167                 self.list = list
2168                 self.l.setList(list)
2169                 self.itemCount = len(self.list) - 1
2170         
2171         def getItemCount(self):
2172                 return  self.itemCount
2173
2174         def getList(self):
2175                 return self.list
2176
2177         def removeItem(self, index):
2178                 del self.list[index]
2179                 self.l.entryRemoved(index)
2180
2181         def getDisplaySongMode(self):
2182                 return self.displaySongMode
2183                 
2184         def setMode(self, mode):
2185                 self.mode = mode
2186                 if mode == 2 or mode == 6 or mode == 8 or mode == 10 or mode == 18 or mode == 19 or mode == 14 or mode == 20:
2187                         self.displaySongMode = True
2188                         self.l.setItemHeight(68)
2189                 else:
2190                         self.displaySongMode = False
2191                         self.l.setItemHeight(22)
2192
2193
2194 class MerlinMediaPixmap(Pixmap):
2195         def __init__(self):
2196                 Pixmap.__init__(self)
2197                 self.coverArtFileName = ""
2198                 self.picload = ePicLoad()
2199                 self.picload.PictureData.get().append(self.paintCoverArtPixmapCB)
2200                 self.coverFileNames = ["folder.png", "folder.jpg", "cover.jpg", "cover.png", "coverArt.jpg"]
2201
2202         def applySkin(self, desktop, screen):
2203                 from Tools.LoadPixmap import LoadPixmap
2204                 noCoverFile = None
2205                 if self.skinAttributes is not None:
2206                         for (attrib, value) in self.skinAttributes:
2207                                 if attrib == "pixmap":
2208                                         noCoverFile = value
2209                                         break
2210                 if noCoverFile is None:
2211                         noCoverFile = resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/no_coverArt.png")
2212                 self.noCoverPixmap = LoadPixmap(noCoverFile)
2213                 return Pixmap.applySkin(self, desktop, screen)
2214
2215         def onShow(self):
2216                 Pixmap.onShow(self)
2217                 sc = AVSwitch().getFramebufferScale()
2218                 self.picload.setPara((self.instance.size().width(), self.instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
2219
2220         def paintCoverArtPixmapCB(self, picInfo=None):
2221                 ptr = self.picload.getData()
2222                 if ptr != None:
2223                         self.instance.setPixmap(ptr.__deref__())
2224
2225         def updateCoverArt(self, path):
2226                 back = False
2227                 while not path.endswith("/"):
2228                         path = path[:-1]
2229                 new_coverArtFileName = None
2230                 for filename in self.coverFileNames:
2231                         if fileExists(path + filename):
2232                                 new_coverArtFileName = path + filename
2233                 if self.coverArtFileName != new_coverArtFileName:
2234                         if new_coverArtFileName:
2235                                 self.coverArtFileName = new_coverArtFileName
2236                                 print "[MerlinMusicPlayer] using cover from %s " % self.coverArtFileName
2237                                 self.picload.startDecode(self.coverArtFileName)
2238                                 back = True
2239                 else:
2240                         if new_coverArtFileName:
2241                                 back = True
2242                 return back
2243
2244         def showDefaultCover(self):
2245                 self.coverArtFileName = ""
2246                 self.instance.setPixmap(self.noCoverPixmap)
2247
2248         def showCoverFromFile(self, filename):
2249                 self.coverArtFileName = filename
2250                 self.picload.startDecode(self.coverArtFileName)
2251
2252         def embeddedCoverArt(self):
2253                 print "[embeddedCoverArt] found"
2254                 self.coverArtFileName = "/tmp/.id3coverart"
2255                 self.picload.startDecode(self.coverArtFileName)
2256
2257
2258 class SelectPath(Screen):
2259         skin = """<screen name="SelectPath" position="center,center" size="560,320" title="Select path">
2260                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
2261                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
2262                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
2263                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
2264                         <widget name="target" position="0,60" size="540,22" valign="center" font="Regular;22" />
2265                         <widget name="filelist" position="0,100" zPosition="1" size="560,220" scrollbarMode="showOnDemand"/>
2266                         <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" />
2267                         <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" />
2268                 </screen>"""
2269         def __init__(self, session, initDir):
2270                 Screen.__init__(self, session)
2271                 inhibitDirs = ["/bin", "/boot", "/dev", "/etc", "/lib", "/proc", "/sbin", "/sys", "/usr", "/var"]
2272                 inhibitMounts = []
2273                 self["filelist"] = FileList(initDir, showDirectories = True, showFiles = False, inhibitMounts = inhibitMounts, inhibitDirs = inhibitDirs)
2274                 self["target"] = Label()
2275                 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EPGSelectActions"],
2276                 {
2277                         "back": self.cancel,
2278                         "left": self.left,
2279                         "right": self.right,
2280                         "up": self.up,
2281                         "down": self.down,
2282                         "ok": self.ok,
2283                         "green": self.green,
2284                         "red": self.cancel
2285                         
2286                 }, -1)
2287                 self["key_red"] = StaticText(_("Cancel"))
2288                 self["key_green"] = StaticText(_("OK"))
2289
2290         def cancel(self):
2291                 self.close(None)
2292
2293         def green(self):
2294                 self.close(self["filelist"].getSelection()[0])
2295
2296         def up(self):
2297                 self["filelist"].up()
2298                 self.updateTarget()
2299
2300         def down(self):
2301                 self["filelist"].down()
2302                 self.updateTarget()
2303
2304         def left(self):
2305                 self["filelist"].pageUp()
2306                 self.updateTarget()
2307
2308         def right(self):
2309                 self["filelist"].pageDown()
2310                 self.updateTarget()
2311
2312         def ok(self):
2313                 if self["filelist"].canDescent():
2314                         self["filelist"].descent()
2315                         self.updateTarget()
2316
2317         def updateTarget(self):
2318                 currFolder = self["filelist"].getSelection()[0]
2319                 if currFolder is not None:
2320                         self["target"].setText(currFolder)
2321                 else:
2322                         self["target"].setText(_("Invalid Location"))
2323
2324
2325 class MerlinMusicPlayerLCDScreen(Screen):
2326         skin = """
2327                 <screen position="0,0" size="132,64">
2328                         <widget source="session.CurrentService" render="Label" position="4,0" size="132,12" valign="top" font="Regular;10" halign="center">
2329                                 <convert type="ServicePosition">Position,ShowHours</convert>
2330                         </widget>
2331                         <widget name="text1" position="4,14" size="132,35" halign="center" valign="top" font="Regular;14"/>
2332                         <widget name="text4" position="4,51" size="132,12" halign="center" valign="top" font="Regular;10"/>
2333                 </screen>"""
2334
2335         def __init__(self, session, parent):
2336                 Screen.__init__(self, session)
2337                 self["text1"] = Label()
2338                 self["text4"] = Label()
2339
2340         def setText(self, text, line):
2341                 if line == 1:
2342                         self["text1"].setText(text)
2343                 elif line == 4:
2344                         self["text4"].setText(text)
2345
2346 class MerlinMusicPlayerLCDScreenText(Screen):
2347         skin = """
2348                 <screen position="0,0" size="132,64">
2349                         <widget name="text3" position="4,0" size="132,14" font="Regular;10"/>
2350                         <widget name="text1" position="4,14" size="132,35" font="Regular;14"/>
2351                         <widget name="text4" position="4,49" size="132,14" font="Regular;10"/>
2352                 </screen>"""
2353
2354         def __init__(self, session, parent):
2355                 Screen.__init__(self, session)
2356                 self["text1"] = Label()
2357                 self["text3"] = Label()
2358                 self["text4"] = Label()
2359
2360         def setText(self, text, line):
2361                 textleer = "    "
2362                 text = text + textleer*10
2363                 if line == 1:
2364                         self["text1"].setText(text)
2365                 elif line == 3:
2366                         self["text3"].setText(text)
2367                 elif line == 4:
2368                         self["text4"].setText(text)
2369
2370
2371 class MerlinMusicPlayerSetup(Screen, ConfigListScreen):
2372
2373         sz_w = getDesktop(0).size().width()
2374         if sz_w == 1280:
2375                 skin = """
2376                         <screen position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="Merlin Music Player Setup" >
2377                                 <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmpborderHD.png" position="128,72" size="1024,576"/>
2378                                 <ePixmap position="178,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
2379                                 <ePixmap position="328,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
2380                                 <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" />
2381                                 <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" />
2382                                 <widget name="config" position="178,152" size="924,350" backgroundColor="#00000000" scrollbarMode="showOnDemand" />
2383                         </screen>"""
2384
2385         elif sz_w == 1024:
2386                 skin = """
2387                         <screen position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="Merlin Music Player Setup" >
2388                                 <ePixmap position="50,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
2389                                 <ePixmap position="200,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
2390                                 <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" />
2391                                 <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" />
2392                                 <widget name="config" position="50,80" size="924,350" backgroundColor="#00000000" scrollbarMode="showOnDemand" />
2393                         </screen>"""
2394         else:
2395                 skin = """
2396                         <screen name="MerlinMusicPlayerFileList" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="Merlin Music Player Setup">
2397                                 <ePixmap position="50,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
2398                                 <ePixmap position="200,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
2399                                 <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" />
2400                                 <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" />
2401                                 <widget name="config" position="50,80" size="620,350" backgroundColor="#00000000" scrollbarMode="showOnDemand" />
2402                         </screen>"""
2403
2404
2405         def __init__(self, session, databasePath):
2406                 Screen.__init__(self, session)
2407
2408                 self["key_red"] = StaticText(_("Cancel"))
2409                 self["key_green"] = StaticText(_("OK"))
2410
2411                 self.list = [ ]
2412                 if HardwareInfo().get_device_name() != "dm7025":
2413                         self.list.append(getConfigListEntry(_("Use hardware-decoder for MP3"), config.plugins.merlinmusicplayer.hardwaredecoder))
2414                 self.list.append(getConfigListEntry(_("Play last used songlist after starting"), config.plugins.merlinmusicplayer.startlastsonglist))
2415                 if databasePath:
2416                         self.database = getConfigListEntry(_("iDream database path"), config.plugins.merlinmusicplayer.databasepath)
2417                         self.list.append(self.database)
2418                 else:
2419                         self.database = None
2420                 self.list.append(getConfigListEntry(_("Use google-images for cover art"), config.plugins.merlinmusicplayer.usegoogleimage))
2421                 self.googleimage = getConfigListEntry(_("Google image path"), config.plugins.merlinmusicplayer.googleimagepath)
2422                 self.list.append(self.googleimage)
2423                 self.list.append(getConfigListEntry(_("Activate screensaver"), config.plugins.merlinmusicplayer.usescreensaver))
2424                 self.list.append(getConfigListEntry(_("Wait for screensaver (in min)"), config.plugins.merlinmusicplayer.screensaverwait))
2425                 self.list.append(getConfigListEntry(_("Remember last path of filebrowser"), config.plugins.merlinmusicplayer.rememberlastfilebrowserpath))
2426                 self.defaultFileBrowserPath = getConfigListEntry(_("Filebrowser startup path"), config.plugins.merlinmusicplayer.defaultfilebrowserpath)
2427                 self.list.append(self.defaultFileBrowserPath)
2428                 self.list.append(getConfigListEntry(_("Show iDream in extended-pluginlist"), config.plugins.merlinmusicplayer.idreamextendedpluginlist))
2429                 self.list.append(getConfigListEntry(_("Show Merlin Music Player in extended-pluginlist"), config.plugins.merlinmusicplayer.merlinmusicplayerextendedpluginlist))
2430
2431                 ConfigListScreen.__init__(self, self.list, session)
2432                 self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
2433                 {
2434                         "green": self.keySave,
2435                         "cancel": self.keyClose,
2436                         "ok": self.keySelect,
2437                 }, -2)
2438
2439         def keySelect(self):
2440                 cur = self["config"].getCurrent()
2441                 if cur == self.database:
2442                         self.session.openWithCallback(self.pathSelectedDatabase,SelectPath,config.plugins.merlinmusicplayer.databasepath.value)
2443                 elif cur == self.defaultFileBrowserPath:
2444                         self.session.openWithCallback(self.pathSelectedFilebrowser,SelectPath,config.plugins.merlinmusicplayer.defaultfilebrowserpath.value)
2445                 elif cur == self.googleimage:
2446                         self.session.openWithCallback(self.pathSelectedGoogleImage,SelectPath,config.plugins.merlinmusicplayer.googleimagepath.value)
2447
2448         def pathSelectedGoogleImage(self, res):
2449                 if res is not None:
2450                         config.plugins.merlinmusicplayer.googleimagepath.value = res
2451
2452         def pathSelectedDatabase(self, res):
2453                 if res is not None:
2454                         config.plugins.merlinmusicplayer.databasepath.value = res
2455
2456         def pathSelectedFilebrowser(self, res):
2457                 if res is not None:
2458                         config.plugins.merlinmusicplayer.defaultfilebrowserpath.value = res
2459
2460         def keySave(self):
2461                 for x in self["config"].list:
2462                         x[1].save()
2463                 configfile.save()
2464                 self.close(True)
2465
2466         def keyClose(self):
2467                 for x in self["config"].list:
2468                         x[1].cancel()
2469                 self.close(False)
2470
2471
2472
2473 class MerlinMusicPlayerFileList(Screen):
2474         
2475         sz_w = getDesktop(0).size().width()
2476         if sz_w == 1280:
2477                 skin = """
2478                         <screen name="MerlinMusicPlayerFileList" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
2479                         <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmpborderHD.png" position="128,72" size="1024,576"/>
2480                         <eLabel backgroundColor="#999999" position="178,112" size="924,2" zPosition="1"/>
2481                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="178,104" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>
2482                         <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"/>
2483                         <widget name="headertext" position="178,145" zPosition="1" size="900,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
2484                         <widget name="list" position="178,182" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>                         
2485                         </screen>"""
2486         elif sz_w == 1024:
2487                 skin = """
2488                         <screen name="MerlinMusicPlayerFileList" position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
2489                         <eLabel backgroundColor="#999999" position="50,40" size="924,2" zPosition="1"/>
2490                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,32" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>
2491                         <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"/>
2492                         <widget name="headertext" position="50,73" zPosition="1" size="900,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
2493                         <widget name="list" position="50,110" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
2494                         </screen>"""
2495         else:
2496                 skin = """
2497                         <screen name="MerlinMusicPlayerFileList" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
2498                         <eLabel backgroundColor="#999999" position="50,50" size="620,2" zPosition="1"/>\r
2499                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,40" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>\r
2500                         <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"/>
2501
2502                         <widget name="headertext" position="50,73" zPosition="1" size="620,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
2503                         <widget name="list" position="50,110" zPosition="2" size="620,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
2504                         </screen>"""
2505                 
2506         
2507         def __init__(self, session):
2508                 self.session = session
2509                 Screen.__init__(self, session)
2510                 self["list"] = FileList(config.plugins.merlinmusicplayer.defaultfilebrowserpath.value, showDirectories = True, showFiles = True, matchingPattern = "(?i)^.*\.(mp3|m4a|flac|ogg|m3u|pls|cue)", useServiceRef = False)
2511
2512
2513                 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EPGSelectActions"],
2514                 {
2515                         "ok": self.ok,
2516                         "back": self.close,
2517                         "input_date_time": self.config,
2518                         "info" : self.info_pressed,
2519                 }, -1)
2520
2521                 self["headertext"] = Label(_("Filelist"))
2522                 self.player = None
2523                 self.onClose.append(self.__onClose)
2524                 self.onLayoutFinish.append(self.startRun)
2525                 self.CurrentService = self.session.nav.getCurrentlyPlayingServiceReference()
2526                 self.session.nav.stopService()
2527
2528         def startRun(self):
2529                 if config.plugins.merlinmusicplayer.startlastsonglist.value:
2530                         self.startPlayerTimer = eTimer()
2531                         self.startPlayerTimer.callback.append(self.startPlayerTimerCallback)
2532                         self.startPlayerTimer.start(0,1)
2533
2534         def startPlayerTimerCallback(self):
2535                 connection = OpenDatabase()
2536                 connection.text_factory = str
2537                 cursor = connection.cursor()
2538                 iDreamMode = False
2539                 SongList = []
2540                 cursor.execute("select song_id, filename, title, artist, album, genre, bitrate, length,  track, date, PTS from CurrentSongList;")
2541                 for row in cursor:
2542                         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),))
2543                         if row[0] != 0:
2544                                 iDreamMode = True
2545                 cursor.close() 
2546                 connection.close()
2547                 if self.player is not None:
2548                         self.player.doClose()
2549                         self.player = None
2550                 count = len(SongList)
2551                 if count:
2552                         # just to be sure, check the index , it's critical
2553                         index = config.plugins.merlinmusicplayer.lastsonglistindex.value
2554                         if index >= count:
2555                                 index = 0
2556                         self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,SongList, index, iDreamMode)
2557                         self.session.execDialog(self.player)
2558         
2559         def readCUE(self, filename):
2560                 SongList = []
2561                 displayname = None
2562                 try:
2563                         cuefile = open(filename, "r")
2564                 except IOError:
2565                         return None
2566                 import re
2567                 performer_re = re.compile(r"""PERFORMER "(?P<performer>.*?)"(?:=\r\n|\r|\n|$)""")
2568                 title_re = re.compile(r"""TITLE "(?P<title>.*?)"(?:=\r\n|\r|\n|$)""")
2569                 filename_re = re.compile(r"""FILE "(?P<filename>.+?)".*(?:=\r\n|\r|\n|$)""", re.DOTALL)
2570                 track_re = re.compile(r"""TRACK (?P<track_number>[^ ]+?)(?:[ ]+.*?)(?:=\r\n|\r|\n|$)""")
2571                 index_re = re.compile(r"""INDEX (?P<index_nr>[^ ]+?)[ ]+(?P<track_index>[^ ]+?)(?:=\r\n|\r|\n|$)""")
2572                 msts_re = re.compile("""^(?P<mins>[0-9]{1,}):(?P<secs>[0-9]{2}):(?P<ms>[0-9]{2})$""")
2573                 songfilename = ""
2574                 album = ""
2575                 performer = ""
2576                 title = ""
2577                 pts = 0
2578                 state = 0 # header
2579                 for line in cuefile.readlines():
2580                         entry = line.strip()
2581                         m = filename_re.search(entry)
2582                         if m:
2583                                 if  m.group('filename')[0] == "/":
2584                                         songfilename = m.group('filename')
2585                                 else:
2586                                         songfilename = os_path.dirname(filename) + "/" + m.group('filename')
2587                         m = title_re.search(entry)
2588                    &