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