예제 #1
0
 def __init__(self, addr='127.0.0.1', port='6600', **kwargs):
     '''
     Constructor
     '''
     self.addr = addr
     print addr
     print port
     self.port = int(port)
     self.mpd = MpdFactory(self.changed_state)
     internet.TCPClient.__init__(self,  # @UndefinedVariable
                                 addr,
                                 self.port,
                                 self.mpd)
예제 #2
0
class Mpdclient(internet.TCPClient):  # @UndefinedVariable
    '''
    classdocs
   '''
    _state = "pending"
    upnp_state = "TRANSITIONNING"
    oh_state = 'Buffering'
    _track_URI = ''
    _managed = False
    _errors = 0
    _metadata = {}
    _playlist = []
    _volume = 100
    _rate = "1"
    _mtlist = ''
    mtlist = ''
    _muted = True
    _track_duration = '0:00:00.000'
    name = "MpdPlayer"
    cancelplay = False
    reltime = '0:00:00.000'
    seconds = 0
    repeat = False
    shuffle = False
    counter = 0
    tracksmax = 0
    metadata = {}
    playlist = []
    idArray = ''
    maxid = 0
    metadata_str = 'NOT_IMPLEMENTED'
    songid = 0
    transport_actions = ['PLAY']
    timer = None
    token = 0
    max_volume = 100

    def __init__(self, addr='127.0.0.1', port='6600', **kwargs):
        '''
        Constructor
        '''
        self.addr = addr
        print addr
        print port
        self.port = int(port)
        self.mpd = MpdFactory(self.changed_state)
        internet.TCPClient.__init__(self,  # @UndefinedVariable
                                    addr,
                                    self.port,
                                    self.mpd)

    def startService(self):
        internet.TCPClient.startService(self)  # @UndefinedVariable
        self.update_state()
        self.update_metadata()
        self.update_mimetypes()

    def changed_state(self, state):
        changed = state.keys()
        if 'state' in changed:
            self.set_state(state['state'])
        if "volume" in changed:
            log.msg('volume changed', loglevel=logging.DEBUG)
            vol = int(state['volume'])
            if vol != self._volume:
                if vol != 0:
                    self._volume = vol
                    muted = False
                else:
                    muted = True
                log.msg('send volume', loglevel=logging.DEBUG)
                self.oh_eventVOLUME(self._volume, 'volume')
                self.upnp_eventRCS(self._volume, 'Volume')
                if muted is not self._muted:
                    self._muted = muted
                    self.upnp_eventRCS(self._muted, 'Mute')
                self.oh_eventVOLUME(int(self._muted), 'mute')

        if 'songid' in changed:
            self.update_metadata(state['songid'])
        if 'repeat' in changed:
            if self.repeat != bool(state['repeat']):
                self.repeat = bool(state['repeat'])
                if not self.shuffle:
                    self.upnp_eventAV(
                        'REPEAT_ALL' if self.repeat else 'NORMAL',
                        'CurrentPlayMode')
                else:
                    self.upnp_eventAV('REPEAT_ALL SHUFFLE' if self.repeat
                                      else 'NORMAL SHUFFLE', 'CurrentPlayMode')
                self.oh_eventPLAYLIST(self.repeat, 'repeat')
        if 'random' in changed:
            if self.shuffle != bool(state['repeat']):
                self.shuffle = bool(state['repeat'])
                if not self.repeat:
                    self.upnp_eventAV(
                        'NORMAL SHUFFLE' if self.shuffle else 'NORMAL',
                        'CurrentPlayMode')
                else:
                    self.upnp_eventAV(
                        'REPEAT_ALL SHUFFLE' if self.shuffle
                        else 'NORMAL SHUFFLE', 'CurrentPlayMode')
                self.oh_eventPLAYLIST(self.shuffle, 'shuffle')
        if 'elapsed' in changed:
            if self.timer is not None:
                self.timer.set(float(state['elapsed']))
        if 'playlist' in changed:
            self.token = int(state['playlist'])
        if 'playlistdata' in changed:
            self.update_playlist(state['playlistdata'])
        if 'bitrate' in changed:
            self.oh_eventINFO(int(state['bitrate']), 'bitrate')
        if 'audio' in changed:
            try:
                sr = int(state['audio'].split(':')[0])
                self.oh_eventINFO(sr, 'samplerate')
            except:
                log.err('Bad Samplerate: %s' % state['audio'].split(':')[0])
            try:
                bd = int(state['audio'].split(':')[1])
                self.oh_eventINFO(bd, 'bitdepth')
            except:
                log.err('Bad Bitdepth: %s' % state['audio'].split(':')[1])

    def update_state(self):
