Exemple #1
0
 def __init__(self, proxy, playername):
     super().__init__(proxy, playername)
     self._inited = False
     self._metadata = None
     self._songid = -1
     self._playlist = -1
     self._repeat = None
     self._single = None
     self._random = None
     self._state = None
     self._elapsed = Timer(100)
     self._send_cmd(Cmds.STATUS, sync=True)
     self._inited = True
Exemple #2
0
 def __init__(self, proxy, playername):
     super(MpdPlayer, self).__init__(proxy, playername)
     self._inited = False
     self._metadata = None
     self._songid = -1
     self._playlist = -1
     self._repeat = None
     self._single = None
     self._random = None
     self._state = None
     self._elapsed = Timer(100)
     self._send_cmd(Cmds.STATUS, sync=True)
     self._inited = True
Exemple #3
0
class MpdPlayer(BasePlayer):

    CMD_HANDLERS = {
        Cmds.CURRENTSONG: '_handle_currentsong',
        Cmds.NEXT: None,
        Cmds.PAUSE: None,
        Cmds.PLAY: None,
        Cmds.PREVIOUS: None,
        Cmds.RANDOM: None,
        Cmds.REPEAT: None,
        Cmds.REPLAY_GAIN_MODE: None,
        Cmds.REPLAY_GAIN_STATUS: '_handle_replay_gain_status',
        Cmds.SEEK: None,
        Cmds.SEEKCUR: None,
        Cmds.SEEKID: None,
        Cmds.SETVOL: None,
        Cmds.SINGLE: None,
        Cmds.STATUS: '_handle_status',
        Cmds.STOP: None,
    }

    CHANGE_CMDS = {
        'player': [Cmds.STATUS],
        'options': [Cmds.STATUS],
    }

    STATUS_CHANGE_MAP = {
        'songid': (int, 'track'),
        'playlist': (int, 'track'),
        'repeat': (int, 'repeat'),
        'single': (int, 'repeat'),
        'random': (int, 'shuffle'),
        'state': ('_parse_status', 'status'),
    }

    def __init__(self, proxy, playername):
        super().__init__(proxy, playername)
        self._inited = False
        self._metadata = None
        self._songid = -1
        self._playlist = -1
        self._repeat = None
        self._single = None
        self._random = None
        self._state = None
        self._elapsed = Timer(100)
        self._send_cmd(Cmds.STATUS, sync=True)
        self._inited = True

    def _send_cmd(self, cmd, *args, **kwargs):
        """ Send a cmd. Can use sync=[True|False] to send in a blocking or
        non-blocking way. Default is non-blocking
        """
        sync = False if 'sync' not in kwargs else kwargs['sync']
        if cmd not in self.CMD_HANDLERS:
            raise RuntimeError('Unknown command: %s', cmd)
        handler = self.CMD_HANDLERS[cmd]
        if handler is not None:
            handler = getattr(self, handler)
        else:
            handler = self._handle_nothing
        if sync:
            self.proxy.send_command_sync(cmd, handler, *args)
        else:
            self.proxy.send_command(cmd, handler, *args)

    def _handle_status(self, status):
        logging.debug('status\n%s', status)
        changes = set()
        for prop, handler in self.STATUS_CHANGE_MAP.items():
            if prop not in status:
                value = None
            else:
                func = handler[0]
                if not callable(func):
                    func = getattr(self, func)
                value = func(status[prop])
            if value != getattr(self, '_' + prop):
                logging.debug('prop %s changed to %s', prop, value)
                setattr(self, '_' + prop, value)
                changes.add(handler[1])

        if 'track' in changes:
            if self._songid is None:
                self._metadata = Metadata()
            else:
                self._send_cmd(Cmds.CURRENTSONG, sync=True)

        if 'status' in changes:
            if self._state == STATUS.PAUSED:
                self._elapsed.pause()
            elif self._state == STATUS.PLAYING:
                self._elapsed.play()
            else:
                self._elapsed.stop()
        if self._state == STATUS.STOPPED:
            elapsed = 0
        else:
            elapsed = float(status['elapsed']) * 1000
        if self._elapsed.set_time(elapsed):
            changes.add('position')
        if not self._inited:
            # Initializing, do not emit the change signals
            changes = set()
        for change in changes:
            getattr(self, change + '_changed')()

    def _handle_currentsong(self, metadata):
        logging.debug('currentsong: %s', metadata)
        args = {}
        for key in ('title', 'artist', 'album'):
            if key in metadata:
                args[key] = metadata[key]
        if 'time' in metadata:
            args['length'] = int(metadata['time']) * 1000
        if 'track' in metadata:
            args['tracknum'] = int(metadata['track'].split('/')[0])
        self._metadata = Metadata(**args)

    @staticmethod
    def _parse_status(value):
        status_map = {
            'play': STATUS.PLAYING,
            'pause': STATUS.PAUSED,
            'stop': STATUS.STOPPED,
        }
        if value not in status_map:
            raise RuntimeError('Unknown status ' + value)
        return status_map[value]

    def _handle_replay_gain_status(self, status):
        pass

    def _handle_nothing(self, *args):
        pass

    def handle_changes(self, changes):
        cmds = set()
        for change in changes:
            if change in self.CHANGE_CMDS:
                for cmd in self.CHANGE_CMDS[change]:
                    cmds.add(cmd)
        logging.debug('changes: %s', changes)
        logging.debug('cmds: %s', cmds)
        for cmd in cmds:
            self._send_cmd(cmd)

    def get_status(self):
        return self._state

    def get_metadata(self):
        return self._metadata

    def get_position(self):
        return self._elapsed.time

    def get_caps(self):
        return set([CAPS.PLAY, CAPS.PAUSE, CAPS.NEXT, CAPS.PREV, CAPS.SEEK])

    def get_repeat(self):
        if not self._repeat:
            return REPEAT.NONE
        if not self._single:
            return REPEAT.ALL
        return REPEAT.TRACK

    def set_repeat(self, mode):
        repeat_mode_map = {
            REPEAT.NONE: (0, 0),
            REPEAT.TRACK: (1, 1),
            REPEAT.ALL: (1, 0),
        }
        if mode not in repeat_mode_map:
            raise ValueError('Unknown repeat mode: %s', mode)
        self._repeat = repeat_mode_map[mode][0]
        self._single = repeat_mode_map[mode][1]
        self._send_cmd(Cmds.REPEAT, self._repeat)
        self._send_cmd(Cmds.SINGLE, self._single)

    def get_shuffle(self):
        return bool(self._random)

    def set_shuffle(self, shuffle):
        self._random = 1 if shuffle else 0
        self._send_cmd(Cmds.RANDOM, self._random)

    def play(self):
        if self._state == STATUS.PAUSED:
            self._send_cmd(Cmds.PAUSE, 0)
        elif self._state == STATUS.STOPPED:
            self._send_cmd(Cmds.PLAY)

    def pause(self):
        self._send_cmd(Cmds.PAUSE, 1)

    def stop(self):
        self._send_cmd(Cmds.STOP)

    def prev(self):
        self._send_cmd(Cmds.PREVIOUS)

    def next(self):
        self._send_cmd(Cmds.NEXT)

    def set_position(self, pos):
        self._send_cmd(Cmds.SEEK, self._songid, int(pos // 1000))

    def debug_info(self):
        ret = dbus.Dictionary(signature='sv')
        ret.update({
            'state': self._state,
            'metadata': self._metadata.to_mpris1(),
            'repeat': self._repeat,
            'single': self._single,
            'position': self.get_position()
        })
        return ret
Exemple #4
0
class MpdPlayer(BasePlayer):

    CMD_HANDLERS = {
        Cmds.CURRENTSONG: '_handle_currentsong',
        Cmds.NEXT: None,
        Cmds.PAUSE: None,
        Cmds.PLAY: None,
        Cmds.PREVIOUS: None,
        Cmds.RANDOM: None,
        Cmds.REPEAT: None,
        Cmds.REPLAY_GAIN_MODE: None,
        Cmds.REPLAY_GAIN_STATUS: '_handle_replay_gain_status',
        Cmds.SEEK: None,
        Cmds.SEEKCUR: None,
        Cmds.SEEKID: None,
        Cmds.SETVOL: None,
        Cmds.SINGLE: None,
        Cmds.STATUS: '_handle_status',
        Cmds.STOP: None,
    }

    CHANGE_CMDS = {
        'player': [Cmds.STATUS],
        'options': [Cmds.STATUS],
    }

    STATUS_CHANGE_MAP = {
        'songid': ('int', 'track'),
        'playlist': ('int', 'track'),
        'repeat': ('int', 'repeat'),
        'single': ('int', 'repeat'),
        'random': ('int', 'shuffle'),
        'state': ('_parse_status', 'status'),
    }

    def __init__(self, proxy, playername):
        super(MpdPlayer, self).__init__(proxy, playername)
        self._inited = False
        self._metadata = None
        self._songid = -1
        self._playlist = -1
        self._repeat = None
        self._single = None
        self._random = None
        self._state = None
        self._elapsed = Timer(100)
        self._send_cmd(Cmds.STATUS, sync=True)
        self._inited = True

    def _send_cmd(self, cmd, *args, **kwargs):
        """ Send a cmd. Can use sync=[True|False] to send in a blocking or
        non-blocking way. Default is non-blocking
        """
        sync = False if 'sync' not in kwargs else kwargs['sync']
        if cmd not in self.CMD_HANDLERS:
            raise RuntimeError('Unknown command: %s', cmd)
        handler = self.CMD_HANDLERS[cmd]
        if handler is not None:
            handler = getattr(self, handler)
        else:
            handler = self._handle_nothing
        if sync:
            self.proxy.send_command_sync(cmd, handler, *args)
        else:
            self.proxy.send_command(cmd, handler, *args)

    def _handle_status(self, status):
        logging.debug('status\n%s', status)
        changes = set()
        for prop, handler in self.STATUS_CHANGE_MAP.items():
            if not prop in status:
                value = None
            else:
                funcname = handler[0]
                func = getattr(__builtin__, funcname) \
                    if not funcname.startswith('_') \
                    else getattr(self, funcname)
                value = func(status[prop])
            if value != getattr(self, '_' + prop):
                logging.debug('prop %s changed to %s', prop, value)
                setattr(self, '_' + prop, value)
                changes.add(handler[1])

        if 'track' in changes:
            if self._songid is None:
                self._metadata = Metadata()
            else:
                self._send_cmd(Cmds.CURRENTSONG, sync=True)

        if 'status' in changes:
            if self._state == STATUS_PAUSED:
                self._elapsed.pause()
            elif self._state == STATUS_PLAYING:
                self._elapsed.play()
            else:
                self._elapsed.stop()
        if self._state == STATUS_STOPPED:
            elapsed = 0
        else:
            elapsed = float(status['elapsed']) * 1000
        if self._elapsed.set_time(elapsed):
            changes.add('position')
        if not self._inited:
            # Initializing, do not emit the change signals
            changes = set()
        for change in changes:
            getattr(self, change + '_changed')()

    def _handle_currentsong(self, metadata):
        logging.debug('currentsong: %s', metadata)
        args = {}
        for key in ('title', 'artist', 'album'):
            if key in metadata:
                args[key] = metadata[key]
        if 'time' in metadata:
            args['length'] = int(metadata['time']) * 1000
        if 'track' in metadata:
            args['tracknum'] = int(metadata['track'].split('/')[0])
        self._metadata = Metadata(**args)

    def _parse_status(self, value):
        status_map = {
            'play': STATUS_PLAYING,
            'pause': STATUS_PAUSED,
            'stop': STATUS_STOPPED,
        }
        if value not in status_map:
            raise RuntimeError('Unknown status ' + value)
        return status_map[value]

    def _handle_replay_gain_status(self, status):
        pass

    def _handle_nothing(self, *args):
        pass

    def handle_changes(self, changes):
        cmds = set()
        for change in changes:
            if change in self.CHANGE_CMDS:
                for cmd in self.CHANGE_CMDS[change]:
                    cmds.add(cmd)
        logging.debug('changes: %s', changes)
        logging.debug('cmds: %s', cmds)
        for cmd in cmds:
            self._send_cmd(cmd)

    def get_status(self):
        return self._state

    def get_metadata(self):
        return self._metadata

    def get_position(self):
        return self._elapsed.time

    def get_caps(self):
        return set([CAPS_PLAY, CAPS_PAUSE, CAPS_NEXT, CAPS_PREV, CAPS_SEEK])

    def get_repeat(self):
        if not self._repeat:
            return REPEAT_NONE
        if not self._single:
            return REPEAT_ALL
        return REPEAT_TRACK

    def set_repeat(self, mode):
        repeat_mode_map = {
            REPEAT_NONE: (0, 0),
            REPEAT_TRACK: (1, 1),
            REPEAT_ALL: (1, 0),
        }
        if mode not in repeat_mode_map:
            raise ValueError('Unknown repeat mode: %s', mode)
        self._repeat = repeat_mode_map[mode][0]
        self._single = repeat_mode_map[mode][1]
        self._send_cmd(Cmds.REPEAT, self._repeat)
        self._send_cmd(Cmds.SINGLE, self._single)

    def get_shuffle(self):
        return bool(self._random)

    def set_shuffle(self, shuffle):
        self._random = 1 if shuffle else 0
        self._send_cmd(Cmds.RANDOM, self._random)

    def play(self):
        if self._state == STATUS_PAUSED:
            self._send_cmd(Cmds.PAUSE, 0)
        elif self._state == STATUS_STOPPED:
            self._send_cmd(Cmds.PLAY)

    def pause(self):
        self._send_cmd(Cmds.PAUSE, 1)

    def stop(self):
        self._send_cmd(Cmds.STOP)

    def prev(self):
        self._send_cmd(Cmds.PREVIOUS)

    def next(self):
        self._send_cmd(Cmds.NEXT)

    def set_position(self, pos):
        self._send_cmd(Cmds.SEEK, self._songid, int(pos / 1000))

    def debug_info(self):
        ret = dbus.Dictionary(signature='sv')
        ret.update({
            'state': self._state,
            'metadata': self._metadata.to_mpris1(),
            'repeat': self._repeat,
            'single': self._single,
            'position': self.get_position()
        })
        return ret