Пример #1
0
    def check_auth(self, username, password):
        """
        check user and password in redis db
        :param username:
        :param password:
        :return:
        """
        userdb = CombaUser()

        if userdb.hasPassword(username, password):
            return userdb.getUser(username)
        else:
            return False
Пример #2
0
 def __init__(self, sender, lqs_socket, lqs_recsocket):
     """
     Constructor
     @type    sender: object
     @param   sender: Der Communicator Adapter - z-B. zmq
     @type    lqs_socket: string 
     @param   lqs_socket: Liquidsoap Player Socket
     @type    lqs_recsocket: string
     @param   lqs_recsocket: Liquidsoap Recorder Socket 
     """
     # Der Liquidsoap Client
     self.lqc = LiquidsoapClient(lqs_socket)
     self.lqcr = LiquidsoapClient(lqs_recsocket)
     # Felder die Liquidsoap fuer einen Track (rid) zurueckliefert
     self.knownfields = ["status", "album","time","title","artist","comment","filename","on_air","source","rid", "genre"]  
     self.lq_error = ''
     self.sender = sender
     self.is_intern = False
     self.messenger = CombaMessenger()
     self.messenger.setChannel('controller')
     self.messenger.setSection('execjob')
     self.userdb = CombaUser()
     self.job_result = ['', '', '', '','', '']
     errors_file = os.path.dirname(os.path.realpath(__file__)) + '/error/combac_error.js'
     json_data = open(errors_file)
     self.errorData = simplejson.load(json_data)
