Merge branch 'refs/heads/master' of ssh://sreichholf@scm.schwerkraft.elitedvb.net...
[vuplus_dvbapp-plugin] / 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","\n")
1502                         text = text.replace("\r","\n")
1503                         self["lyric_text"].setText(text)
1504                 else:
1505                         self["lyric_text"].setText("No lyrics found")
1506   
1507         def getLyricsFromID3Tag(self,tag):
1508                 for frame in tag.values():
1509                         if frame.FrameID == "USLT":
1510                                 return frame.text
1511                 return "No lyrics found in id3-tag"
1512
1513         
1514         def urlError(self, error = None):
1515                 if error is not None:
1516                         self["resulttext"].setText(str(error.getErrorMessage()))
1517
1518         def getHID(self, xmlstring):
1519                 root = cet_fromstring(xmlstring)
1520                 url = ""
1521                 child = root.find("searchResults")
1522                 if child:
1523                         child2 = child.find("result")
1524                         if child2:
1525                                 url = "http://api.leoslyrics.com/api_lyrics.php?auth=duane&hid=%s" % quote(child2.get("hid"))
1526                                 sendUrlCommand(url, None,10).addCallback(self.getLyrics).addErrback(self.urlError)
1527                 if not url:
1528                         self["resulttext"].setText(_("No lyrics found"))
1529
1530         def getLyrics(self, xmlstring):
1531                 root = cet_fromstring(xmlstring)
1532                 lyrictext = ""
1533                 child = root.find("lyric")
1534                 if child:
1535                         title = child.findtext("title").encode("utf-8", 'ignore')
1536                         child2 = child.find("artist")
1537                         if child2:
1538                                 artist = child2.findtext("name").encode("utf-8", 'ignore')
1539                         else:
1540                                 artist = ""
1541                         lyrictext = child.findtext("text").encode("utf-8", 'ignore')
1542                         self["lyric_text"].setText(lyrictext)
1543                         result = _("Response -> lyrics for: %s (%s)") % (title,artist)
1544                         self["resulttext"].setText(result)
1545                 if not lyrictext:
1546                         self["resulttext"].setText(_("No lyrics found"))
1547
1548         def pageUp(self):
1549                 self["lyric_text"].pageUp()
1550
1551         def pageDown(self):
1552                 self["lyric_text"].pageDown()   
1553
1554 class MerlinMusicPlayerSongList(Screen):
1555         
1556         sz_w = getDesktop(0).size().width()
1557         if sz_w == 1280:
1558                 skin = """
1559                         <screen name="MerlinMusicPlayerSongList" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="Songlist">
1560                         <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmpborderHD.png" position="128,72" size="1024,576"/>
1561                         <eLabel backgroundColor="#999999" position="178,112" size="924,2" zPosition="1"/>
1562                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="178,104" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>
1563                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="852,104" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
1564                         <widget name="headertext" position="178,145" zPosition="1" size="900,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
1565                         <widget name="list" position="178,182" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
1566                         </screen>"""
1567         elif sz_w == 1024:
1568                 skin = """
1569                         <screen name="MerlinMusicPlayerSongList" position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="Songlist">
1570                         <eLabel backgroundColor="#999999" position="50,40" size="924,2" zPosition="1"/>
1571                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,32" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>
1572                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="724,32" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
1573                         <widget name="headertext" position="50,73" zPosition="1" size="900,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
1574                         <widget name="list" position="50,110" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
1575                         </screen>"""
1576         else:
1577                 skin = """
1578                         <screen name="MerlinMusicPlayerSongList" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="Songlist">
1579                         <eLabel backgroundColor="#999999" position="50,50" size="620,2" zPosition="1"/>
1580                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,40" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>
1581                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="420,40" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
1582                         <widget name="headertext" position="50,73" zPosition="1" size="620,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
1583                         <widget name="list" position="50,110" zPosition="2" size="620,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
1584                         </screen>"""
1585                 
1586         
1587         def __init__(self, session, songlist, index, idreammode):
1588                 self.session = session
1589                 Screen.__init__(self, session)
1590                 self["headertext"] = Label(_("Merlin Music Player Songlist"))
1591                 self["list"] = iDreamList()
1592                 self["list"].connectSelChanged(self.lcdUpdate)
1593                 self["actions"] = ActionMap(["WizardActions"],
1594                 {
1595                         "ok": self.ok,
1596                         "back": self.closing,
1597                 }, -1)
1598                 self.songList = songlist
1599                 self.index = index
1600                 self.iDreamMode = idreammode
1601                 self.onLayoutFinish.append(self.startRun)
1602                 self.onShown.append(self.lcdUpdate)
1603
1604         def startRun(self):
1605                 if self.iDreamMode:
1606                         self["list"].setMode(10) # songlist
1607                 self["list"].setList(self.songList)
1608                 self["list"].moveToIndex(self.index)
1609
1610         def ok(self):
1611                 self.close(self["list"].getCurrentIndex())
1612
1613         def closing(self):
1614                 self.close(-1)
1615
1616         def lcdUpdate(self):
1617                 try:
1618                         index = self["list"].getCurrentIndex()
1619                         songlist = self["list"].getList()
1620                         mode =  self.iDreamMode or songlist[index][0].PTS
1621                         if mode:
1622                                 self.summaries.setText(songlist[index][0].title,1)
1623                         else:
1624                                 self.summaries.setText(songlist[index][0].text,1)
1625                         count = self["list"].getItemCount()
1626                         # voheriges
1627                         index -= 1
1628                         if index < 0:
1629                                 index = count
1630                         if mode:
1631                                 self.summaries.setText(songlist[index][0].title,3)
1632                         else:
1633                                 self.summaries.setText(songlist[index][0].text,3)
1634                         # naechstes
1635                         index = self["list"].getCurrentIndex() + 1
1636                         if index > count:
1637                                 index = 0
1638                         if mode:
1639                                 self.summaries.setText(songlist[index][0].title,4)
1640                         else:
1641                                 self.summaries.setText(songlist[index][0].text,4)
1642                 except: pass
1643
1644         def createSummary(self):
1645                 return MerlinMusicPlayerLCDScreenText
1646
1647 class iDreamMerlin(Screen):
1648         
1649
1650         sz_w = getDesktop(0).size().width()
1651         if sz_w == 1280:
1652                 skin = """
1653                         <screen name="iDreamMerlin" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
1654                                 <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmpborderHD.png" position="128,72" size="1024,576"/>
1655                                 <ePixmap position="178,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1656                                 <ePixmap position="328,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1657                                 <ePixmap position="478,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1658                                 <ePixmap position="628,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
1659                                 <widget render="Label" source="key_red" position="178,102" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1660                                 <widget render="Label" source="key_green" position="328,102" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1661                                 <widget render="Label" source="key_yellow" position="478,102" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1662                                 <widget render="Label" source="key_blue" position="628,102" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1663                                 <widget name="headertext" position="178,149" zPosition="1" size="900,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
1664                                 <widget name="list" position="178,182" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
1665                         </screen>"""
1666         elif sz_w == 1024:
1667                 skin = """
1668                         <screen name="iDreamMerlin" position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
1669                                 <ePixmap position="50,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1670                                 <ePixmap position="200,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1671                                 <ePixmap position="350,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1672                                 <ePixmap position="500,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
1673                                 <widget render="Label" source="key_red" position="50,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1674                                 <widget render="Label" source="key_green" position="200,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1675                                 <widget render="Label" source="key_yellow" position="350,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1676                                 <widget render="Label" source="key_blue" position="500,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1677                                 <widget name="headertext" position="50,77" zPosition="1" size="900,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
1678                                 <widget name="list" position="50,110" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
1679                         </screen>"""
1680         else:
1681                 skin = """
1682                         <screen name="iDreamMerlin" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
1683                                 <ePixmap position="50,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
1684                                 <ePixmap position="200,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
1685                                 <ePixmap position="350,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
1686                                 <ePixmap position="500,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
1687                                 <widget render="Label" source="key_red" position="50,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1688                                 <widget render="Label" source="key_green" position="200,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1689                                 <widget render="Label" source="key_yellow" position="350,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1690                                 <widget render="Label" source="key_blue" position="500,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
1691                                 <widget name="headertext" position="50,77" zPosition="1" size="620,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
1692                                 <widget name="list" position="50,110" zPosition="2" size="620,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
1693                         </screen>"""
1694                 
1695         
1696         def __init__(self, session, servicelist):
1697                 self.session = session
1698                 Screen.__init__(self, session)
1699                 self["list"] = iDreamList()
1700                 self["list"].connectSelChanged(self.lcdUpdate)
1701
1702
1703                 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EPGSelectActions"],
1704                 {
1705                         "ok": self.ok,
1706                         "back": self.closing,
1707                         "red": self.red_pressed,
1708                         "green": self.green_pressed,
1709                         "yellow": self.yellow_pressed,
1710                         "blue": self.blue_pressed,
1711                         "input_date_time": self.menu_pressed,
1712                         "info" : self.info_pressed,
1713                 }, -1)
1714
1715                 self["actions2"] = NumberActionMap(["InputActions"],
1716                 {
1717                         "0": self.keyNumber_pressed,
1718                 }, -1)
1719
1720                 self.onLayoutFinish.append(self.startRun)
1721                 self.onShown.append(self.lcdUpdate)
1722                 self.onClose.append(self.__onClose)
1723                 
1724                 self.serviceList = servicelist
1725                 self.currentService = self.session.nav.getCurrentlyPlayingServiceReference()
1726                 self.session.nav.stopService()
1727                 
1728                 self.mode = 0
1729                 self.mainMenuList = []
1730                 self.cacheList = []
1731                 self.LastMethod = None
1732                 self.player = None
1733                 
1734                 self["key_red"] = StaticText("")
1735                 self["key_green"] = StaticText("")
1736                 self["key_yellow"] = StaticText("")
1737                 self["key_blue"] = StaticText("")
1738                 self["headertext"] = Label(_("iDream Main Menu"))
1739
1740                 self.startMerlinPlayerScreenTimer = eTimer()
1741                 self.startMerlinPlayerScreenTimer.timeout.get().append(self.info_pressed)
1742
1743         def getPlayList(self):
1744                 connection = OpenDatabase()
1745                 if connection is not None:
1746                         connection.text_factory = str
1747                         cursor = connection.cursor()
1748                         playList = []
1749                         cursor.execute("select playlist_id,playlist_text from playlists order by playlist_text;")
1750                         for row in cursor:
1751                                 playList.append((row[1], row[0]))
1752                         cursor.close()  
1753                         connection.close()
1754                         return playList
1755                 else:
1756                         return None
1757
1758         def sqlCommand(self, sqlSatement):
1759                 connection = OpenDatabase()
1760                 if connection is not None:
1761                         cursor = connection.cursor()
1762                         cursor.execute(sqlSatement)
1763                         cursor.close()
1764                         connection.commit()
1765                         connection.close()
1766
1767         def clearCache(self):
1768                 for items in self.cacheList:
1769                         items.cache = False
1770                         items.listview = []
1771                         items.headertext = ""
1772
1773         def getCurrentSelection(self):
1774                 sel = None
1775                 try: sel = self["list"].l.getCurrentSelection()[0]
1776                 except: pass
1777                 return sel
1778
1779         def addListToPlaylistConfirmed(self, methodName, answer):
1780                 if answer:
1781                         playList = self.getPlayList()
1782                         if len(playList):
1783                                 self.session.openWithCallback(methodName, ChoiceBox,list = playList)
1784                         else:
1785                                 self.session.openWithCallback(self.createPlaylistConfirmed, MessageBox, _("There are no playlists defined.\nDo you want to create a new playlist?"))
1786
1787         def menu_pressed(self):
1788                 self.startMerlinPlayerScreenTimer.stop()
1789                 options = [(_("Configuration"), self.config),(_("Search in iDream database"), self.searchInIDreamDatabase),]
1790                 options.extend(((_("Scan path for music files and add them to database"), self.scanDir),))
1791                 if self.mode != 1:
1792                         options.extend(((_("Create new playlist"), self.createPlaylist),))
1793                 if self["list"].getDisplaySongMode():
1794                         if self.mode == 2:
1795                                 options.extend(((_("Delete song from current playlist"), self.deleteSongFromPlaylist),))
1796                         else:
1797                                 options.extend(((_("Add selected song to a playlist"), self.addSongToPlaylist),))
1798                                 if self.mode == 18:
1799                                         options.extend(((_("Add all songs from selected album to a playlist"), self.addAlbumToPlaylist),))
1800                                 elif self.mode == 19:
1801                                         options.extend(((_("Add all songs from selected artist to a playlist"), self.addArtistToPlaylist),))
1802                                 options.extend(((_("Delete song from database"), self.deleteSongFromDatabase),))
1803                         options.extend(((_("Clear current songlist and play selected entry"), self.stopPlayingAndAppendFileToSongList),))
1804                         options.extend(((_("Append file to current playing songlist"), self.appendFileToSongList),))
1805                         if self.player is not None and self.player.songList:
1806                                 options.extend(((_("Insert file to current playing songlist and play next"), self.insertFileToSongList),))
1807                 else:
1808                         if self.mode == 1:
1809                                 options.extend(((_("Delete selected playlist"), self.deletePlaylist),))
1810                         elif self.mode == 4:
1811                                 options.extend(((_("Add all songs from selected artist to a playlist"), self.addArtistToPlaylist),))
1812                         elif self.mode == 5 or self.mode == 7:
1813                                 options.extend(((_("Add all songs from selected album to a playlist"), self.addAlbumToPlaylist),))
1814                         elif self.mode == 13:
1815                                 options.extend(((_("Add all songs from selected genre to a playlist"), self.addGenreToPlaylist),))
1816                 self.session.openWithCallback(self.menuCallback, ChoiceBox,list = options)
1817
1818         def menuCallback(self, ret):
1819                 ret and ret[1]()
1820
1821         def scanDir(self):
1822                 SelectPath
1823                 self.session.openWithCallback(self.pathSelected,SelectPath,"/media/")
1824
1825         def pathSelected(self, res):
1826                 if res is not None:
1827                         self.session.openWithCallback(self.filesAdded, iDreamAddToDatabase,res)
1828
1829         def filesAdded(self):
1830                 if pathToDatabase.isRunning:
1831                         self.close()
1832                 else:
1833                         self.red_pressed()
1834                 
1835
1836
1837
1838         def addGenreToPlaylist(self):
1839                 self.session.openWithCallback(boundFunction(self.addListToPlaylistConfirmed,self.addGenreToPlaylistConfirmedCallback), MessageBox, _("Do you really want to add all songs from that genre to a playlist?"))
1840
1841         def addGenreToPlaylistConfirmedCallback(self, ret):
1842                 if ret:
1843                         sel = self.getCurrentSelection()
1844                         if sel:
1845                                 self.sqlCommand("INSERT INTO Playlist_Songs (playlist_id,song_id) select %d, song_id from songs where genre_id=%d order by album_id,tracknumber,title,filename;" % (ret[1],sel.genreID))
1846                                 self.clearCache()
1847
1848         def addArtistToPlaylist(self):
1849                 self.session.openWithCallback(boundFunction(self.addListToPlaylistConfirmed, self.addArtistToPlaylistConfirmedCallback), MessageBox, _("Do you really want to add all songs from that artist to a playlist?"))
1850
1851         def addArtistToPlaylistConfirmedCallback(self, ret):
1852                 if ret:
1853                         sel = self.getCurrentSelection()
1854                         if sel:
1855                                 self.sqlCommand("INSERT INTO Playlist_Songs (playlist_id,song_id) select %d, song_id from songs where artist_id=%d order by album_id,tracknumber,title,filename;" % (ret[1],sel.artistID))
1856                                 self.clearCache()
1857
1858         def addAlbumToPlaylist(self):
1859                 self.session.openWithCallback(boundFunction(self.addListToPlaylistConfirmed, self.addAlbumToPlaylistConfirmedCallback), MessageBox, _("Do you really want to add all songs from that album to a playlist?"))
1860
1861         def addAlbumToPlaylistConfirmedCallback(self, ret):
1862                 if ret:
1863                         sel = self.getCurrentSelection()
1864                         if sel:
1865                                 self.sqlCommand("INSERT INTO Playlist_Songs (playlist_id,song_id) select %d, song_id from songs where album_id=%d order by tracknumber,title,filename;" % (ret[1],sel.albumID))
1866                                 self.clearCache()
1867
1868         def deletePlaylist(self):
1869                 self.session.openWithCallback(self.deletePlaylistConfirmed, MessageBox, _("Do you really want to delete the current playlist?"))
1870
1871         def deletePlaylistConfirmed(self, answer):
1872                 if answer:
1873                         sel = self.getCurrentSelection()
1874                         if sel:
1875                                 self.sqlCommand("delete from playlist_songs where playlist_id = %d" % (sel.playlistID))
1876                                 self.sqlCommand("delete from playlists where playlist_id = %d" % (sel.playlistID))
1877                                 self["list"].removeItem(self["list"].getCurrentIndex())
1878                                 self.clearCache()
1879
1880
1881         def deleteSongFromPlaylist(self):
1882                 self.session.openWithCallback(self.deleteSongFromPlaylistConfirmed, MessageBox, _("Do you really want to delete that song the current playlist?"))
1883
1884         def deleteSongFromPlaylistConfirmed(self, answer):
1885                 if answer:
1886                         sel = self.getCurrentSelection()
1887                         if sel:
1888                                 self.sqlCommand("delete from playlist_songs where song_id = %d" % (sel.songID))
1889                                 self["list"].removeItem(self["list"].getCurrentIndex())
1890                                 self.clearCache()
1891
1892         def deleteSongFromDatabase(self):
1893                 self.session.openWithCallback(self.deleteSongFromDatabaseConfirmed, MessageBox, _("Do you really want to delete that song from the database?"))
1894
1895         def deleteSongFromDatabaseConfirmed(self, answer):
1896                 if answer:
1897                         sel = self.getCurrentSelection()
1898                         if sel:
1899                                 self.sqlCommand("delete from playlist_songs where song_id = %d" % (sel.songID))
1900                                 self.sqlCommand("delete from songs where song_id = %d" % (sel.songID))
1901                                 self["list"].removeItem(self["list"].getCurrentIndex())
1902                                 self.clearCache()
1903                         
1904         def addSongToPlaylist(self):
1905                 playList = self.getPlayList()
1906                 if len(playList):
1907                         self.session.openWithCallback(self.addSongToPlaylistCallback, ChoiceBox,list = playList)
1908                 else:
1909                         self.session.openWithCallback(self.createPlaylistConfirmed, MessageBox, _("There are no playlists defined.\nDo you want to create a new playlist?"))
1910
1911         def createPlaylistConfirmed(self, val):
1912                 if val:
1913                         self.createPlaylist()
1914
1915         def addSongToPlaylistCallback(self,ret):
1916                 if ret:
1917                         sel = self.getCurrentSelection()
1918                         if sel:
1919                                 self.sqlCommand("INSERT INTO Playlist_Songs (playlist_id,song_id) VALUES(%d,%d);" % (ret[1],sel.songID))
1920                                 self.clearCache()
1921
1922         def createPlaylist(self):
1923                 self.session.openWithCallback(self.createPlaylistFinished, VirtualKeyBoard, title = _("Enter name for playlist"))
1924
1925         def createPlaylistFinished(self, text = None):
1926                 if text:
1927                         self.sqlCommand('INSERT INTO Playlists (playlist_text) VALUES("%s");' % (text))
1928                         self.clearCache()
1929                         self.menu_pressed()
1930
1931         def searchInIDreamDatabase(self):
1932                 options = [(_("search for title"), 1),
1933                         (_("search for artist"), 2),
1934                         (_("search for album"), 3),
1935                         (_("search in all of them"), 4),]
1936                 self.session.openWithCallback(self.enterSearchText, ChoiceBox,list = options)
1937
1938         def enterSearchText(self, ret):
1939                 if ret:
1940                         self.session.openWithCallback(boundFunction(self.enterSearchTextFinished,ret[1]), VirtualKeyBoard, title = _("Enter search-text"))
1941
1942         def enterSearchTextFinished(self, searchType, searchText = None):
1943                 if searchText:
1944                         search = "%" + searchText + "%"
1945                         if searchType == 1:
1946                                 sql_where = "where title like '%s'" % search
1947                                 text = _('Search results for "%s" in all titles') % searchText
1948                         elif searchType == 2:
1949                                 sql_where = "where artists.artist like '%s'" % search
1950                                 text = _('Search results for "%s" in all artists') % searchText
1951                         elif searchType == 3:
1952                                 sql_where = "where album_text like '%s'" % search
1953                                 text = _('Search results for "%s" in all albums') % searchText
1954                         else:
1955                                 sql_where = "where (title like '%s' or artists.artist like '%s' or album_text like '%s')"  % (search,search,search)
1956                                 text = _('Search results for "%s" in title, artist or album') % searchText
1957                         self.setButtons(red = True, yellow = True, blue = True)
1958                         oldmode = self.mode
1959                         self.mode = 20
1960                         self["list"].setMode(self.mode)
1961                         self.buildSearchSongList(sql_where, text, oldmode, True)
1962
1963
1964         def keyNumber_pressed(self, number):
1965                 if number == 0 and self.mode != 0:
1966                         self["list"].moveToIndex(0)
1967                         self.ok()
1968
1969         def ok(self):
1970                 sel = self.getCurrentSelection()
1971                 if sel is None:
1972                         return
1973                 if sel.mode == 99:
1974                         self.green_pressed()
1975                 else:
1976                         self.mode = sel.mode
1977                         self["list"].setMode(self.mode)
1978                         if sel.navigator and len(self.cacheList) > 0:
1979                                 cache = self.cacheList.pop()
1980                         else:
1981                                 cache = CacheList(cache = False, index = -1)
1982                         if sel.navigator: 
1983                                 self["headertext"].setText(cache.headertext)
1984                                 if cache.cache:
1985                                         self["list"].setList(cache.listview)
1986                                         self.LastMethod = MethodArguments(method = cache.methodarguments.method, arguments = cache.methodarguments.arguments)
1987                                 else:
1988                                         cache.methodarguments.method(**cache.methodarguments.arguments)
1989                                 self["list"].moveToIndex(cache.index)
1990                         if self.mode == 0:
1991                                 self.setButtons()
1992                                 if not sel.navigator:
1993                                         self.buildMainMenuList()
1994                         elif self.mode == 1:
1995                                 self.setButtons(red = True)
1996                                 if not sel.navigator:
1997                                         self.buildPlaylistList(addToCache = True)
1998                         elif self.mode == 2:
1999                                 self.setButtons(red = True, green = True, yellow = True, blue = True)
2000                                 if not sel.navigator:
2001                                         self.buildPlaylistSongList(playlistID = sel.playlistID, addToCache = True)
2002                         elif self.mode == 4:
2003                                 self.setButtons(red = True)
2004                                 if not sel.navigator:
2005                                         self.buildArtistList(addToCache = True)
2006                         elif self.mode == 5:
2007                                 self.setButtons(red = True)
2008                                 if not sel.navigator:
2009                                         self.buildArtistAlbumList(sel.artistID, addToCache = True)
2010                         elif self.mode == 6:
2011                                 self.setButtons(red = True, green = True, yellow = True)
2012                                 if not sel.navigator:
2013                                         self.buildAlbumSongList(albumID = sel.albumID, mode = 5, addToCache = True)
2014                         elif self.mode == 7:
2015                                 self.setButtons(red = True)
2016                                 if not sel.navigator:
2017                                         self.buildAlbumList(addToCache = True)
2018                         elif self.mode == 8:
2019                                 self.setButtons(red = True, green = True, yellow = True)
2020                                 if not sel.navigator:
2021                                         self.buildAlbumSongList(albumID = sel.albumID, mode = 7, addToCache = True)
2022                         elif self.mode == 10:
2023                                 self.setButtons(red = True, green = True, yellow = True, blue = True)
2024                                 if not sel.navigator:
2025                                         self.buildSongList(addToCache = True)
2026                         elif self.mode == 13:
2027                                 self.setButtons(red = True)
2028                                 if not sel.navigator:
2029                                         self.buildGenreList(addToCache = True)
2030                         elif self.mode == 14:
2031                                 self.setButtons(red = True, green = True, yellow = True, blue = True)
2032                                 if not sel.navigator:
2033                                         self.buildGenreSongList(genreID = sel.genreID, addToCache = True)
2034                         elif self.mode == 18 or self.mode == 19:
2035                                 if self.mode == 18:
2036                                         self.setButtons(red = True, green = True, yellow = True)
2037                                 if self.mode == 19:
2038                                         self.setButtons(red = True, green = True, blue = True)
2039                                 if not sel.navigator:
2040                                         self.red_pressed() # back to main menu --> normally that can not be happened
2041                         elif self.mode == 20:
2042                                 self.setButtons(red = True, green = True, yellow = True, blue = True)
2043                                 if not sel.navigator:
2044                                         self.red_pressed() # back to main menu --> normally that can not be happened
2045
2046         def buildPlaylistList(self, addToCache):
2047                 if addToCache:
2048                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2049                 arguments = {}
2050                 arguments["addToCache"] = False
2051                 self.LastMethod = MethodArguments(method = self.buildPlaylistList, arguments = arguments)
2052                 self["headertext"].setText(_("Playlists"))
2053                 connection = OpenDatabase()
2054                 if connection is not None:
2055                         connection.text_factory = str
2056                         cursor = connection.cursor()
2057                         playlistList = []
2058                         playlistList.append((Item(text = _("[back]"), mode = 0, navigator = True),))
2059                         cursor.execute("select playlists.playlist_id, playlist_text, count(Playlist_Songs.playlist_id) from playlists left outer join Playlist_Songs on playlists.playlist_id = Playlist_Songs.playlist_id group by playlists.playlist_id order by playlists.playlist_text;")
2060                         for row in cursor:
2061                                 playlistList.append((Item(text = "%s (%d)" % (row[1], row[2]), mode = 2, playlistID = row[0]),))
2062                         cursor.close() 
2063                         connection.close()
2064                         self["list"].setList(playlistList)
2065                         if len(playlistList) > 1:
2066                                 self["list"].moveToIndex(1)
2067
2068         def buildPlaylistSongList(self, playlistID, addToCache):
2069                 if addToCache:
2070                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2071                 arguments = {}
2072                 arguments["playlistID"] = playlistID
2073                 arguments["addToCache"] = False
2074                 self.LastMethod = MethodArguments(method = self.buildPlaylistSongList, arguments = arguments)
2075                 connection = OpenDatabase()
2076                 if connection is not None:
2077                         connection.text_factory = str
2078                         cursor = connection.cursor()
2079                         playlistSongList = []
2080                         playlistSongList.append((Item(text = _("[back]"), mode = 1, navigator = True),))
2081                         cursor.execute("select songs.song_id, title, artists.artist, filename, songs.artist_id, bitrate, length, genre_text, track, date, album_text, songs.Album_id from songs inner join artists on songs.artist_id = artists.artist_id inner join Album on songs.Album_id = Album.Album_id inner join genre on songs.genre_id = genre.genre_id inner join playlist_songs on songs.song_id = playlist_songs.song_id where playlist_songs.playlist_id =  %d order by playlist_songs.id;" % (playlistID))
2082                         for row in cursor:
2083                                 playlistSongList.append((Item(mode = 99, songID = row[0], title = row[1], artist = row[2], filename = row[3], artistID = row[4], bitrate = row[5], length = row[6], genre = row[7], track = row[8], date = row[9], album = row[10], albumID = row[11], playlistID = playlistID),))
2084                         cursor.execute("SELECT playlist_text from playlists where playlist_id = %d;" % playlistID)
2085                         row = cursor.fetchone()
2086                         self["headertext"].setText(_("Playlist (%s) -> Song List") % row[0])
2087                         cursor.close() 
2088                         connection.close()
2089                         self["list"].setList(playlistSongList)
2090                         if len(playlistSongList) > 1:
2091                                 self["list"].moveToIndex(1)
2092                                 
2093         def buildGenreList(self, addToCache):
2094                 if addToCache:
2095                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2096                 arguments = {}
2097                 arguments["addToCache"] = False
2098                 self.LastMethod = MethodArguments(method = self.buildGenreList, arguments = arguments)
2099                 self["headertext"].setText(_("Genre List"))
2100                 connection = OpenDatabase()
2101                 if connection is not None:
2102                         connection.text_factory = str
2103                         cursor = connection.cursor()
2104                         genreList = []
2105                         genreList.append((Item(text = _("[back]"), mode = 0, navigator = True),))
2106                         cursor.execute("select Genre.genre_id,Genre.Genre_text, count(*) from songs inner join Genre on songs.genre_id = Genre.Genre_id group by songs.Genre_id order by Genre.Genre_text;")
2107                         for row in cursor:
2108                                 genreList.append((Item(text = "%s (%d)" % (row[1], row[2]), mode = 14, genreID = row[0]),))
2109                         cursor.close() 
2110                         connection.close()
2111                         self["list"].setList(genreList)
2112                         if len(genreList) > 1:
2113                                 self["list"].moveToIndex(1)
2114
2115         def buildGenreSongList(self, genreID, addToCache):
2116                 if addToCache:
2117                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2118                 arguments = {}
2119                 arguments["genreID"] = genreID
2120                 arguments["addToCache"] = False
2121                 self.LastMethod = MethodArguments(method = self.buildGenreSongList, arguments = arguments)
2122                 connection = OpenDatabase()
2123                 if connection is not None:
2124                         connection.text_factory = str
2125                         cursor = connection.cursor()
2126                         genreSongList = []
2127                         genreSongList.append((Item(text = _("[back]"), mode = 13, navigator = True),))
2128                         cursor.execute("select song_id, title, artists.artist, filename, songs.artist_id, bitrate, length, genre_text, track, date, album_text, songs.Album_id from songs inner join artists on songs.artist_id = artists.artist_id inner join Album on songs.Album_id = Album.Album_id inner join genre on songs.genre_id = genre.genre_id where songs.genre_id = %d order by title, filename;" % (genreID))
2129                         for row in cursor:
2130                                 genreSongList.append((Item(mode = 99, songID = row[0], title = row[1], artist = row[2], filename = row[3], artistID = row[4], bitrate = row[5], length = row[6], genre = row[7], track = row[8], date = row[9], album = row[10], albumID = row[11], genreID = genreID),))
2131                         cursor.execute("SELECT genre_text from genre where genre_ID = %d;" % genreID)
2132                         row = cursor.fetchone()
2133                         self["headertext"].setText(_("Genre (%s) -> Song List") % row[0])
2134                         cursor.close() 
2135                         connection.close()
2136                         self["list"].setList(genreSongList)
2137                         if len(genreSongList) > 1:
2138                                 self["list"].moveToIndex(1)
2139
2140         def setButtons(self, red = False, green = False, yellow = False, blue = False):
2141                 if red:
2142                         self["key_red"].setText("Main Menu")
2143                 else:
2144                         self["key_red"].setText("")
2145                 if green:
2146                         self["key_green"].setText("Play")
2147                 else:
2148                         self["key_green"].setText("")
2149                 if yellow:
2150                         self["key_yellow"].setText("All Artists")
2151                 else:           
2152                         self["key_yellow"].setText("")
2153                 if blue:
2154                         self["key_blue"].setText("Show Album")
2155                 else:
2156                         self["key_blue"].setText("")
2157
2158         def info_pressed(self):
2159                 self.startMerlinPlayerScreenTimer.stop()
2160                 if self.player is not None:
2161                         if self.player.songList:
2162                                 self.session.execDialog(self.player)
2163
2164         def green_pressed(self):
2165                 try:
2166                         sel = self["list"].l.getCurrentSelection()[0]
2167                 except: 
2168                         sel = None
2169                 if sel is None:
2170                         return
2171                 if sel.songID != 0:
2172                         if self.player is not None:
2173                                 self.player.doClose()
2174                                 self.player = None
2175                         self.startMerlinPlayerScreenTimer.stop()
2176                         self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,self["list"].getList()[1:], self["list"].getCurrentIndex() -1, True, self.currentService, self.serviceList)
2177                         self.session.execDialog(self.player)
2178
2179         def red_pressed(self):
2180                 self.cacheList = []
2181                 self.setButtons()
2182                 self.mode = 0
2183                 self["list"].setMode(self.mode)
2184                 self.buildMainMenuList()
2185         
2186         def yellow_pressed(self):
2187                 try:
2188                         sel = self["list"].l.getCurrentSelection()[0]
2189                 except: 
2190                         return
2191                 if sel.artistID != 0:
2192                         oldmode = self.mode
2193                         self.mode = 19
2194                         self.setButtons(red = True, green = True, blue = True)
2195                         self["list"].setMode(self.mode)
2196                         self.buildArtistSongList(artistID = sel.artistID, mode = oldmode, addToCache = True)
2197                 
2198         def blue_pressed(self):
2199                 try:
2200                         sel = self["list"].l.getCurrentSelection()[0]
2201                 except: 
2202                         return
2203                 if sel.albumID != 0:
2204                         self.setButtons(red = True, green = True, yellow = True)
2205                         oldmode = self.mode
2206                         self.mode = 18
2207                         self["list"].setMode(self.mode)
2208                         self.buildAlbumSongList(albumID = sel.albumID, mode = oldmode, addToCache = True)
2209         
2210         def buildSongList(self, addToCache):
2211                 if addToCache:
2212                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2213                 arguments = {}
2214                 arguments["addToCache"] = False
2215                 self.LastMethod = MethodArguments(method = self.buildSongList,  arguments = arguments)
2216                 self["headertext"].setText(_("All Songs"))
2217                 connection = OpenDatabase()
2218                 if connection is not None:
2219                         connection.text_factory = str
2220                         cursor = connection.cursor()
2221                         SongList = []
2222                         SongList.append((Item(text = _("[back]"), mode = 0, navigator = True),))
2223                         cursor.execute("select song_id, title, artists.artist, filename, songs.artist_id, bitrate, length, genre_text, track, date, album_text, songs.Album_id from songs inner join artists on songs.artist_id = artists.artist_id inner join Album on songs.Album_id = Album.Album_id inner join genre on songs.genre_id = genre.genre_id order by title, filename;")
2224                         for row in cursor:
2225                                 SongList.append((Item(mode = 99, songID = row[0], title = row[1], artist = row[2], filename = row[3], artistID = row[4], bitrate = row[5], length = row[6], genre = row[7], track = row[8], date = row[9], album = row[10], albumID = row[11]),))
2226                         cursor.close() 
2227                         connection.close()
2228                         self["list"].setList(SongList)
2229                         if len(SongList) > 1:
2230                                 self["list"].moveToIndex(1)
2231
2232
2233         def buildSearchSongList(self, sql_where, headerText, mode, addToCache):
2234                 if addToCache:
2235                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2236                 arguments = {}
2237                 arguments["sql_where"] = sql_where
2238                 arguments["headerText"] = headerText
2239                 arguments["mode"] = mode
2240                 arguments["addToCache"] = False
2241                 self.LastMethod = MethodArguments(method = self.buildSearchSongList, arguments = arguments)
2242                 self["headertext"].setText(headerText)
2243                 connection = OpenDatabase()
2244                 if connection is not None:
2245                         connection.text_factory = str
2246                         cursor = connection.cursor()
2247                         SongList = []
2248                         SongList.append((Item(text = _("[back]"), mode = mode, navigator = True),))
2249                         cursor.execute("select song_id, title, artists.artist, filename, songs.artist_id, bitrate, length, genre_text, track, date, album_text, songs.Album_id from songs inner join artists on songs.artist_id = artists.artist_id inner join Album on songs.Album_id = Album.Album_id inner join genre on songs.genre_id = genre.genre_id %s order by title, filename;" % sql_where)
2250                         for row in cursor:
2251                                 SongList.append((Item(mode = 99, songID = row[0], title = row[1], artist = row[2], filename = row[3], artistID = row[4], bitrate = row[5], length = row[6], genre = row[7], track = row[8], date = row[9], album = row[10], albumID = row[11]),))
2252                         cursor.close() 
2253                         connection.close()
2254                         self["list"].setList(SongList)
2255                         if len(SongList) > 1:
2256                                 self["list"].moveToIndex(1)
2257
2258         
2259         def buildArtistSongList(self, artistID, mode, addToCache):
2260                 if addToCache:
2261                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2262                 arguments = {}
2263                 arguments["artistID"] = artistID
2264                 arguments["mode"] = mode
2265                 arguments["addToCache"] = False
2266                 self.LastMethod = MethodArguments(method = self.buildArtistSongList, arguments = arguments)
2267                 connection = OpenDatabase()
2268                 if connection is not None:
2269                         connection.text_factory = str
2270                         cursor = connection.cursor()
2271                         artistSongList = []
2272                         artistSongList.append((Item(text = _("[back]"), mode = mode, navigator = True),))
2273                         cursor.execute("select song_id, title, artists.artist, filename, bitrate, length, genre_text, track, date, album_text, songs.Album_id from songs inner join artists on songs.artist_id = artists.artist_id inner join Album on songs.Album_id = Album.Album_id inner join genre on songs.genre_id = genre.genre_id where songs.artist_id = %d order by Album.album_text, tracknumber, filename;" % (artistID))
2274                         for row in cursor:
2275                                 artistSongList.append((Item(mode = 99, songID = row[0], title = row[1], artist = row[2], filename = row[3], bitrate = row[4], length = row[5], genre = row[6], track = row[7], date = row[8], album = row[9], albumID = row[10], artistID = artistID),))
2276                         cursor.execute("SELECT artist from artists where artist_ID = %d;" % artistID)
2277                         row = cursor.fetchone()
2278                         self["headertext"].setText(_("Artist (%s) -> Song List") % row[0])
2279                         cursor.close() 
2280                         connection.close()
2281                         self["list"].setList(artistSongList)
2282                         if len(artistSongList) > 1:
2283                                 self["list"].moveToIndex(1)
2284                         
2285         def buildAlbumSongList(self, albumID, mode, addToCache):
2286                 if addToCache:
2287                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2288                 arguments = {}
2289                 arguments["albumID"] = albumID
2290                 arguments["mode"] = mode
2291                 arguments["addToCache"] = False
2292                 self.LastMethod = MethodArguments(method = self.buildAlbumSongList, arguments = arguments)
2293                 connection = OpenDatabase()
2294                 if connection is not None:
2295                         connection.text_factory = str
2296                         cursor = connection.cursor()
2297                         albumSongList = []
2298                         albumSongList.append((Item(text = _("[back]"), mode = mode, navigator = True),))
2299                         cursor.execute("select song_id, title, artists.artist, filename, songs.artist_id, bitrate, length, genre_text, track, date, album_text from songs inner join artists on songs.artist_id = artists.artist_id inner join Album on songs.Album_id = Album.Album_id inner join genre on songs.genre_id = genre.genre_id where songs.album_id = %d order by tracknumber, filename;" % (albumID))
2300                         for row in cursor:
2301                                 albumSongList.append((Item(mode = 99, songID = row[0], title = row[1], artist = row[2], filename = row[3], artistID = row[4], bitrate = row[5], length = row[6], genre = row[7], track = row[8], date = row[9], album = row[10], albumID = albumID),))
2302                         cursor.execute("SELECT album_text from album where album_ID = %d;" % albumID)
2303                         row = cursor.fetchone()
2304                         self["headertext"].setText(_("Album (%s) -> Song List") % row[0])
2305                         cursor.close() 
2306                         connection.close()
2307                         self["list"].setList(albumSongList)
2308                         if len(albumSongList) > 1:
2309                                 self["list"].moveToIndex(1)
2310                 
2311         def buildMainMenuList(self, addToCache = True):
2312                 arguments = {}
2313                 arguments["addToCache"] = True
2314                 self.LastMethod = MethodArguments(method = self.buildMainMenuList, arguments = arguments)
2315                 self["headertext"].setText(_("iDream Main Menu"))
2316                 mainMenuList = []
2317                 connection = OpenDatabase()
2318                 if connection is not None:
2319                         connection.text_factory = str
2320                         cursor = connection.cursor()
2321                         # 1. Playlists
2322                         cursor.execute("SELECT COUNT (*) FROM playlists;")
2323                         row = cursor.fetchone()
2324                         mainMenuList.append((Item(text = _("Playlists (%d)") % row[0], mode = 1),))
2325                         # 2. Artists
2326                         cursor.execute("SELECT COUNT (*) FROM artists;")
2327                         row = cursor.fetchone()
2328                         mainMenuList.append((Item(text = _("Artists (%d)") % row[0], mode = 4),))
2329                         # 3. Albums
2330                         cursor.execute("SELECT COUNT (DISTINCT album_text) FROM album;")
2331                         row = cursor.fetchone()
2332                         mainMenuList.append((Item(text = _("Albums (%d)") % row[0], mode = 7),))
2333                         # 4. Songs
2334                         cursor.execute("SELECT COUNT (*) FROM songs;")
2335                         row = cursor.fetchone()
2336                         mainMenuList.append((Item(text = _("Songs (%d)") % row[0], mode = 10),))
2337                         # 5. Genres
2338                         cursor.execute("SELECT COUNT (*) FROM genre;")
2339                         row = cursor.fetchone()
2340                         mainMenuList.append((Item(text = _("Genres (%d)") % row[0], mode = 13),))
2341                         cursor.close()  
2342                         connection.close()
2343                         self["list"].setList(mainMenuList)
2344                         self["list"].moveToIndex(0)
2345                 
2346         def buildArtistList(self, addToCache):
2347                 if addToCache:
2348                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2349                 arguments = {}
2350                 arguments["addToCache"] = False
2351                 self.LastMethod = MethodArguments(method = self.buildArtistList, arguments = arguments)
2352                 self["headertext"].setText(_("Artists List"))
2353                 connection = OpenDatabase()
2354                 if connection is not None:
2355                         connection.text_factory = str
2356                         cursor = connection.cursor()
2357                         artistList = []
2358                         artistList.append((Item(text = _("[back]"), mode = 0, navigator = True),))
2359                         cursor.execute("SELECT artists.artist_id,artists.artist, count (distinct album.album_text) FROM songs INNER JOIN artists ON songs.artist_id = artists.artist_id inner join album on songs.album_id =  album.album_id GROUP BY songs.artist_id ORDER BY artists.artist;")
2360                         for row in cursor:
2361                                 artistList.append((Item(text = "%s (%d)" % (row[1], row[2]), mode = 5, artistID = row[0]),))
2362                         cursor.close() 
2363                         connection.close()
2364                         self["list"].setList(artistList)
2365                 
2366         def buildArtistAlbumList(self, ArtistID, addToCache):
2367                 if addToCache:
2368                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2369                 arguments = {}
2370                 arguments["ArtistID"] = ArtistID
2371                 arguments["addToCache"] = False
2372                 self.LastMethod = MethodArguments(method = self.buildArtistAlbumList, arguments = arguments)
2373                 connection = OpenDatabase()
2374                 if connection is not None:
2375                         connection.text_factory = str
2376                         cursor = connection.cursor()
2377                         albumArtistList = []
2378                         albumArtistList.append((Item(text = _("[back]"), mode = 4, navigator = True),))
2379                         cursor.execute("select Album.Album_id,Album.Album_text from songs inner join Album on songs.Album_id = Album.Album_id where songs.artist_id = %d group by songs.Album_id order by Album.Album_text;" % ArtistID)
2380                         for row in cursor:
2381                                 cursor2 = connection.cursor()
2382                                 cursor2.execute("select count(song_id) from songs where album_id = %d;" % row[0])
2383                                 row2 = cursor2.fetchone()
2384                                 albumArtistList.append((Item(text = "%s (%d)" % (row[1], row2[0]), mode = 6, albumID = row[0], artistID = ArtistID),))
2385                                 cursor2.close()
2386                         cursor.execute("SELECT artist from artists where artist_ID = %d;" % ArtistID)
2387                         row = cursor.fetchone()
2388                         self["headertext"].setText(_("Artist (%s) -> Album List") % row[0])
2389                         cursor.close() 
2390                         connection.close()
2391                         self["list"].setList(albumArtistList)
2392                         if len(albumArtistList) > 1:
2393                                 self["list"].moveToIndex(1)
2394                         
2395         def buildAlbumList(self, addToCache):
2396                 if addToCache:
2397                         self.cacheList.append(CacheList(index = self["list"].getCurrentIndex(), listview = self["list"].getList(), headertext = self["headertext"].getText(), methodarguments = self.LastMethod))
2398                 arguments = {}
2399                 arguments["addToCache"] = False
2400                 self.LastMethod = MethodArguments(method = self.buildAlbumList, arguments = arguments)
2401                 self["headertext"].setText(_("Albums List"))
2402                 connection = OpenDatabase()
2403                 if connection is not None:
2404                         connection.text_factory = str
2405                         cursor = connection.cursor()
2406                         albumList = []
2407                         albumList.append((Item(text = _("[back]"), mode = 0, navigator = True),))
2408                         cursor.execute("select Album.Album_id,Album.Album_text, count(*) from songs inner join Album on songs.Album_id = Album.Album_id group by songs.Album_id order by Album.Album_text;")
2409                         for row in cursor:
2410                                 albumList.append((Item(text = "%s (%d)" % (row[1], row[2]), mode = 8, albumID = row[0]),))
2411                         cursor.close() 
2412                         connection.close()
2413                         self["list"].setList(albumList)
2414                         if len(albumList) > 1:
2415                                 self["list"].moveToIndex(1)
2416                         
2417         def startRun(self):
2418                 if pathToDatabase.isRunning:
2419                         self.showScanner = eTimer()
2420                         self.showScanner.callback.append(self.showScannerCallback)
2421                         self.showScanner.start(0,1)
2422                 else:
2423                         if config.plugins.merlinmusicplayer.startlastsonglist.value:
2424                                 self.startPlayerTimer = eTimer()
2425                                 self.startPlayerTimer.callback.append(self.startPlayerTimerCallback)
2426                                 self.startPlayerTimer.start(0,1)
2427                         self.mode = 0
2428                         self["list"].setMode(self.mode)
2429                         self.buildMainMenuList()
2430
2431         def showScannerCallback(self):
2432                 self.session.openWithCallback(self.filesAdded, iDreamAddToDatabase,None)
2433
2434
2435         def startPlayerTimerCallback(self):
2436                 connection = OpenDatabase()
2437                 if connection is not None:
2438                         connection.text_factory = str
2439                         cursor = connection.cursor()
2440                         iDreamMode = False
2441                         SongList = []
2442                         cursor.execute("select song_id, filename, title, artist, album, genre, bitrate, length,  track, date, PTS from CurrentSongList;")
2443                         for row in cursor:
2444                                 SongList.append((Item(songID = row[0], text = os_path.basename(row[1]), filename = row[1], title = row[2], artist = row[3], album = row[4], genre = row[5],  bitrate = row[6], length = row[7], track = row[8], date = row[9], PTS = row[10], join = False),))
2445                                 if row[0] != 0:
2446                                         iDreamMode = True
2447                         cursor.close() 
2448                         connection.close()
2449                         if self.player is not None:
2450                                 self.player.doClose()
2451                                 self.player = None
2452                         self.startMerlinPlayerScreenTimer.stop()
2453                         count = len(SongList)
2454                         if count:
2455                                 # just to be sure, check the index , it's critical
2456                                 index = config.plugins.merlinmusicplayer.lastsonglistindex.value
2457                                 if index >= count:
2458                                         index = 0
2459                                 self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,SongList, index, iDreamMode, self.currentService, self.serviceList)
2460                                 self.session.execDialog(self.player)
2461
2462         def config(self):
2463                 self.startMerlinPlayerScreenTimer.stop()
2464                 self.session.openWithCallback(self.setupFinished, MerlinMusicPlayerSetup, True)
2465
2466         def setupFinished(self, result):
2467                 if result:
2468                         self.red_pressed()
2469
2470
2471         def stopPlayingAndAppendFileToSongList(self):
2472                 self.startMerlinPlayerScreenTimer.stop()
2473                 if self.player is not None:
2474                         self.player.doClose()
2475                         self.player = None
2476                 self.appendFileToSongList()     
2477                 self.startMerlinPlayerScreenTimer.start(START_MERLIN_PLAYER_SCREEN_TIMER_VALUE)
2478
2479         def appendFileToSongList(self):
2480                 SongList = []
2481                 playerAvailable =  self.player is not None and self.player.songList
2482                 sel = self.getCurrentSelection()
2483                 if sel:
2484                         if playerAvailable:
2485                                 self.player.songList.append((sel,))
2486                                 self.player.origSongList.append((sel,))
2487                         else:
2488                                 SongList.append((sel,))
2489                         if not playerAvailable:
2490                                 if self.player is not None:
2491                                         self.player.doClose()
2492                                         self.player = None
2493                                 self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,SongList, 0, True, self.currentService, self.serviceList)
2494                                 self.player.playSong(self.player.songList[self.player.currentIndex][0].filename)
2495                                 self.player["coverArt"].onShow()
2496                                 self.player.init = 1
2497                         else:
2498                                 self.player["nextTitle"].setText(self.player.getNextTitle())
2499                                 self.session.open(MessageBox, _("%s\nappended to songlist")%sel.title, type = MessageBox.TYPE_INFO,timeout = 3 )
2500
2501         def insertFileToSongList(self):
2502                 sel = self.getCurrentSelection()
2503                 if sel:
2504                         if self.player is not None and self.player.songList:
2505                                 index = self.player.currentIndex
2506                                 self.player.songList.insert(index+1,(sel,))
2507                                 self.player.origSongList.insert(index+1,(sel,))
2508                                 self.player["nextTitle"].setText(self.player.getNextTitle())
2509                                 self.session.open(MessageBox, _("%s\ninserted and will be played as next song")%sel.title, type = MessageBox.TYPE_INFO,timeout = 3 )
2510                         else:
2511                                 self.appendFileToSongList()
2512
2513         def Error(self, error = None):
2514                 if error is not None:
2515                         self["list"].hide()
2516                         self["statustext"].setText(str(error.getErrorMessage()))
2517                         
2518         def closing(self):
2519                 self.close()
2520                 
2521         def __onClose(self):
2522                 self.startMerlinPlayerScreenTimer.stop()
2523                 if self.player is not None:
2524                         self.player.closePlayer()
2525                         self.player.doClose()
2526                         self.player = None
2527                 if self.serviceList is None:
2528                         self.session.nav.playService(self.currentService)
2529                 else:
2530                         current = ServiceReference(self.serviceList.getCurrentSelection())
2531                         self.session.nav.playService(current.ref)
2532                 
2533
2534         def lcdUpdate(self):
2535                 self.startMerlinPlayerScreenTimer.start(START_MERLIN_PLAYER_SCREEN_TIMER_VALUE)
2536                 try:
2537                         count = self["list"].getItemCount()
2538                         index = self["list"].getCurrentIndex()
2539                         iDreamList = self["list"].getList()
2540                         self.summaries.setText(iDreamList[index][0].title or iDreamList[index][0].text,1)
2541                         # voheriges
2542                         index -= 1
2543                         if index < 0:
2544                                 index = count
2545                         self.summaries.setText(iDreamList[index][0].title or iDreamList[index][0].text,3)
2546                         # naechstes
2547                         index = self["list"].getCurrentIndex() + 1
2548                         if index > count:
2549                                 index = 0
2550                         self.summaries.setText(iDreamList[index][0].title or iDreamList[index][0].text,4)
2551                 except: pass
2552
2553         def createSummary(self):
2554                 return MerlinMusicPlayerLCDScreenText
2555
2556                 
2557 class iDreamList(GUIComponent, object):
2558         def buildEntry(self, item):
2559                 width = self.l.getItemSize().width()
2560                 res = [ None ]
2561                 if self.displaySongMode:
2562                         if item.navigator:
2563                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width , 20, 0, RT_HALIGN_CENTER|RT_VALIGN_CENTER, "%s" % item.text))
2564                         else:
2565                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width - 100 , 20, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "%s - %s" % (item.title, item.artist)))
2566                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, width - 100,3,100, 20, 1, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, "%s" % item.track))
2567                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 26,width -200, 18, 1, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "%s%s" % (item.album, item.date)))
2568                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, width -200, 26,200, 18, 1, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, "%s" % item.length))
2569                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 47,width -200, 18, 1, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "%s" % item.genre))
2570                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, width -200, 47,200, 18, 1, RT_HALIGN_RIGHT|RT_VALIGN_CENTER, "%s" % item.bitrate))
2571                 else:
2572                         if item.navigator:
2573                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width , 20, 0, RT_HALIGN_CENTER|RT_VALIGN_CENTER, "%s" % item.text))
2574                         else:
2575                                 if item.PTS is None:
2576                                         res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width , 20, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "%s" % item.text))
2577                                 else:
2578                                         res.append((eListboxPythonMultiContent.TYPE_TEXT, 0, 3, width , 20, 0, RT_HALIGN_LEFT|RT_VALIGN_CENTER, "%s" % item.title))
2579                 
2580                 return res
2581         
2582         def __init__(self):
2583                 GUIComponent.__init__(self)
2584                 self.l = eListboxPythonMultiContent()
2585                 self.l.setBuildFunc(self.buildEntry)
2586                 self.l.setFont(0, gFont("Regular", 20))
2587                 self.l.setFont(1, gFont("Regular", 16))
2588                 self.l.setItemHeight(22)
2589                 self.onSelectionChanged = [ ]
2590                 self.mode = 0
2591                 self.displaySongMode = False
2592                 self.list = []
2593                 self.itemCount = 0
2594
2595         def connectSelChanged(self, fnc):
2596                 if not fnc in self.onSelectionChanged:
2597                         self.onSelectionChanged.append(fnc)
2598
2599         def disconnectSelChanged(self, fnc):
2600                 if fnc in self.onSelectionChanged:
2601                         self.onSelectionChanged.remove(fnc)
2602
2603         def selectionChanged(self):
2604                 for x in self.onSelectionChanged:
2605                         x()
2606         
2607         def getCurrent(self):
2608                 cur = self.l.getCurrentSelection()
2609                 return cur and cur[0]
2610         
2611         GUI_WIDGET = eListbox
2612         
2613         def postWidgetCreate(self, instance):
2614                 instance.setContent(self.l)
2615                 instance.selectionChanged.get().append(self.selectionChanged)
2616
2617         def preWidgetRemove(self, instance):
2618                 instance.setContent(None)
2619                 instance.selectionChanged.get().remove(self.selectionChanged)
2620
2621         def moveToIndex(self, index):
2622                 self.instance.moveSelectionTo(index)
2623
2624         def getCurrentIndex(self):
2625                 return self.instance.getCurrentIndex()
2626
2627         currentIndex = property(getCurrentIndex, moveToIndex)
2628         currentSelection = property(getCurrent)
2629
2630         def setList(self, list):
2631                 self.list = list
2632                 self.l.setList(list)
2633                 self.itemCount = len(self.list) - 1
2634         
2635         def getItemCount(self):
2636                 return  self.itemCount
2637
2638         def getList(self):
2639                 return self.list
2640
2641         def removeItem(self, index):
2642                 del self.list[index]
2643                 self.l.entryRemoved(index)
2644
2645         def getDisplaySongMode(self):
2646                 return self.displaySongMode
2647                 
2648         def setMode(self, mode):
2649                 self.mode = mode
2650                 if mode == 2 or mode == 6 or mode == 8 or mode == 10 or mode == 18 or mode == 19 or mode == 14 or mode == 20:
2651                         self.displaySongMode = True
2652                         self.l.setItemHeight(68)
2653                 else:
2654                         self.displaySongMode = False
2655                         self.l.setItemHeight(22)
2656
2657
2658 class MerlinMediaPixmap(Pixmap):
2659         def __init__(self):
2660                 Pixmap.__init__(self)
2661                 self.coverArtFileName = ""
2662                 self.picload = ePicLoad()
2663                 self.picload.PictureData.get().append(self.paintCoverArtPixmapCB)
2664                 self.coverFileNames = ["folder.png", "folder.jpg", "cover.jpg", "cover.png", "coverArt.jpg"]
2665
2666         def applySkin(self, desktop, screen):
2667                 from Tools.LoadPixmap import LoadPixmap
2668                 noCoverFile = None
2669                 if self.skinAttributes is not None:
2670                         for (attrib, value) in self.skinAttributes:
2671                                 if attrib == "pixmap":
2672                                         noCoverFile = value
2673                                         break
2674                 if noCoverFile is None:
2675                         noCoverFile = resolveFilename(SCOPE_CURRENT_SKIN, "skin_default/no_coverArt.png")
2676                 self.noCoverPixmap = LoadPixmap(noCoverFile)
2677                 return Pixmap.applySkin(self, desktop, screen)
2678
2679         def onShow(self):
2680                 Pixmap.onShow(self)
2681                 sc = AVSwitch().getFramebufferScale()
2682                 self.picload.setPara((self.instance.size().width(), self.instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
2683
2684         def paintCoverArtPixmapCB(self, picInfo=None):
2685                 ptr = self.picload.getData()
2686                 if ptr != None:
2687                         self.instance.setPixmap(ptr.__deref__())
2688
2689         def updateCoverArt(self, path):
2690                 back = False
2691                 while not path.endswith("/"):
2692                         path = path[:-1]
2693                 new_coverArtFileName = None
2694                 for filename in self.coverFileNames:
2695                         if fileExists(path + filename):
2696                                 new_coverArtFileName = path + filename
2697                 if self.coverArtFileName != new_coverArtFileName:
2698                         if new_coverArtFileName:
2699                                 self.coverArtFileName = new_coverArtFileName
2700                                 print "[MerlinMusicPlayer] using cover from %s " % self.coverArtFileName
2701                                 self.picload.startDecode(self.coverArtFileName)
2702                                 back = True
2703                 else:
2704                         if new_coverArtFileName:
2705                                 back = True
2706                 return back
2707
2708         def showDefaultCover(self):
2709                 self.coverArtFileName = ""
2710                 self.instance.setPixmap(self.noCoverPixmap)
2711
2712         def showCoverFromFile(self, filename):
2713                 self.coverArtFileName = filename
2714                 self.picload.startDecode(self.coverArtFileName)
2715
2716         def embeddedCoverArt(self):
2717                 print "[embeddedCoverArt] found"
2718                 self.coverArtFileName = "/tmp/.id3coverart"
2719                 self.picload.startDecode(self.coverArtFileName)
2720
2721
2722 class SelectPath(Screen):
2723         skin = """<screen name="SelectPath" position="center,center" size="560,320" title="Select path">
2724                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
2725                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
2726                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
2727                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
2728                         <widget name="target" position="0,60" size="540,22" valign="center" font="Regular;22" />
2729                         <widget name="filelist" position="0,100" zPosition="1" size="560,220" scrollbarMode="showOnDemand"/>
2730                         <widget render="Label" source="key_red" position="0,0" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2731                         <widget render="Label" source="key_green" position="140,0" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2732                 </screen>"""
2733         def __init__(self, session, initDir):
2734                 Screen.__init__(self, session)
2735                 inhibitDirs = ["/bin", "/boot", "/dev", "/etc", "/lib", "/proc", "/sbin", "/sys", "/usr", "/var"]
2736                 inhibitMounts = []
2737                 self["filelist"] = FileList(initDir, showDirectories = True, showFiles = False, inhibitMounts = inhibitMounts, inhibitDirs = inhibitDirs)
2738                 self["target"] = Label()
2739                 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EPGSelectActions"],
2740                 {
2741                         "back": self.cancel,
2742                         "left": self.left,
2743                         "right": self.right,
2744                         "up": self.up,
2745                         "down": self.down,
2746                         "ok": self.ok,
2747                         "green": self.green,
2748                         "red": self.cancel
2749                         
2750                 }, -1)
2751                 self["key_red"] = StaticText(_("Cancel"))
2752                 self["key_green"] = StaticText(_("OK"))
2753
2754         def cancel(self):
2755                 self.close(None)
2756
2757         def green(self):
2758                 self.close(self["filelist"].getSelection()[0])
2759
2760         def up(self):
2761                 self["filelist"].up()
2762                 self.updateTarget()
2763
2764         def down(self):
2765                 self["filelist"].down()
2766                 self.updateTarget()
2767
2768         def left(self):
2769                 self["filelist"].pageUp()
2770                 self.updateTarget()
2771
2772         def right(self):
2773                 self["filelist"].pageDown()
2774                 self.updateTarget()
2775
2776         def ok(self):
2777                 if self["filelist"].canDescent():
2778                         self["filelist"].descent()
2779                         self.updateTarget()
2780
2781         def updateTarget(self):
2782                 currFolder = self["filelist"].getSelection()[0]
2783                 if currFolder is not None:
2784                         self["target"].setText(currFolder)
2785                 else:
2786                         self["target"].setText(_("Invalid Location"))
2787
2788
2789 class MerlinMusicPlayerLCDScreen(Screen):
2790         skin = """
2791                 <screen position="0,0" size="132,64">
2792                         <widget source="session.CurrentService" render="Label" position="4,0" size="132,12" valign="top" font="Regular;10" halign="center">
2793                                 <convert type="ServicePosition">Position,ShowHours</convert>
2794                         </widget>
2795                         <widget name="text1" position="4,14" size="132,35" halign="center" valign="top" font="Regular;14"/>
2796                         <widget name="text4" position="4,51" size="132,12" halign="center" valign="top" font="Regular;10"/>
2797                 </screen>"""
2798
2799         def __init__(self, session, parent):
2800                 Screen.__init__(self, session)
2801                 self["text1"] = Label()
2802                 self["text4"] = Label()
2803
2804         def setText(self, text, line):
2805                 if line == 1:
2806                         self["text1"].setText(text)
2807                 elif line == 4:
2808                         self["text4"].setText(text)
2809
2810 class MerlinMusicPlayerLCDScreenText(Screen):
2811         skin = """
2812                 <screen position="0,0" size="132,64">
2813                         <widget name="text3" position="4,0" size="132,14" font="Regular;10"/>
2814                         <widget name="text1" position="4,14" size="132,35" font="Regular;14"/>
2815                         <widget name="text4" position="4,49" size="132,14" font="Regular;10"/>
2816                 </screen>"""
2817
2818         def __init__(self, session, parent):
2819                 Screen.__init__(self, session)
2820                 self["text1"] = Label()
2821                 self["text3"] = Label()
2822                 self["text4"] = Label()
2823
2824         def setText(self, text, line):
2825                 textleer = "    "
2826                 text = text + textleer*10
2827                 if line == 1:
2828                         self["text1"].setText(text)
2829                 elif line == 3:
2830                         self["text3"].setText(text)
2831                 elif line == 4:
2832                         self["text4"].setText(text)
2833
2834
2835 class MerlinMusicPlayerSetup(Screen, ConfigListScreen):
2836
2837         sz_w = getDesktop(0).size().width()
2838         if sz_w == 1280:
2839                 skin = """
2840                         <screen position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="Merlin Music Player Setup" >
2841                                 <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmpborderHD.png" position="128,72" size="1024,576"/>
2842                                 <ePixmap position="178,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
2843                                 <ePixmap position="328,102" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
2844                                 <widget render="Label" source="key_red" position="178,102" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2845                                 <widget render="Label" source="key_green" position="328,102" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2846                                 <widget name="config" position="178,152" size="924,350" backgroundColor="#00000000" scrollbarMode="showOnDemand" />
2847                         </screen>"""
2848
2849         elif sz_w == 1024:
2850                 skin = """
2851                         <screen position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="Merlin Music Player Setup" >
2852                                 <ePixmap position="50,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
2853                                 <ePixmap position="200,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
2854                                 <widget render="Label" source="key_red" position="50,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2855                                 <widget render="Label" source="key_green" position="200,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2856                                 <widget name="config" position="50,80" size="924,350" backgroundColor="#00000000" scrollbarMode="showOnDemand" />
2857                         </screen>"""
2858         else:
2859                 skin = """
2860                         <screen position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="Merlin Music Player Setup">
2861                                 <ePixmap position="50,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
2862                                 <ePixmap position="200,30" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
2863                                 <widget render="Label" source="key_red" position="50,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2864                                 <widget render="Label" source="key_green" position="200,30" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
2865                                 <widget name="config" position="50,80" size="620,350" backgroundColor="#00000000" scrollbarMode="showOnDemand" />
2866                         </screen>"""
2867
2868
2869         def __init__(self, session, databasePath):
2870                 Screen.__init__(self, session)
2871
2872                 self["key_red"] = StaticText(_("Cancel"))
2873                 self["key_green"] = StaticText(_("OK"))
2874
2875                 self.list = [ ]
2876                 if HardwareInfo().get_device_name() != "dm7025":
2877                         self.list.append(getConfigListEntry(_("Use hardware-decoder for MP3"), config.plugins.merlinmusicplayer.hardwaredecoder))
2878                 self.list.append(getConfigListEntry(_("Play last used songlist after starting"), config.plugins.merlinmusicplayer.startlastsonglist))
2879                 if databasePath:
2880                         self.database = getConfigListEntry(_("iDream database path"), config.plugins.merlinmusicplayer.databasepath)
2881                         self.list.append(self.database)
2882                 else:
2883                         self.database = None
2884                 self.list.append(getConfigListEntry(_("Use google-images for cover art"), config.plugins.merlinmusicplayer.usegoogleimage))
2885                 self.googleimage = getConfigListEntry(_("Google image path"), config.plugins.merlinmusicplayer.googleimagepath)
2886                 self.list.append(self.googleimage)
2887                 self.list.append(getConfigListEntry(_("Activate screensaver"), config.plugins.merlinmusicplayer.usescreensaver))
2888                 self.list.append(getConfigListEntry(_("Wait for screensaver (in min)"), config.plugins.merlinmusicplayer.screensaverwait))
2889                 self.list.append(getConfigListEntry(_("Remember last path of filebrowser"), config.plugins.merlinmusicplayer.rememberlastfilebrowserpath))
2890                 self.defaultFileBrowserPath = getConfigListEntry(_("Filebrowser startup path"), config.plugins.merlinmusicplayer.defaultfilebrowserpath)
2891                 self.list.append(self.defaultFileBrowserPath)
2892                 self.list.append(getConfigListEntry(_("Show iDream in extended-pluginlist"), config.plugins.merlinmusicplayer.idreamextendedpluginlist))
2893                 self.list.append(getConfigListEntry(_("Show Merlin Music Player in extended-pluginlist"), config.plugins.merlinmusicplayer.merlinmusicplayerextendedpluginlist))
2894                 self.list.append(getConfigListEntry(_("Show iDream in mainmenu"), config.plugins.merlinmusicplayer.idreammainmenu))
2895                 self.list.append(getConfigListEntry(_("Show Merlin Music Player in mainmenu"), config.plugins.merlinmusicplayer.merlinmusicplayermainmenu))
2896
2897                 ConfigListScreen.__init__(self, self.list, session)
2898                 self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
2899                 {
2900                         "green": self.keySave,
2901                         "cancel": self.keyClose,
2902                         "ok": self.keySelect,
2903                 }, -2)
2904
2905         def keySelect(self):
2906                 cur = self["config"].getCurrent()
2907                 if cur == self.database:
2908                         self.session.openWithCallback(self.pathSelectedDatabase,SelectPath,config.plugins.merlinmusicplayer.databasepath.value)
2909                 elif cur == self.defaultFileBrowserPath:
2910                         self.session.openWithCallback(self.pathSelectedFilebrowser,SelectPath,config.plugins.merlinmusicplayer.defaultfilebrowserpath.value)
2911                 elif cur == self.googleimage:
2912                         self.session.openWithCallback(self.pathSelectedGoogleImage,SelectPath,config.plugins.merlinmusicplayer.googleimagepath.value)
2913
2914         def pathSelectedGoogleImage(self, res):
2915                 if res is not None:
2916                         config.plugins.merlinmusicplayer.googleimagepath.value = res
2917
2918         def pathSelectedDatabase(self, res):
2919                 if res is not None:
2920                         config.plugins.merlinmusicplayer.databasepath.value = res
2921
2922         def pathSelectedFilebrowser(self, res):
2923                 if res is not None:
2924                         config.plugins.merlinmusicplayer.defaultfilebrowserpath.value = res
2925
2926         def keySave(self):
2927                 for x in self["config"].list:
2928                         x[1].save()
2929                 configfile.save()
2930                 self.close(True)
2931
2932         def keyClose(self):
2933                 for x in self["config"].list:
2934                         x[1].cancel()
2935                 self.close(False)
2936
2937
2938
2939 class MerlinMusicPlayerFileList(Screen):
2940         
2941         sz_w = getDesktop(0).size().width()
2942         if sz_w == 1280:
2943                 skin = """
2944                         <screen name="MerlinMusicPlayerFileList" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
2945                         <ePixmap alphatest="on" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/MerlinMusicPlayer/images/mmpborderHD.png" position="128,72" size="1024,576"/>
2946                         <eLabel backgroundColor="#999999" position="178,112" size="924,2" zPosition="1"/>
2947                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="178,104" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>
2948                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="852,104" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
2949                         <widget name="headertext" position="178,145" zPosition="1" size="900,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
2950                         <widget name="list" position="178,182" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>                         
2951                         </screen>"""
2952         elif sz_w == 1024:
2953                 skin = """
2954                         <screen name="MerlinMusicPlayerFileList" position="0,0" size="1024,576" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
2955                         <eLabel backgroundColor="#999999" position="50,40" size="924,2" zPosition="1"/>
2956                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,32" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>
2957                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="724,32" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
2958                         <widget name="headertext" position="50,73" zPosition="1" size="900,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
2959                         <widget name="list" position="50,110" zPosition="2" size="940,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
2960                         </screen>"""
2961         else:
2962                 skin = """
2963                         <screen name="MerlinMusicPlayerFileList" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="#00000000" title="iDream">
2964                         <eLabel backgroundColor="#999999" position="50,50" size="620,2" zPosition="1"/>
2965                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="50,40" size="250,20" text="MERLIN  MUSIC  PLAYER" valign="center" zPosition="2"/>
2966                         <eLabel backgroundColor="#999999" font="Regular;16" foregroundColor="#0f0f0f" halign="center" position="420,40" size="250,20" text="WWW.DREAMBOX-TOOLS.INFO" valign="center" zPosition="2"/>
2967
2968                         <widget name="headertext" position="50,73" zPosition="1" size="620,23" font="Regular;20" transparent="1"  foregroundColor="#fcc000" backgroundColor="#00000000"/>
2969                         <widget name="list" position="50,110" zPosition="2" size="620,350" scrollbarMode="showOnDemand" transparent="0"  backgroundColor="#00000000"/>
2970                         </screen>"""
2971                 
2972         
2973         def __init__(self, session, servicelist):
2974                 self.session = session
2975                 Screen.__init__(self, session)
2976                 self["list"] = FileList(config.plugins.merlinmusicplayer.defaultfilebrowserpath.value, showDirectories = True, showFiles = True, matchingPattern = "(?i)^.*\.(mp3|m4a|flac|ogg|m3u|pls|cue)", useServiceRef = False)
2977
2978
2979                 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EPGSelectActions"],
2980                 {
2981                         "ok": self.ok,
2982                         "back": self.close,
2983                         "input_date_time": self.menu_pressed,
2984                         "info" : self.info_pressed,
2985                         "green": self.green_pressed,
2986                         "up": self.moveup,
2987                         "down": self.movedown,
2988                         "right": self.moveright,
2989                         "left" : self.moveleft,
2990                         "blue" : self.appendFileToSongList,
2991                         "yellow" : self.insertFileToSongList,
2992                         "red" : self.stopPlayingAndAppendFileToSongList,
2993                 }, -1)
2994                 self.serviceList = servicelist
2995                 self["headertext"] = Label()
2996                 self.player = None
2997                 self.onClose.append(self.__onClose)
2998                 self.onLayoutFinish.append(self.startRun)
2999                 self.onShown.append(self.updateTarget)
3000                 self.currentService = self.session.nav.getCurrentlyPlayingServiceReference()
3001                 self.session.nav.stopService()
3002
3003                 self.startMerlinPlayerScreenTimer = eTimer()
3004                 self.startMerlinPlayerScreenTimer.timeout.get().append(self.info_pressed)
3005
3006         def startRun(self):
3007                 if config.plugins.merlinmusicplayer.startlastsonglist.value:
3008                         self.startPlayerTimer = eTimer()
3009                         self.startPlayerTimer.callback.append(self.startPlayerTimerCallback)
3010                         self.startPlayerTimer.start(0,1)
3011
3012         def startPlayerTimerCallback(self):
3013                 connection = OpenDatabase()
3014                 if connection is not None:
3015                         connection.text_factory = str
3016                         cursor = connection.cursor()
3017                         iDreamMode = False
3018                         SongList = []
3019                         cursor.execute("select song_id, filename, title, artist, album, genre, bitrate, length,  track, date, PTS from CurrentSongList;")
3020                         for row in cursor:
3021                                 SongList.append((Item(songID = row[0], text = os_path.basename(row[1]), filename = row[1], title = row[2], artist = row[3], album = row[4], genre = row[5],  bitrate = row[6], length = row[7], track = row[8], date = row[9], PTS = row[10], join = False),))
3022                                 if row[0] != 0:
3023                                         iDreamMode = True
3024                         cursor.close() 
3025                         connection.close()
3026                         if self.player is not None:
3027                                 self.player.doClose()
3028                                 self.player = None
3029                         self.startMerlinPlayerScreenTimer.stop()
3030                         count = len(SongList)
3031                         if count:
3032                                 # just to be sure, check the index , it's critical
3033                                 index = config.plugins.merlinmusicplayer.lastsonglistindex.value
3034                                 if index >= count:
3035                                         index = 0
3036                                 self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,SongList, index, iDreamMode, self.currentService, self.serviceList)
3037                                 self.session.execDialog(self.player)
3038         
3039         def readCUE(self, filename):
3040                 SongList = []
3041                 displayname = None
3042                 try:
3043                         cuefile = open(filename, "r")
3044                 except IOError:
3045                         return None
3046                 import re
3047                 performer_re = re.compile(r"""PERFORMER "(?P<performer>.*?)"(?:=\r\n|\r|\n|$)""")
3048                 title_re = re.compile(r"""TITLE "(?P<title>.*?)"(?:=\r\n|\r|\n|$)""")
3049                 filename_re = re.compile(r"""FILE "(?P<filename>.+?)".*(?:=\r\n|\r|\n|$)""", re.DOTALL)
3050                 track_re = re.compile(r"""TRACK (?P<track_number>[^ ]+?)(?:[ ]+.*?)(?:=\r\n|\r|\n|$)""")
3051                 index_re = re.compile(r"""INDEX (?P<index_nr>[^ ]+?)[ ]+(?P<track_index>[^ ]+?)(?:=\r\n|\r|\n|$)""")
3052                 msts_re = re.compile("""^(?P<mins>[0-9]{1,}):(?P<secs>[0-9]{2}):(?P<ms>[0-9]{2})$""")
3053                 songfilename = ""
3054                 album = ""
3055                 performer = ""
3056                 title = ""
3057                 pts = 0
3058                 state = 0 # header
3059                 for line in cuefile.readlines():
3060                         entry = line.strip()
3061                         m = filename_re.search(entry)
3062                         if m:
3063                                 if  m.group('filename')[0] == "/":
3064                                         songfilename = m.group('filename')
3065                                 else:
3066                                         songfilename = os_path.join(os_path.dirname(filename), m.group('filename'))
3067                         m = title_re.search(entry)
3068                         if m:
3069                                 if state == 0:
3070                                         album = m.group('title')
3071                                 else:
3072                                         title = m.group('title')
3073                         m = performer_re.search(entry)
3074                         if m:
3075                                 performer = m.group('performer')
3076                         m = track_re.search(entry)
3077                         if m:
3078                                 state = 1 # tracks
3079                         m = index_re.search(entry)
3080                         if m:
3081                                 if int(m.group('index_nr')) == 1:
3082                                         m1 = msts_re.search(m.group('track_index'))
3083                                         if m1:
3084                                                 pts = (int(m1.group('mins')) * 60 + int(m1.group('secs'))) * 90000
3085                                                 SongList.append((Item(text = title, filename = songfilename, title = title, artist = performer, album = album,join = False, PTS = pts),))
3086                 cuefile.close()
3087                 return SongList
3088
3089         def readM3U(self, filename):
3090                 SongList = []
3091                 displayname = None
3092                 try:
3093                         m3ufile = open(filename, "r")
3094                 except IOError:
3095                         return None
3096                 for line in m3ufile.readlines():
3097                         entry = line.strip()
3098                         if entry != "":
3099                                 if entry.startswith("#EXTINF:"):
3100                                         extinf = entry.split(',',1)
3101                                         if len(extinf) > 1:
3102                                                 displayname = extinf[1]
3103                                 elif entry[0] != "#":
3104                                         if entry[0] == "/":
3105                                                 songfilename = entry
3106                                         else:
3107                                                 songfilename = os_path.join(os_path.dirname(filename),entry)
3108                                         if displayname:
3109                                                 text = displayname
3110                                                 displayname = None
3111                                         else:
3112                                                 text = entry
3113                                         SongList.append((Item(text = text, filename = songfilename),))
3114                 m3ufile.close()
3115                 return SongList
3116
3117         def readPLS(self, filename):
3118                 SongList = []
3119                 displayname = None
3120                 try:
3121                         plsfile = open(filename, "r")
3122                 except IOError:
3123                         return None
3124                 entry = plsfile.readline().strip()
3125                 if entry == "[playlist]":
3126                         while True:
3127                                 entry = plsfile.readline().strip()
3128                                 if entry == "":
3129                                         break
3130                                 if entry[0:4] == "File":
3131                                         pos = entry.find('=') + 1
3132                                         newentry = entry[pos:]
3133                                         SongList.append((Item(text = newentry, filename = newentry),))
3134                 else:
3135                         SongList = self.readM3U(filename)
3136                 plsfile.close()
3137                 return SongList
3138
3139         def green_pressed(self):
3140                 SongList = []
3141                 count = 0
3142                 for root, subFolders, files in os_walk(self["list"].getCurrentDirectory()):
3143                         files.sort()
3144                         for filename in files:
3145                                 if filename.lower().endswith(".mp3") or filename.lower().endswith(".flac") or filename.lower().endswith(".m4a") or filename.lower().endswith(".ogg"):
3146                                         SongList.append((Item(text = filename, filename = os_path.join(root,filename)),))
3147                 if self.player is not None:
3148                         self.player.doClose()
3149                         self.player = None
3150                 self.startMerlinPlayerScreenTimer.stop()
3151                 count = len(SongList)
3152                 if count:
3153                         self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,SongList, 0, False, self.currentService, self.serviceList)
3154                         self.session.execDialog(self.player)
3155                 else:
3156                         self.session.open(MessageBox, _("No music files found!"), type = MessageBox.TYPE_INFO,timeout = 20 )
3157
3158         def ok(self):
3159                 if self["list"].canDescent():
3160                         self["list"].descent()
3161                         self.updateTarget()
3162                 else:
3163                         SongList = []
3164                         foundIndex = 0
3165                         count = 0
3166                         index = 0
3167                         currentFilename = self["list"].getFilename()
3168                         if currentFilename.lower().endswith(".m3u"):
3169                                 SongList = self.readM3U(os_path.join(self["list"].getCurrentDirectory(),currentFilename))
3170                         elif currentFilename.lower().endswith(".pls"):
3171                                 SongList = self.readPLS(os_path.join(self["list"].getCurrentDirectory(),currentFilename))
3172                         elif currentFilename.lower().endswith(".cue"):
3173                                 SongList = self.readCUE(os_path.join(self["list"].getCurrentDirectory(),currentFilename))
3174                         else:
3175                                 files = os_listdir(self["list"].getCurrentDirectory())
3176                                 files.sort()
3177                                 for filename in files:
3178                                         if filename.lower().endswith(".mp3") or filename.lower().endswith(".flac") or filename.lower().endswith(".m4a") or filename.lower().endswith(".ogg"):
3179                                                 SongList.append((Item(text = filename, filename = os_path.join(self["list"].getCurrentDirectory(),filename)),))
3180                                                 if self["list"].getFilename() == filename:
3181                                                         foundIndex = index
3182                                                 index += 1
3183
3184                         if self.player is not None:
3185                                 self.player.doClose()
3186                                 self.player = None
3187                         self.startMerlinPlayerScreenTimer.stop()
3188                         count = len(SongList)
3189                         if count:
3190                                 self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,SongList, foundIndex, False, self.currentService, self.serviceList)
3191                                 self.session.execDialog(self.player)
3192                         else:
3193                                 self.session.open(MessageBox, _("No music files found!"), type = MessageBox.TYPE_INFO,timeout = 20 )
3194
3195         def config(self):
3196                 self.startMerlinPlayerScreenTimer.stop()
3197                 self.session.open(MerlinMusicPlayerSetup, True)
3198
3199         def menu_pressed(self):
3200                 self.startMerlinPlayerScreenTimer.stop()
3201                 options = [(_("Configuration"), self.config),]
3202                 if not self["list"].canDescent():
3203                         filename = self["list"].getFilename()
3204                         if filename.lower().endswith(".mp3") or filename.lower().endswith(".flac") or filename.lower().endswith(".m4a") or filename.lower().endswith(".ogg"):
3205                                 options.extend(((_("Clear current songlist and play selected entry"), self.stopPlayingAndAppendFileToSongList),))
3206                                 options.extend(((_("Append file to current songlist"), self.appendFileToSongList),))
3207                                 if self.player is not None and self.player.songList:
3208                                         options.extend(((_("Insert file to current songlist and play next"), self.insertFileToSongList),))
3209                 self.session.openWithCallback(self.menuCallback, ChoiceBox,list = options)
3210
3211         def menuCallback(self, ret):
3212                 ret and ret[1]()
3213
3214         def stopPlayingAndAppendFileToSongList(self):
3215                 self.startMerlinPlayerScreenTimer.stop()
3216                 if self.player is not None:
3217                         self.player.doClose()
3218                         self.player = None
3219                 self.appendFileToSongList()     
3220                 self.startMerlinPlayerScreenTimer.start(START_MERLIN_PLAYER_SCREEN_TIMER_VALUE)
3221
3222         def appendFileToSongList(self):
3223                 playerAvailable =  self.player is not None and self.player.songList
3224                 filename = self["list"].getFilename()
3225                 if filename.lower().endswith(".mp3") or filename.lower().endswith(".flac") or filename.lower().endswith(".m4a") or filename.lower().endswith(".ogg"):
3226                         SongList = []
3227                         a = Item(text = filename, filename = os_path.join(self["list"].getCurrentDirectory(),filename))
3228                         if playerAvailable:
3229                                 self.player.songList.append((a,))
3230                                 self.player.origSongList.append((a,))
3231                         else:
3232                                 SongList.append((a,))
3233                         if not playerAvailable:
3234                                 if self.player is not None:
3235                                         self.player.doClose()
3236                                         self.player = None
3237                                 self.player = self.session.instantiateDialog(MerlinMusicPlayerScreen,SongList, 0, False, self.currentService, self.serviceList)
3238                                 self.player.playSong(self.player.songList[self.player.currentIndex][0].filename)
3239                                 self.player["coverArt"].onShow()
3240                                 self.player.init = 1
3241                         else:
3242                                 self.player["nextTitle"].setText(self.player.getNextTitle())
3243                                 self.session.open(MessageBox, _("%s\nappended to songlist")%a.text, type = MessageBox.TYPE_INFO,timeout = 3 )
3244
3245         def insertFileToSongList(self):
3246                 if self.player is not None and self.player.songList:
3247                         index = self.player.currentIndex
3248                         filename = self["list"].getFilename()
3249                         if filename.lower().endswith(".mp3") or filename.lower().endswith(".flac") or filename.lower().endswith(".m4a") or filename.lower().endswith(".ogg"):
3250                                 a = Item(text = filename, filename = os_path.join(self["list"].getCurrentDirectory(),filename))
3251                                 self.player.songList.insert(index+1,(a,))
3252                                 self.player.origSongList.insert(index+1,(a,))
3253                                 self.player["nextTitle"].setText(self.player.getNextTitle())
3254                                 self.session.open(MessageBox, _("%s\ninserted and will be played as next song")%a.text, type = MessageBox.TYPE_INFO,timeout = 3 )
3255                 else:
3256                         self.appendFileToSongList()
3257
3258         def info_pressed(self):
3259                 self.startMerlinPlayerScreenTimer.stop()
3260                 if self.player is not None:
3261                         if self.player.songList:
3262                                 self.session.execDialog(self.player)
3263
3264         def moveright(self):
3265                 self["list"].pageDown()
3266                 self.lcdupdate()
3267
3268         def moveleft(self):
3269                 self["list"].pageUp()
3270                 self.lcdupdate()
3271                 
3272         def moveup(self):
3273                 self["list"].up()
3274                 self.lcdupdate()
3275
3276         def movedown(self):
3277                 self["list"].down()
3278                 self.lcdupdate()
3279
3280         def updateTarget(self):
3281                 currFolder = self["list"].getCurrentDirectory()
3282                 if currFolder is None:
3283                         currFolder = ("Invalid Location")
3284                 self["headertext"].setText(_("Filelist: %s") % currFolder)
3285                 self.lcdupdate()
3286
3287         def lcdupdate(self):
3288                 self.startMerlinPlayerScreenTimer.start(START_MERLIN_PLAYER_SCREEN_TIMER_VALUE)
3289                 index = self["list"].getSelectionIndex()
3290                 sel = self["list"].list[index]
3291                 text = sel[1][7]
3292                 if sel[0][1] == True:
3293                         text = "/" + text
3294                 self.summaries.setText(text,1)
3295                 # voheriges
3296                 index -= 1
3297                 if index < 0:
3298                         index = len(self["list"].list) -1
3299                 sel = self["list"].list[index]
3300                 text = sel[1][7]
3301                 if sel[0][1] == True:
3302                         text = "/" + text
3303                 self.summaries.setText(text,3)
3304                 # naechstes
3305                 index = self["list"].getSelectionIndex() + 1
3306                 if index > (len(self["list"].list) -1):         
3307                         index = 0
3308                 sel = self["list"].list[index]
3309                 text = sel[1][7]
3310                 if sel[0][1] == True:
3311                         text = "/" + text
3312                 self.summaries.setText(text,4)
3313
3314         def __onClose(self):
3315                 self.startMerlinPlayerScreenTimer.stop()
3316                 if self.player is not None:
3317                         self.player.closePlayer()
3318                         self.player.doClose()
3319                         self.player = None
3320                 if self.serviceList is None:
3321                         self.session.nav.playService(self.currentService)
3322                 else:
3323                         current = ServiceReference(self.serviceList.getCurrentSelection())
3324                         self.session.nav.playService(current.ref)
3325                 if config.plugins.merlinmusicplayer.rememberlastfilebrowserpath.value:
3326                         try:
3327                                 config.plugins.merlinmusicplayer.defaultfilebrowserpath.value = self["list"].getCurrentDirectory()
3328                                 config.plugins.merlinmusicplayer.defaultfilebrowserpath.save()
3329                         except:
3330                                 pass
3331
3332         def createSummary(self):
3333                 return MerlinMusicPlayerLCDScreenText
3334
3335 def main(session,**kwargs):
3336         if kwargs.has_key("servicelist"):
3337                 servicelist = kwargs["servicelist"]
3338         else:
3339                 servicelist = None
3340         session.open(iDreamMerlin, servicelist)
3341
3342 def merlinmusicplayerfilelist(session,**kwargs):
3343         if kwargs.has_key("servicelist"):
3344                 servicelist = kwargs["servicelist"]
3345         else:
3346                 servicelist = None
3347         session.open(MerlinMusicPlayerFileList, servicelist)
3348
3349 def menu_merlinmusicplayerfilelist(menuid, **kwargs):
3350         if menuid == "mainmenu":
3351                 return [(_("Merlin Music Player"), merlinmusicplayerfilelist, "merlin_music_player", 46)]
3352         return []
3353
3354 def menu_idream(menuid, **kwargs):
3355         if menuid == "mainmenu":
3356                 return [(_("iDream"), main, "idream", 47)]
3357         return []
3358
3359 def Plugins(**kwargs):
3360
3361         list = [PluginDescriptor(name="Merlin iDream", description=_("Dreambox Music Database"), where = [PluginDescriptor.WHERE_PLUGINMENU], icon = "iDream.png", fnc=main)]
3362         list.append(PluginDescriptor(name="Merlin Music Player", description=_("Merlin Music Player"), where = [PluginDescriptor.WHERE_PLUGINMENU], icon = "MerlinMusicPlayer.png", fnc=merlinmusicplayerfilelist))
3363         if config.plugins.merlinmusicplayer.idreamextendedpluginlist.value:
3364                 list.append(PluginDescriptor(name="iDream", description=_("Dreambox Music Database"), where = [PluginDescriptor.WHERE_EXTENSIONSMENU], fnc=main))
3365         if config.plugins.merlinmusicplayer.merlinmusicplayerextendedpluginlist.value:
3366                 list.append(PluginDescriptor(name="Merlin Music Player", description=_("Merlin Music Player"), where = [PluginDescriptor.WHERE_EXTENSIONSMENU], fnc=merlinmusicplayerfilelist))
3367         if config.plugins.merlinmusicplayer.merlinmusicplayermainmenu.value:
3368                 list.append(PluginDescriptor(name="Merlin Music Player", description=_("Merlin Music Player"), where = [PluginDescriptor.WHERE_MENU], fnc=menu_merlinmusicplayerfilelist))
3369         if config.plugins.merlinmusicplayer.idreammainmenu.value:
3370                 list.append(PluginDescriptor(name="iDream", description=_("iDream"), where = [PluginDescriptor.WHERE_MENU], fnc=menu_idream))
3371         return list
3372