Examples

Plain examples

Connect, if playing, get currently playing track, the next one:

 1import logging
 2
 3import musicpd
 4
 5# Set logging to debug level
 6# it should log messages showing where defaults come from
 7logging.basicConfig(level=logging.DEBUG, format='%(levelname)-8s %(message)s')
 8log = logging.getLogger()
 9
10client = musicpd.MPDClient()
11# use MPD_HOST/MPD_PORT env var if set else
12# test ${XDG_RUNTIME_DIR}/mpd/socket for existence
13# fallback to localhost:6600
14# connect support host/port argument as well
15client.connect()
16
17status = client.status()
18if status.get('state') == 'play':
19    current_song_id = status.get('songid')
20    current_song = client.playlistid(current_song_id)[0]
21    log.info(f'Playing   : {current_song.get("file")}')
22    next_song_id = status.get('nextsongid', None)
23    if next_song_id:
24        next_song = client.playlistid(next_song_id)[0]
25        log.info(f'Next song : {next_song.get("file")}')
26else:
27    log.info('Not playing')
28
29client.disconnect()

Connect a specific password protected host:

 1import sys
 2import logging
 3
 4import musicpd
 5
 6# Set logging to debug level
 7logging.basicConfig(level=logging.DEBUG, format='%(levelname)-8s %(message)s')
 8
 9client = musicpd.MPDClient()
10try:
11    client.connect(host='example.lan')
12    client.password('secret')
13    client.status()
14except musicpd.MPDError as err:
15    print(f'An error occured: {err}')
16finally:
17    client.disconnect()

Start playing current queue and set the volume:

1import musicpd
2
3# Using a context manager
4# (use env var if you need to override default host)
5with musicpd.MPDClient() as client:
6    client.play()
7    client.setvol('80')

Clear the queue, search artist, queue what’s found and play:

1import musicpd
2
3# Using a context manager
4# (use env var if you need to override default host)
5with musicpd.MPDClient() as client:
6    client.clear()
7    client.findadd("(artist == 'Monkey3')")
8    client.play()

Object Oriented example

A plain client monitoring changes on MPD.

 1"""Plain client class
 2"""
 3import logging
 4import select
 5import sys
 6
 7import musicpd
 8
 9
10class MyClient(musicpd.MPDClient):
11    """Plain client inheriting from MPDClient"""
12
13    def __init__(self):
14        # Set logging to debug level
15        logging.basicConfig(level=logging.DEBUG,
16                            format='%(levelname)-8s %(module)-8s %(message)s')
17        self.log = logging.getLogger(__name__)
18        super().__init__()
19        # Set host/port/password after init to overrides defaults
20        # self.host = 'example.org'
21        # self.port = 4242
22        # self.pwd = 'secret'
23
24    def connect(self):
25        """Overriding explicitly MPDClient.connect()"""
26        try:
27            super().connect(host=self.host, port=self.port)
28            if hasattr(self, 'pwd') and self.pwd:
29                self.password(self.pwd)
30        except musicpd.ConnectionError as err:
31            # Catch socket error
32            self.log.error('Failed to connect: %s', err)
33            sys.exit(42)
34
35    def _wait_for_changes(self, callback):
36        select_timeout = 10  # second
37        while True:
38            self.send_idle()  # use send_ API to avoid blocking on read
39            _read, _, _ = select.select([self], [], [], select_timeout)
40            if _read:  # tries to read response
41                ret = self.fetch_idle()
42                # do something
43                callback(ret)
44            else:  # cancels idle
45                self.noidle()
46
47    def callback(self, *args):
48        """Method launch on MPD event, cf. monitor method"""
49        self.log.info('%s', args)
50
51    def monitor(self):
52        """Continuously monitor MPD activity.
53        Launch callback method on event.
54        """
55        try:
56            self._wait_for_changes(self.callback)
57        except (OSError, musicpd.MPDError) as err:
58            self.log.error('%s: Something went wrong: %s',
59                           type(err).__name__, err)
60
61if __name__ == '__main__':
62    cli = MyClient()
63    # You can overrides host here or in init
64    #cli.host = 'example.org'
65    # Connect MPD server
66    try:
67        cli.connect()
68    except musicpd.ConnectionError as err:
69        cli.log.error(err)
70
71    # Monitor MPD changes, blocking/timeout idle approach
72    try:
73        cli.socket_timeout =  20 # seconds
74        ret = cli.idle()
75        cli.log.info('Leaving idle, got: %s', ret)
76    except TimeoutError as err:
77        cli.log.info('Nothing occured the last %ss', cli.socket_timeout)
78
79    # Reset connection
80    try:
81        cli.socket_timeout = None
82        cli.disconnect()
83        cli.connect()
84    except musicpd.ConnectionError as err:
85        cli.log.error(err)
86
87    # Monitor MPD changes, non blocking idle approach
88    try:
89        cli.monitor()
90    except KeyboardInterrupt as err:
91        cli.log.info(type(err).__name__)
92        cli.send_noidle()
93        cli.disconnect()
94

Dealing with Exceptions

Musicpd module will raise it’s own MPDError exceptions and python OSError. Then you can wrap OSError in MPDError exceptions to have to deal with a single type of exceptions in your code:

 1"""client class dealing with all Exceptions
 2"""
 3import logging
 4
 5import musicpd
 6
 7
 8# Wrap Exception decorator
 9def wrapext(func):
10    """Decorator to wrap errors in musicpd.MPDError"""
11    errors=(OSError, TimeoutError)
12    into = musicpd.MPDError
13    def w_func(*args, **kwargs):
14        try:
15            return func(*args, **kwargs)
16        except errors as err:
17            strerr = str(err)
18            if hasattr(err, 'strerror'):
19                if err.strerror:
20                    strerr = err.strerror
21            raise into(strerr) from err
22    return w_func
23
24
25class MyClient(musicpd.MPDClient):
26    """Plain client inheriting from MPDClient"""
27
28    def __init__(self):
29        # Set logging to debug level
30        logging.basicConfig(level=logging.DEBUG,
31                format='%(levelname)-8s %(module)-10s %(message)s')
32        self.log = logging.getLogger(__name__)
33        super().__init__()
34
35    @wrapext
36    def __getattr__(self, cmd):
37        """Wrapper around MPDClient calls for abstract overriding"""
38        self.log.debug('cmd: %s', cmd)
39        return super().__getattr__(cmd)
40
41
42if __name__ == '__main__':
43    cli = MyClient()
44    # You can overrides host here or in init
45    #cli.host = 'example.org'
46    # Connect MPD server
47    try:
48        cli.connect()
49        cli.currentsong()
50        cli.stats()
51    except musicpd.MPDError as error:
52        cli.log.fatal(error)
53    finally:
54        cli.log.info('Disconnecting')
55        try:
56            # Tries to close the socket anyway
57            cli.disconnect()
58        except OSError:
59            pass