#         log.err('Update State: %s' % self.mpd.status['state'])
        self.set_state(self.mpd.status['state'])

    def update_playlist(self, newpl):
        self.playlist = newpl
        self.idArray = id_array(newpl)
        self.oh_eventPLAYLIST(self.idArray, 'idarray')
#         d.addCallback(self.oh_eventPLAYLIST, 'idarray')

    def update_metadata(self, songid=None):
        log.msg('update metadata')

        def getmd(md):
            if isinstance(md, list):
                nd = {}
                for d in md:
                    nd.update(d)
                md = nd
            if md != self._metadata:
                self._metadata = md
#                 log.err(md)
                self.metadata.update(mpd_decode(self._metadata))
                if self._track_duration != self.metadata['duration']:
                    self._track_duration = self.metadata['duration']
                    self.upnp_eventAV(self._track_duration,
                                      'CurrentTrackDuration')
                    sec = upnptime_to_mpdtime(self._track_duration)
                    self.oh_eventINFO(sec, 'duration')
                    self.oh_eventTIME(sec, 'duration')
                if self.songid != self.metadata['id']:
                    self.songid = self.metadata['id']
                    self.upnp_eventAV(int(self.songid), 'CurrentTrack')
                    self.oh_eventPLAYLIST(int(self.songid), 'id')
                    self.oh_eventTIME(1, 'trackcount')
                if 'url' in self.metadata.keys():
                    self._track_URI = self.metadata['url']
                    self.upnp_eventAV(self._track_URI, 'AVTransportURI')
                    self.oh_eventINFO(self._track_URI, 'uri')
                    self.upnp_eventAV(self._track_URI, 'CurrentTrackURI')
                    try:
                        self.oh_eventINFO(
                            self.metadata['codec'].upper(), 'codecname')
                        if self.metadata['codec'].lower() in ['flac', 'm4a']:
                            self.oh_eventINFO(1, 'lossless')
                        else:
                            self.oh_eventINFO(0, 'lossless')
                    except KeyError:
                        pass
                self.metadata_str = didl_encode(self.metadata)
                self.oh_eventINFO(self.metadata_str, 'metadata')
                self.upnp_eventAV(self.metadata_str, 'AVTransportURIMetaData')
                if self.tracksmax == 0:
                    self.tracksmax = 10000
                    self.oh_eventPLAYLIST(self.tracksmax, 'tracksmax')

        if songid is not None:
            d = self.mpd.call('playlistid', songid)
        else:
            d = self.mpd.call('currentsong')
        d.addCallback(getmd)

    def update_mimetypes(self):
        self.set_mimetypes(self.mpd.mimetypes)

    def upnp_eventAV(self, evt, var):
        pass

    def upnp_eventCM(self, evt, var):
        pass

    def upnp_eventRCS(self, evt, var):
        pass

    def oh_eventPLAYLIST(self, evt, var):
        pass

    def oh_eventINFO(self, evt, var):
        pass

    def oh_eventTIME(self, evt, var):
        pass

    def oh_eventVOLUME(self, evt, var):
        pass

    def getMetadata(self):
        return self.mpd.call('playlistid', self.mpd.status['songid'])

    def getMimeTypes(self):
        return self.mpd.call('decoders')

    def get_state(self):
        return self._state

    def get_rate(self):
        return self._rate

    def get_track_duration(self):
        try:
            duration = self._track_duration
        except:
            duration = '00:00:00'
        return duration

    def get_track_URI(self):
        try:
            uri = self._track_URI
        except:
            uri = ''
        return uri

    def get_track_md(self):
        return self.metadata_str

    def get_sticker(self, url, dic={}):

        def got_sticker(stklist, dic):
            if not isinstance(stklist, list):
                stklist = [stklist]
            for sticker in stklist:
                try:
                    dic.update(
                        {sticker['sticker'].split('=')[0],
                         sticker['sticker'].split('=')[1]})
                except:
                    continue
            return dic

        d = self.mpd.call('sticker', ' '.join(('list song', url.join('"'*2))))
        d.addBoth(got_sticker, dic)
        return d

    def get_tracks(self, tracks):

        def got_tracks(tracks):
            if not isinstance(tracks, list):
                tracks = [tracks]
            sl = []
            for track in tracks:
                t = mpd_decode(track)
                sl.append(self.get_sticker(t['url'], t))
            return defer.gatherResults(sl)

        def generate_tracklist(tracks, tracklist=None):