Пример #3
0
class CombaController(object):
    
    # Constructor
    def __init__(self, sender, lqs_socket, lqs_recsocket):
        """
        Constructor
        @type    sender: object
        @param   sender: Der Communicator Adapter - z-B. zmq
        @type    lqs_socket: string 
        @param   lqs_socket: Liquidsoap Player Socket
        @type    lqs_recsocket: string
        @param   lqs_recsocket: Liquidsoap Recorder Socket 
        """
        # Der Liquidsoap Client
        self.lqc = LiquidsoapClient(lqs_socket)
        self.lqcr = LiquidsoapClient(lqs_recsocket)
        # Felder die Liquidsoap fuer einen Track (rid) zurueckliefert
        self.knownfields = ["status", "album","time","title","artist","comment","filename","on_air","source","rid", "genre"]  
        self.lq_error = ''
        self.sender = sender
        self.is_intern = False
        self.messenger = CombaMessenger()
        self.messenger.setChannel('controller')
        self.messenger.setSection('execjob')
        self.userdb = CombaUser()
        self.job_result = ['', '', '', '','', '']
        errors_file = os.path.dirname(os.path.realpath(__file__)) + '/error/combac_error.js'
        json_data = open(errors_file)
        self.errorData = simplejson.load(json_data)

    #------------------------------------------------------------------------------------------#
    def message(self, message, log=False, warning=False):
        """
        Daten an einen Client senden oder bei einer internen Aktion loggen
        @type     message: string
        @param    message: String, der gesendet wird
        @type     log: boolean
        @param    log: Wenn falsch, wird die message an den Client gesendet
        @type     warning: boolean
        @param    warning: Wenn falsch, ist der logging typ info, andernfalls warning
        @rtype:   string/None
        @return:  Die Message, falls log false ist
        """
        if not self.is_intern:
            self.sender.send(message)
        else:
            return message
        if log: 
            if warning:
                    logging.warning(message) 
            else:     
                logging.info(message) 

    #------------------------------------------------------------------------------------------#
    def allData(self):
        """
        Gibt Metadaten aller Kanäle als JSON-String an den Client zurück 
        @rtype:   string/None
        @return:  Die Antwort des Liquidsoap-Servers

        """        
        channels = self.sendLqcCommand(self.lqc, 'listChannels')
        
        if not isinstance(channels, list):
            self.warning('01')
            self.notifyClient()
            return 
        
        data = {}
        pdata = {}
                      
        try:
            self.is_intern = True  
            playlist_data = simplejson.loads(self.playlist_data(True))
            self.is_intern = False
        except:
            self.warning('01')            
            self.notifyClient()
            return
                    
        # Status des Playlistkanals abfragen
        status = self.sendLqcCommand(self.lqc, 'status', 'mixer', '0')
        
        states = status.split(' ')
        state_data = {}
        
        # Die Stati in python dicts einlesen
        for state in states:
            item = state.split('=')
            try:
                state_data[item[0]] = item[1]
            except:
                self.warning('01')
                self.notifyClient()
                return
        
        remaining = self.sendLqcCommand(self.lqc, 'playlist_remaining')
        state_data['remaining'] = remaining
        # Die Metadaten der Playlist
        pdata['state'] = state_data
        pdata['tracks'] = playlist_data        
        data['playlist'] = pdata
        
        # Servermeldungen abschalten
        self.is_intern = True                
        # die channel queues einlesen
        
        for channel in channels:
            data[channel] = self.channel_queue(channel, True)        
        # Servermeldungen einschalten
        self.is_intern = False
        self.success('00', data)
        self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def ping(self):
        """
        dem Client antworten
        """
        return self.message('OK')

    #------------------------------------------------------------------------------------------#
    def channel_insert(self, channel, uri, pos):
        """
        Track in einen Channel einfuegen 
        @type     channel: string
        @param    channel: Kanal
        @type     uri:     string
        @param    uri:     Uri - z.B. file:///my/audio/mp3 
        @type     pos:     int
        @param    pos:     Die Position an der eingefügt werden soll        
        @rtype:   string/None
        @return:  Die Antwort des Liquidsoap-Servers                
        """
        message = self.sendLqcCommand(self.lqc, 'insert', uri, pos, channel)
        message = message.strip()
        
        try:
            if int(message) > -1:                
                self.success()
                return self.message(message)        
        except:
            self.warning('01')
            self.notifyClient()                    

    #------------------------------------------------------------------------------------------#
    def channel_move(self, channel, fromPos, toPos):        
        """
        Channel-Eintrag von Position fromPos nach Position toPos verschieben 
        @type     channel: string
        @param    channel: Kanal
        @type     fromPos: int
        @param    fromPos: die Position des Eintrags, der verschoben wird 
        @type     toPos:   int
        @param    toPos:   Zielposition             
        @rtype:   string
        @return:  Die Antwort des Liquidsoap-Servers           
        """

        message = self.sendLqcCommand(self.lqc, 'get_queue', channel,'secondary_queue')

        rids = message.strip().split(' ')
        
        try:
            rid = rids[int(fromPos)-1]
        except:
            self.warning('01')
            self.notifyClient()
            return
        try:
            target = rids[int(toPos)-1]
        except:
            self.warning('01') 
            self.notifyClient()  
            return
            
        if rids[int(fromPos)-1] == rids[int(toPos)-1]:
            self.warning('02')
            self.notifyClient()
            return
        
        message = self.sendLqcCommand(self.lqc, 'move', rid, str(int(toPos)-1), channel)        
        message = message.strip()

        if message.strip().find('OK') > -1:
                self.success()                                
                self.notifyClient()
                return        
        else:
            self.warning('03')            
            self.notifyClient()                

    #------------------------------------------------------------------------------------------#
    def channel_off(self, channel):
        """
        Channel deaktivieren 
        @type     channel: string
        @param    channel: Kanal
        @rtype:   string
        @return:  Die Antwort des Liquidsoap-Servers        
        """        
        # internal channel name for playlist is 'common'
        if channel == 'playlist':
            channel = 'common'

        channels = self.sendLqcCommand(self.lqc, 'listChannels', False)

        index = channels.index(channel)            
        message = self.sendLqcCommand(self.lqc, 'deactivate', str(index))        
        if message.find('selected=false'):
            self.success()            
        else:
            self.warning('01')
        
        self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def channel_on(self, channel):
        """
        Channel aktivieren 
        @type     channel: string
        @param    channel: Kanal
        @rtype:   string
        @return:  Die Antwort des Liquidsoap-Servers               
        """                
        # Find channels
        if channel == 'playlist':
            channel = 'common'
        
        channels = self.sendLqcCommand(self.lqc, 'listChannels', False)
        
        index = channels.index(channel)        
        #a activate channel    
        message = self.sendLqcCommand(self.lqc, 'activate', str(index))        
        
        if message.find('selected=true'):
            self.success()
        else:
            self.warning('01')
        
        self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def channel_queue(self, channel, raw=False):
        """
        Channel Queue abrufen 
        @type     channel: string
        @param    channel: Kanal
        @type     raw:     boolean
        @param    raw:     Wenn true, Rückgabe als Python dict Object, andernfalls als JSON-String
        @rtype:   string/dict
        @return:  Der Channel Queue               
        """        
        data = {}
        
        # queue will return request id's (rids)
        
        message = self.sendLqcCommand(self.lqc, 'get_queue', channel)
              
        rids = message.strip().split(' ')
        data['tracks'] = []               
        for rid in rids:
            if rid != '':
                # get each rids metadata
                metadata = self.sendLqcCommand(self.lqc, 'getMetadata', rid)
                track = self._metadata_format(metadata)
                if not track.has_key('title'):
                    if track.has_key('location'):
                        track['title'] = os.path.basename(track['location'])
                    elif track.has_key('filename'):
                        track['title'] = os.path.basename(track['filename'])
                    else:
                        track['title'] = 'unknown' 
                        
                data['tracks'].extend([track])
        channels = self.sendLqcCommand(self.lqc, 'listChannels')   
        
        """
        now get channels state 
        self.lqc.status: ready=false volume=100% single=false selected=false remaining=0.00
        """        
        try:
            index = channels.index(channel)           
            status = self.sendLqcCommand(self.lqc, 'status', 'mixer', str(index + 1))            
            states = status.split(' ')            
            state_data = {}
            for state in states:
                item = state.split('=')
                if len(item) > 1:
                    state_data[item[0]] = item[1]
        except:
            state_data = {}
            self.error('01')
            self.notifyClient()
            return 
            
         
        data['state'] = state_data
        
        if raw:
            # return the list internal
            data['state'] = state_data            
            return data
        else:
            self.success('00', data)
            self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def channel_remove(self, channel, pos):
        """
        Channel-Eintrag löschen 
        @type     channel: string
        @param    channel: Kanal
        @type     pos:     int
        @param    pos:     Position des Eintrags                      
        """               
        # Es kann nur vom Secondary Queue gelöscht werden
        # Falls der Track im Primary Queue gelöscht werden soll, ist ein skip nötg  

        message = self.sendLqcCommand(self.lqc, 'get_queue', channel, 'secondary_queue')        
        rids = message.strip().split(' ')
        try:
            rid = rids[int(pos)-1]
        except:
            self.warning('02')
            self.notifyClient()
            return
        message = self.sendLqcCommand(self.lqc, 'remove', rid, channel)
        if message.find('OK') > -1:
            self.success()
        else:
            self.warning('01')

        self.notifyClient()          

    #------------------------------------------------------------------------------------------#
    def channel_seek(self, channel, duration):
        """
        Im aktuell spielenden Track auf dem Kanal <channel> <duration> Sekunden "vorspulen"
        @type     channel:  string
        @param    channel:  Kanal
        @type     duration: int
        @param    duration: Dauer in Sekunden               
        """                
        # Liquidsoap Kommando        
        data = self.sendLqcCommand(self.lqc, 'seek', duration, channel)
                
        # Resultate prüfen
        if self._check_result(data):        
                self.success('00', self.lq_error['value'])
        else:    
            self.warning('01')
        
        self.notifyClient()                        

    #------------------------------------------------------------------------------------------#
    def channel_skip(self, channel):
        """
        Kanal skippen 
        @type     channel:  string
        @param    channel:  Kanal      
        """                        
        # Liquidsoap Kommando
        channels = self.sendLqcCommand(self.lqc, 'listChannels')

        foundChannel = ''
        if not isinstance(channels, list):
            self.error('02')    
        else:        
            for index, item in enumerate(channels):
                if item == channel:
                    foundChannel = self.sendLqcCommand(self.lqc, 'skip', 'mixer', str(index + 1))
                    break
               
            if foundChannel.strip().find('OK') > -1:
                self.success()
            elif len(channels) < 1:
                self.warning('01')            
            else:
                self.error('03')                                
        
        self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def channel_volume(self, channel, volume):
        """
        Lautstärke auf Kanal <channel> setzen
        @type     channel:  string
        @param    channel:  Kanal
        @type     volume:   int
        @param    volume:  Lautstärke von 1-100               
        """        
                
        if channel == 'playlist':
            channel = 'common'
        # Liquidsoap Kommando
        channels = self.sendLqcCommand(self.lqc, 'listChannels', False)
                
        try: 
            index = channels.index(channel)
            if len(channel) < 1:
                self.warning('02')
        except:
            self.error('03')
            
        else:
            message = self.sendLqcCommand(self.lqc, 'volume', str(index), str(int(volume)))

            if message.find('volume=' + str(volume) + '%'):
                self.success('01', str(volume))
            else:
                self.warning('01')
        
        self.notifyClient()                 

    #------------------------------------------------------------------------------------------#
    def currentData(self):
        """
        Metadaten des gespielten Tracks im JSON-Format
        Beispiel: {"title": "Deserted Cities of the Heart", "filename": "/home/michel/Nas-audio/cream/the_very_best_of/17_Deserted_Cities_of_the_Heart.mp3", "source": "ch2", "on_air": "2014/07/23 23:46:37",  "rid": "2"}               
        """          
        # Liquidsoap Kommando
        message = self.sendLqcCommand(self.lqc, 'currentTrack')      
        
        rid = message.strip()        
        
        metadata = self.sendLqcCommand(self.lqc, 'getMetadata', rid)                    

        data = self._metadata_format(metadata)
        
        if data:
            self.success('00', simplejson.dumps(data))
        elif rid == '':
            self.warning('01')
        else:
            self.warning('02', rid)
        
        self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def get_channel_state(self, channel):        
        if channel == 'playlist':
            channel = 'common'
            
        channels = self.sendLqcCommand(self.lqc, 'listChannels', False)

        index = channels.index(channel)        
        state_data = {}
        try:
            index = channels.index(channel)           
            status = self.sendLqcCommand(self.lqc, 'status', 'mixer', str(index + 1))            
            states = status.split(' ')                        
            for state in states:
                item = state.split('=')
                if len(item) > 1:
                    state_data[item[0]] = item[1]
        except:
            state_data = {}
            self.error('01')
            self.notifyClient()
            return 
        self.success('00', simplejson.dumps(state_data))        
        self.notifyClient()                    

    #------------------------------------------------------------------------------------------#
    def help(self):        
        """
        Gibt die Hilfe aus                 
        """
        errNum = '11'
        try:
            file = open(os.path.dirname(os.path.abspath(__file__)) +  '/doc/comba.hlp', 'r')
            doc = file.read()
            return self.message(doc)
        except:
            self.warning('01')
            self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def listChannels(self):
        """
        Channels auflisten (Simple JSON)                      
        """           
        # Liquidsoap Kommando
        channels = self.sendLqcCommand(self.lqc, 'listChannels')      
        
        if not isinstance(channels, list):
            self.error('02')
        elif len(channels) < 1:            
            self.warning('01')
        else:
            self.success('00', channels)
        
        self.notifyClient()      

    #------------------------------------------------------------------------------------------#
    def playlist_data(self, raw=False):
        """
        Aktuelle Playlist Daten im JSON-Format                  
        """
        
        # Liquidsoap Kommando
        data = self.sendLqcCommand(self.lqc, 'playlistData')
        if not raw:
            self.success('00', simplejson.loads(data))
            self.notifyClient()
        else:
            return data     
           
    #------------------------------------------------------------------------------------------#
    def playlist_flush(self):
        """
        Aktuelle Playlist leeren           
        """ 
        data = self.sendLqcCommand(self.lqc, 'flush')               
        self.success('00') 
        self.notifyClient()        

    #------------------------------------------------------------------------------------------#
    def playlist_insert(self, uri, pos):
        """
        Track in die Playlist einfuegen                        
        """                        
        data = self.sendLqcCommand(self.lqc, 'insert', uri, pos)
        if not self._check_result(data):
            self.warning('01')
        else:
            self.success('00') 
        self.notifyClient()
        
    #------------------------------------------------------------------------------------------#
    def playlist_load(self, uri):
        """
        Playlist laden        
        @type   uri:   string
        @param  uri:   Uri der Playlist          
        """

        try:
            xml = urllib2.urlopen(uri).read().decode('utf8')

        except:
            try:
                xml = open(uri).read().decode('utf8')
            except:
                self.error('01', self.lq_error['message'])
                self.notifyClient()
                return

        (num, filename) = tempfile.mkstemp(suffix=".xspf")

        with codecs.open(filename, "w",encoding='utf8') as text_file:
            text_file.write(xml)

        playlist = parsexml(xml)


        if not isinstance(playlist, dict):
            self.error('02')
            self.notifyClient()
        else:
            self.sendLqcCommand(self.lqc, 'flush')
            data = self.sendLqcCommand(self.lqc, 'loadPlaylist', filename)

            if not self._check_result(data):
                self.error('01', self.lq_error['message'])
                     
            else:
                os.remove(filename)
                self._updateEventQueue(playlist)
                event = {'job':'loadplaylist', 'uri': uri}         
                self.messenger.fireEvent('loadplaylist', event, 'player')
                self.success('00') 
        
            self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def playlist_move(self, fromPos, toPos):
        """
        Playlist-Eintrag von Position fromPos nach Position toPos verschieben
        @type     fromPos: int
        @param    fromPos: die Position des Eintrags, der verschoben wird 
        @type     toPos:   int
        @param    toPos:   Zielposition                                       
        """               
        data = self.sendLqcCommand(self.lqc, 'move', str(int(fromPos)+1), str(int(toPos)+1))
            
        if not self._check_result(data):
            self.warning('01')
        else:
            self.success('00') 
        
        self.notifyClient()    
    
    #------------------------------------------------------------------------------------------#
    def playlist_pause(self):
        """
        Playlist pausieren
        """               

        data = self.sendLqcCommand(self.lqc, 'pause')
        
        if not self._check_result(data):
            self.info('01')
        else:
            self.success('00') 
        
        self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def playlist_stop(self):
        """
        Playlist stoppen - der Kanal wird deaktiviert
        """
        # Kanal 0 (Playlist) deaktivieren
        self.sendLqcCommand(self.lqc, 'deactivate', '0')

        data = self.sendLqcCommand(self.lqc, 'pause')

        if not self._check_result(data):
            self.info('01')
        else:
            self.success('00')

        self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def playlist_play(self, when='now'):
        """
        Playlist starten
        @type   when:   string
        @param  when:   Wenn "now" werden alle anderen Kanäle deaktiviert und geskipped                   
        """                       
        # Playlist Kanal aktivieren
        self.sendLqcCommand(self.lqc, 'activate', '0')
                
        if when == 'now':            
            # immediately skip all playing channels
            # and activate the playlist channel
            channels = self.sendLqcCommand(self.lqc, 'listChannels')
            if not isinstance(channels, list):
                self.error('03')
            elif len(channels) < 1:            
                self.warning('02')
            else:        
                for i in xrange(len(channels)):
                    status = self.sendLqcCommand(self.lqc, 'status', 'mixer', str(i + 1))
                    if "selected=true" in status:
                        status = self.sendLqcCommand(self.lqc, 'deactivate', str(i + 1))
                        status = self.sendLqcCommand(self.lqc, 'skip', 'mixer', str(i + 1))
                        self.sendLqcCommand(self.lqc, 'activate', '0')

        # send the play command
        data = self.sendLqcCommand(self.lqc, 'play')
        if not self._check_result(data):
            self.info('01')
        else:
            self.success('00')
        
        self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def playlist_push(self, uri):
        """
        Eine Uri in die Playlist einfügen
        @type   uri:   str
        @param  uri:   Die Uri
        """                       
        data = self.sendLqcCommand(self.lqc, 'push', uri)
        
        if not self._check_result(data):
            self.info('01')
        else:
            self.success('00') 
        
        self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def playlist_remove(self, pos):
        """
        Playlist-Eintrag löschen 
        @type     pos:     int
        @param    pos:     Position des Eintrags             
        """
        data = self.sendLqcCommand(self.lqc, 'remove', pos)

        if not self._check_result(data):
            self.info('01')
        else:
            self.success('00') 
        
        self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def playlist_seek(self, duration):
        """
        Im aktuell spielenden Track auf dem der Playlist "vorspulen"
        @type     duration: int
        @param    duration: Dauer in Sekunden     
        """                
        data = self.sendLqcCommand(self.lqc, 'seek', duration)
                
        # Resultate prüfen
        if self._check_result(data):        
                self.success('00', self.lq_error['value'])
        else:    
            self.warning('01')
        
        self.notifyClient()                         

    #------------------------------------------------------------------------------------------#
    def playlist_skip(self):
        """
        Playlist skippen 
        """
        data = self.sendLqcCommand(self.lqc, 'skip')                
        
        self.success('00')
        
        self.notifyClient()                         

    #------------------------------------------------------------------------------------------#
    def recorder_start(self):
        """
        Recorder starten
        @rtype:   string
        @return:  Die Antwort des Liquidsoap-Servers               
        """                                
        message = self.sendLqcCommand(self.lqcr, 'start_record')
        if message.strip() == 'OK':
            self.success('00')
        else:    
            self.warning('01')
                
        self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def recorder_stop(self):
        """
        Recorder stoppen  
        """
        message = self.sendLqcCommand(self.lqcr, 'stop_record')
                                 
        if message.strip() == 'OK':
            self.success('00')
        else:    
            self.warning('01')
                
        self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def recorder_stop(self):
        """
        Recorder stoppen  
        """
        message = self.sendLqcCommand(self.lqcr, 'stop_record')
                                 
        if message.strip() == 'OK':
            self.success('00')
        else:    
            self.warning('01')
                
        self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def recorder_data(self):
        """
        Status-Daten des Recorders
        Rückgabe-Beispiel: /var/audio/rec/2014-05-13/2014-05-13-22-00.wav,30 - Aufnahme von 30% der angegebenen Audiodatei     
        """   
        
        message = self.sendLqcCommand(self.lqcr, 'recorder_data')
        l = message.split(',')
        data = {}
        
        if not isinstance(l, list):
            data = {'file':'', 'recorded': ''}
            self.warning('01')
        else:
            data['file'] = l[0]
            if len(l) > 1:
                data['recorded'] = l[1]
            else:
                data['recorded'] = ''
            self.success('00', data) 
        
        self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def scheduler_reload(self):
        """
        Veranlasst den Scheduler zum Reload
        """
        process =  "combas.py"
        pids = psutil.get_pid_list()
        foundProcess = False  
        for pid in pids:
            cmd = psutil.Process(pid).cmdline
            if len(cmd) > 1:
                processName = cmd[1]
            else:
                processName = psutil.Process(pid).name    
    
            if processName.find(process) > 0:
                os.kill(pid,signal.SIGUSR1)                
                foundProcess = True  
                break
        if not foundProcess:
            return False
        else:
            return True

    #------------------------------------------------------------------------------------------#
    def scheduler_data(self):
        """
        Scheduler Config ausliefern
        """
        jobs = []
        
        try:
            # Das scheduler.xml laden            
            schedulerconfig = CombaSchedulerConfig(self.sender.schedule_config)
            jobs = schedulerconfig.getJobs()
        except:
            # Das scheint kein gültiges XML zu sein            
            self.warning('01', False)
                    
        self.success('00', simplejson.dumps(jobs))
        self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def scheduler_store(self, adminuser, adminpassword, json):
        """
        Scheduler Config zurückschreiben
        """   
        if not self.userdb.hasAdminRights(adminuser, adminpassword):        
            self.warning('01', False)
            self.notifyClient()
            return
        try:
            schedulerconfig = CombaSchedulerConfig(self.sender.schedule_config)
        except:
            self.warning('02', False)
            self.notifyClient()
        try:
            schedulerconfig.storeJsonToXml( base64.b64decode(json))
        except:
            self.warning('02', False)
            self.notifyClient()
        else:                    
            if self.scheduler_reload():
                self.success('00', True)
            else:
                self.warning('02', False)            
        self.notifyClient()

    #------------------------------------------------------------------------------------------#
    def setPassword(self, adminuser, adminpassword, username, password):
        """
        Ein Userpasswort setzen
        TODO: Passwörter verschlüsselt übertragen
        """
        if self.userdb.hasAdminRights(adminuser, adminpassword):
            self.userdb.setPassword(username, password)
            self.success('00', password)
        else:
            self.warning('01', False)

        self.notifyClient()
        self.sender.reload()

    #------------------------------------------------------------------------------------------#
    def addUser(self, adminuser, adminpassword, username):
        """
        Einen User hinzufügen
        TODO: Passwort verschlüsselt übertragen
        """
        if self.userdb.hasAdminRights(adminuser, adminpassword):
            password = ''.join(random.sample(string.lowercase+string.uppercase+string.digits,14))
            self.userdb.insertUser(username, password, 'user')
            self.success('00', password)
        # TODO admin rechte checken user und passwort setzen, passwort zurückgeben
        else:
            self.warning('01', False)

        self.notifyClient()
        self.sender.reload()

    #------------------------------------------------------------------------------------------#
    def delUser(self, adminuser, adminpassword, username):
        """
        Einen User löschen
        TODO: Passwort verschlüsselt übertragen
        """
        # TODO admin rechte checken user löschen
        if self.userdb.hasAdminRights(adminuser, adminpassword):
            self.userdb.delete(username)
            self.success('00', True)
        else:
            self.warning('01', False)

        self.notifyClient()
        self.sender.reload()

    #------------------------------------------------------------------------------------------#
    def getUserlist(self, adminuser, adminpassword):
        """
        Einen User löschen
        TODO: Passwort verschlüsselt übertragen
        """
        # TODO admin rechte checken user löschen
        if self.userdb.hasAdminRights(adminuser, adminpassword):
            userlist = self.userdb.getUserlist()
            self.success('00', simplejson.dumps(userlist))
        else:
            self.warning('01', False)

        self.notifyClient()


    #------------------------------------------------------------------------------------------#
    def _metadata_format(self, metadata):
        """
        Private: Vereinheitlicht die Metadaten von Playlist und anderen Kanälen und entfernt Anführungszeichen in den Feldern
        @rtype:   boolean/dict
        @return:  False/Metadaten
        """           
        mdata = {}  
        try:
            for key,val in metadata.items('root'):
                if key in self.knownfields:
                    mdata[key] = val.strip().replace('"', '')
            return mdata
        except:
            return False

    #------------------------------------------------------------------------------------------#
    def _getError(self, errornumber):
        """
        Privat: Ermittelt Fehlermeldung, Job-Name (Klassenmethode) und Fehlercode für den Job aus error/combac_error.js
        @type errornumber:  string
        @param errornumber: Die interne Fehlernummer der aufrufenden Methode  
        """        
        f = sys._getframe(2)
        
        job = f.f_code.co_name
        data = {'message':'', 'job':job, 'code':'unknown'}
        if self.errorData.has_key(job):
            errMsg = self.errorData[job][errornumber]
            errID = self.errorData[job]['id'] + str(errornumber) 
            args = {x:f.f_locals[x] if not x == 'self' else '' for x in f.f_code.co_varnames[:f.f_code.co_argcount]}
            
            for key in args.keys():            
                errMsg = errMsg.replace('::' + key + '::', str(args[key]))
            
            data['message'] = errMsg
            data['job'] = job
            data['code'] = errID
             
        return data

    #------------------------------------------------------------------------------------------#
    def success(self, errnum='00', value='', section='main'):
        """
        Erfolgsmeldung loggen
        @type errnum:    string
        @param errnum:   Errornummer der aufrufenden Funktion
        @type value:     string
        @param value:    Optionaler Wert 
        @type section:   string
        @param section:  Gültigkeitsbereich        
        """
        error = self._getError(errnum)
        self.job_result = {'message':error['message'], 'code':error['code'], 'success':'success', 'job':error['job'], 'value':value, 'section':section}
        self.messenger.send(error['message'], error['code'], 'success', error['job'], value, section)

    #------------------------------------------------------------------------------------------#
    def info(self, errnum='01', value='', section='main'):                        
        """
        Info loggen
        @type errnum:    string
        @param errnum:   Errornummer der aufrufenden Funktion
        @type value:     string
        @param value:    Optionaler Wert 
        @type section:   string
        @param section:  Gültigkeitsbereich                
        """
        error = self._getError(errnum)
        self.job_result = {'message':error['message'], 'code':error['code'], 'success':'info', 'job':error['job'], 'value':value, 'section':section}        
        self.messenger.send(error['message'], error['code'], 'info', error['job'], value, section)

    #------------------------------------------------------------------------------------------#
    def warning(self, errnum='01', value='', section='main'):
        """
        Warnung loggen
        @type errnum:    string
        @param errnum:   Errornummer der aufrufenden Funktion
        @type value:     string
        @param value:    Optionaler Wert 
        @type section:   string
        @param section:  Gültigkeitsbereich                
        """        
        error = self._getError(errnum)
        self.job_result = {'message':error['message'], 'code':error['code'], 'success':'warning', 'job':error['job'], 'value':value, 'section':section}
        self.messenger.send(error['message'], error['code'], 'warning', error['job'], value, section)

    #------------------------------------------------------------------------------------------#
    def error(self, errnum='01', value='', section='main'):
        """
        Error loggen
        @type errnum:    string
        @param errnum:   Errornummer der aufrufenden Funktion
        @type value:     string
        @param value:    Optionaler Wert 
        @type section:   string
        @param section:  Gültigkeitsbereich                
        """        
        error = self._getError(errnum)
        self.job_result = {'message':error['message'], 'code':error['code'], 'success':'error', 'job':error['job'], 'value':value, 'section':section}
        self.messenger.send(error['message'], error['code'], 'error', error['job'], value, section)

    #------------------------------------------------------------------------------------------#
    def fatal(self, errnum='01', value='', section='main'):
        """
        Fatal error loggen
        @type errnum:    string
        @param errnum:   Errornummer der aufrufenden Funktion
        @type value:     string
        @param value:    Optionaler Wert 
        @type section:   string
        @param section:  Gültigkeitsbereich                
        """
        error = self._getError(errnum)
        self.job_result = {'message':error['message'], 'code':error['code'], 'success':'fatal', 'job':error['job'], 'value':value, 'section':section}
        self.messenger.send(error['message'], error['code'], 'fatal', error['job'], value, section)    

    #------------------------------------------------------------------------------------------#
    def notifyClient(self):
        """
        Eine Nachricht als JSON-String an den Client senden
        """
        if not self.is_intern:                        
            self.message(simplejson.dumps(self.job_result))

    #------------------------------------------------------------------------------------------#
    def sendLqcCommand(self, lqs_instance, command, *args):
        """
        Ein Kommando an Liquidsoap senden
        @type  lqs_instance: object
        @param lqs_instance: Instanz eines Liquidsoap-Servers - recorder oder player
        @type  command:      string
        @param command:      Ein Funktionsname aus der Liquidsoap-Klasse
        @type args:          list
        @param args:         Parameterliste
        @rtype:              string
        @return:             Antwort der Liquidsoap-Instanz
        """
        try:
        # Verbindung herstellen
            lqs_instance.connect()
        except:
            # Verbindung gescheitert - Fehler an Client
            if command.find('record') > -1:
                self.fatal('02')
            else:
                self.fatal('01') 
                
            self.notifyClient()
            # Instanz/Thread zerstören - aufrufende Funktion wird nicht weiter abgearbeitet
            del self
        else:
            # Funktion des Liquidsoap Servers zusammenbasteln 
            func = getattr(lqs_instance, command)
            result = func(*args)             
            return result
            
    #------------------------------------------------------------------------------------------#
    def _check_result(self, result):
        """
        Fehlerbehandlung
        @type     result: string
        @param    result: Ein Json-String
        """
        self.lq_error = simplejson.loads(result)
        
        try:
            if self.lq_error['success'] == 'true':
                return True
            else:
                return False
        except:
            return False

    #------------------------------------------------------------------------------------------#
    def _updateEventQueue(self, playlist):
        """
        Playlist Eventqueue updaten
        @type playlist: dict 
        @param playlist: Playlist 
        """
        # eventuell noch bestehende Events im Queue löschen
        self.messenger.queueRemoveEvents('playtrack', 'player')
        # Für jeden Tack einen Event ankündigen
        for track in playlist['playlist']['trackList']['track']:

            if track.has_key('time') and track.has_key('start'):
                starts = str(track['start'] + 'T' + track['time'])
                event = {'job':'play', 'location': track['location'],'length': track['length'], 'date': track['start'], 'time': track['time']}
                self.messenger.queueAddEvent('playtrack', starts, event, 'player')