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