#             log.err(tracks)
            if not isinstance(tracks, list):
                tracks = [tracks]
            tl = et.Element('TrackList')
            for idx, track in enumerate(tracks):
#                 log.err(track)
                if isinstance(track, dict):
                    track = mpd_decode(track)
                else:
#                     log.err(track)
                    nd = {}
                    for d in track:
#                         log.err(d)
                        nd.update(d)
                    track = mpd_decode(nd)
#                     log.msg(nd)
                en = et.Element('Entry')
                i = et.Element('Id')
                if not 'id' in track:
                    if tracklist:
                        track.update({'id': str(tracklist[idx])})
                    else:
                        log.err(track)
                i.text = track['id'].decode('utf-8')
                en.append(i)
                uri = et.Element('Uri')
                uri.text = track['url'].decode('utf-8')
                en.append(uri)
                md = et.Element('Metadata')
                md.text = didl_encode(track)
                en.append(md)
                tl.append(en)
            return et.tostring(tl)

#         if tracks == self.playlist:
#             d = self.mpd.call('playlistid')
#             d.addCallback(generate_tracklist, tracks)
#         else:
        tl = []
        for track in tracks:
            tl.append(self.mpd.call('playlistid', str(track)))
        d = defer.gatherResults(tl)
#         d.addCallback(got_tracks)
        d.addCallback(generate_tracklist)
        return d

    def get_track(self, track=None):

        def got_result(res):
            uri = res['url']
            return (uri, didl_encode(res))
        if track is None:
            d = defer.succeed((self._track_URI, self.metadata_str))
        else:
            d = self.mpd.call('playlistid', str(track))
            d.addCallback(mpd_decode)
            d.addCallback(got_result)
        return d

    def get_relcount(self):
        return 2147483647

    def get_abscount(self):
        return 2147483647

    def get_abstime(self):
            return '00:00:00'

    def get_reltime(self, fmt='UPNP'):
        if self.timer is not None:
            if fmt == 'UPNP':
                t = mpdtime_to_upnptime(self.timer.get())
            elif fmt == 'seconds':
                t = int(self.timer.get())
            else:
                # msec
                t = self.timer.get()
        else:
            if fmt == 'UPNP':
                t = self.reltime
            else:
                t = self.seconds
#         log.err('reltime: %s' % t)
        return t

    def get_volume(self):

        def noVolume(err):
            if self._muted:
                return 0
            else:
                return self._volume

        def convert_volume(vol):
            self._volume = int(float(vol) * 100)
            log.msg("volume= %d" % self._volume, loglevel=logging.DEBUG)
            return self._volume

        d = self.mediaplayer.get("Volume",
                                 interf='org.mpris.MediaPlayer2.Player')
        d.addCallbacks(convert_volume, noVolume)
        return d

    def get_transport_actions(self):
            return {','.join(self.transport_actions)}

    def set_volume(self, channel, volume):
        volume = str(volume)
        d = self.mpd.call('setvol', volume)
        d.addErrback(
            log.msg,
            'Set Volume Error : %s - %d' % (channel, int(volume)))
        reactor.callLater(0.1,  # @UndefinedVariable
                          self.changed_state,
                          {'volume': str(volume)})

    def set_mimetypes(self, mtlist):
        if self._mtlist != mtlist:
            self._mtlist = mtlist
            self.mtlist = 'http-get:*:' + ''\
                .join([':*,http-get:*:'.join(mtlist)]) + ':*'
            self.upnp_eventCM(self.mtlist, 'SinkProtocolInfo')
            self.oh_eventPLAYLIST(self.mtlist, 'protocolinfo')

    def set_metadata(self, metadata):
        if metadata != self.metadata:
            self.metadata.update(metadata)
            if 'duration' in metadata.keys():
