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