#                 log.err('duration set to %s by metadata'
#                         % metadata['duration'])
                self._track_duration = metadata['duration']
            if 'url' in metadata.keys():
                self._track_URI = metadata['url']
            if 'file' in metadata.keys():
                self._track_URI = metadata['file']

    def set_reltime(self, t):
        self.seconds = int(float(t))
        self.reltime = mpdtime_to_upnptime(t)
#         log.err('seconds: %s' % t)
        self.timer = None

    def set_state(self, state):
        log.msg("SET NEW STATE : %s " % state, loglevel=logging.DEBUG)
        if state == self._state:
            return
        self._state = state
        if state == 'pause':
            #             print(self.transport_actions)
            self.transport_actions = ['PLAY', 'STOP']
#                 self.transport_actions.remove('PAUSE')
#                 self.transport_actions.append('PLAY')
            if self.timer is not None:
                self.timer.stop()
                d = self.mpd.call('status')
                d.addCallback(lambda st: st['elapsed'])
                d.addCallbacks(
                    self.set_reltime,
                    lambda ignored: self.set_reltime(self.timer.get()))
            self.upnp_state = 'PAUSED_PLAYBACK'
            self.oh_state = 'Paused'
        elif state == 'play':
            self.transport_actions = ['STOP', 'PAUSE', 'SEEK']
            self.changed_state({'volume': self.mpd.status['volume']})
            self.timer = Timer()
            self.timer.set(self.seconds)
            d = self.mpd.call('status')
            d.addCallbacks(lambda st: st['elapsed'])
            d.addCallbacks(lambda t: self.timer.set(float(t)),
                           lambda ignored: self.timer.set(0.000))
            self.upnp_state = 'PLAYING'
            self.oh_state = 'Playing'
        elif state == 'stop':
            self.transport_actions = ['PLAY']
            self.set_reltime(0)
            self.upnp_state = 'STOPPED'
            self.oh_state = 'Stopped'
        elif state == 'pending':
            self.upnp_state = 'TRANSITIONNING'
            self.oh_state = 'Buffering'
        else:
#             log.err('Unknow State from player : %s' % state)
            return
        log.msg('send new state: %s' % self._state, loglevel=logging.DEBUG)
        self.upnp_eventAV(self.upnp_state, 'TransportState')
        self.oh_eventPLAYLIST(self.oh_state, 'transportstate')

    def set_songid(self, songid):
        self.songid = songid['Id']
#         log.err('songid = %s' % songid)
        return self.songid

    def set_position(self, newpos, fmt='UPNP'):
        def transition(obj):
            current_state = self._state
            self.set_state('pending')
            reactor.callLater(0.5,  # @UndefinedVariable
                              self.set_state,
                              current_state)
        if fmt == 'UPNP':
            pos = upnptime_to_mpdtime(newpos)
        else:
            pos = newpos
        d = self.mpd.call('seekcur', pos)
        d.addCallback(transition)
        return d

    def set_position_relative(self, delta, fmt='UPNP'):
        newpos = int(self.get_reltime('Seconds')) + int(delta)
        self.set_position(newpos, fmt)

    def set_track_URI(self, uri, md=''):
        log.msg("set track uri : %s " % uri, loglevel=logging.DEBUG)
        try:
            log.msg("current uri : %s " % self._track_URI, loglevel=logging.DEBUG)
        except:
            pass
        if uri != self._track_URI:
            self._track_URI = uri
            self.metadata_str = md
            self.set_metadata(didl_decode(md.encode('utf-8')))
            d = self.mpd.call('addid', uri)
            d.addCallback(self.set_songid)
            d.addCallback(self.play)

    def set_repeat(self, repeat):
        self.mpd.call('repeat', str(int(repeat)))

    def set_shuffle(self, repeat):
        self.mpd.call('shuffle', str(int(repeat)))

    def stop(self):
        def stopped(ret):
                self.set_state('stop')
        if self._state != 'STOPPED':
            d = self.mpd.call('stop')
            self.reltime = '00:00:00'
            d.addCallback(stopped)

    def play(self, songid=None, ignored=None):
        def success(result):
            return None
        if self.cancelplay:
            self.cancelplay = False
        else:
            if songid is not None:
                d = self.mpd.call('playid', songid)
            else:
                if self._state == 'pause':
                    d = self.mpd.call('pause', '0')
                else:
                    d = self.mpd.call('playid', self.songid)
            d.addCallback(self.playing)

    def playing(self, *ret):
            log.msg('playing...', loglevel=logging.DEBUG)
            self.set_state('play')

    def playindex(self, index):
        return self.play(self.playlist[int(index)])

    def playpause(self):
        if self._state == 'pause':
            return self.play()
        else:
            return self.pause()

    def pause(self):
        def paused(ret):
            if self._state == 'play':
                self.set_state('pause')
    #         d =  self.player_func('Pause','org.mpris.MediaPlayer2.Player' )
        d = self.mpd.call('pause', '1')
        d.addCallback(paused)
        return d

    def next(self):
        self.mpd.call('next')

    def previous(self):
        self.mpd.call('previous')

    def volUp(self):
        if self._volume == 0:
            vol = self.get_volume()
            try:
                newvol = vol + 5
            except:
                newvol = self._volume + 5
            return self.set_volume('Master', newvol)
        else:
            if self._volume > 95:
                return
            newvol = self._volume + 5
            return self.set_volume('Master', newvol)

    def volDown(self):
        if self._volume > 5:
            newvol = self._volume - 5
            return self.set_volume('Master', newvol)
        else:
            self._volume = 0
            return self.set_volume('Master', '0')

    def insert_metadata(self, md):
            dic = didl_decode(md)
#             log.err(dic)
            for i, tag in enumerate(dic.keys()):
                if tag.lower() in ('class', 'restricted', 'id', 'duration',
                                   'parentid', 'protocolinfo', 'url',
                                   'ownerudn'):
                    continue
                if not isinstance(dic[tag], str):
                    continue
                reactor.callLater(  # @UndefinedVariable
                    float(i)/2,
                    self.mpd.call,
                    ' '.join(('sticker',
                              'set song',
                              dic['url'].join('"'*2),
                              tag,
                              '"' + dic[tag] + '"')))

    def insert(self, url, afterid, metadata, checked=False):

        def inserted(res, md):
            #             log.err('%s %s' % (res, md))
            #             reactor.callLater(2,  # @UndefinedVariable
            #                               self.insert_metadata,
            #                               md)
            return res['Id']

        if 'youtube' in url and not checked:
            # eclipse workaround !!!
            y = os.environ
            y.update({'PYTHONPATH': '/usr/bin/python'})
            # / eclipse workaround
            d = utils.getProcessOutput(
                '/usr/bin/youtube-dl',
                ['-g', '-f', 'bestaudio', url],
                env=y,
                reactor=reactor)
            d.addCallback(
                lambda u: self.insert(
                    u.split('\n')[0], afterid, metadata, True))
            return d
        if len(self.playlist) == 0:
            d = self.mpd.call('addid', url)
        elif int(afterid) == 0:
            d = self.mpd.call('addid', url + ' 0')
        else:
            d = self.mpd.call(
                'addid',
                ' '.join((url, str(self.playlist.index(int(afterid))+1))))
        d.addCallback(inserted, metadata)

        return d

    def delete(self, songid):
        self.mpd.call('deleteid', str(songid))

    def clear(self):
        self.mpd.call('clear')