]> kaliko git repositories - python-musicpd.git/commitdiff
Add examples
authorKaliko Jack <kaliko@azylum.org>
Tue, 6 Feb 2024 17:43:45 +0000 (18:43 +0100)
committerKaliko Jack <kaliko@azylum.org>
Tue, 6 Feb 2024 17:43:45 +0000 (18:43 +0100)
doc/source/examples.rst [new file with mode: 0644]
doc/source/examples/client.py [new file with mode: 0644]
doc/source/examples/connect.py [new file with mode: 0644]
doc/source/examples/connect_host.py [new file with mode: 0644]
doc/source/examples/findadd.py [new file with mode: 0644]
doc/source/examples/playback.py [new file with mode: 0644]
doc/source/index.rst
doc/source/use.rst

diff --git a/doc/source/examples.rst b/doc/source/examples.rst
new file mode 100644 (file)
index 0000000..291344c
--- /dev/null
@@ -0,0 +1,44 @@
+.. SPDX-FileCopyrightText: 2018-2023 kaliko <kaliko@azylum.org>
+.. SPDX-License-Identifier: LGPL-3.0-or-later
+
+.. _examples:
+
+Examples
+========
+
+Plain examples
+--------------
+
+Connect, if playing, get currently playing track, the next one:
+
+.. literalinclude:: examples/connect.py
+   :language: python
+   :linenos:
+
+Connect a specific password protected host:
+
+.. literalinclude:: examples/connect_host.py
+   :language: python
+   :linenos:
+
+Start playing current queue and set the volume:
+
+.. literalinclude:: examples/playback.py
+   :language: python
+   :linenos:
+
+Clear the queue, search artist, queue what's found and play:
+
+.. literalinclude:: examples/findadd.py
+   :language: python
+   :linenos:
+
+Object Oriented example
+-----------------------
+
+A plain client monitoring changes on MPD.
+
+.. literalinclude:: examples/client.py
+   :language: python
+   :linenos:
+
diff --git a/doc/source/examples/client.py b/doc/source/examples/client.py
new file mode 100644 (file)
index 0000000..41ef1bd
--- /dev/null
@@ -0,0 +1,94 @@
+"""Plain client class
+"""
+import logging
+import select
+import sys
+
+import musicpd
+
+
+class MyClient(musicpd.MPDClient):
+    """Plain client inheriting from MPDClient"""
+
+    def __init__(self):
+        # Set logging to debug level
+        logging.basicConfig(level=logging.DEBUG,
+                            format='%(levelname)-8s %(message)s')
+        self.log = logging.getLogger(__name__)
+        super().__init__()
+        # Set host/port/password after init to overrides defaults
+        # self.host = 'example.org'
+        # self.port = 4242
+        # self.pwd = 'secret'
+
+    def connect(self):
+        """Overriding explicitly MPDClient.connect()"""
+        try:
+            super().connect(host=self.host, port=self.port)
+            if hasattr(self, 'pwd') and self.pwd:
+                self.password(self.pwd)
+        except musicpd.ConnectionError as err:
+            # Catch socket error
+            self.log.error('Failed to connect: %s', err)
+            sys.exit(42)
+
+    def _wait_for_changes(self, callback):
+        select_timeout = 10  # second
+        while True:
+            self.send_idle()  # use send_ API to avoid blocking on read
+            _read, _, _ = select.select([self], [], [], select_timeout)
+            if _read:  # tries to read response
+                ret = self.fetch_idle()
+                # do something
+                callback(ret)
+            else:  # cancels idle
+                self.noidle()
+
+    def callback(self, *args):
+        """Method launch on MPD event, cf. monitor method"""
+        self.log.info('%s', args)
+
+    def monitor(self):
+        """Continuously monitor MPD activity.
+        Launch callback method on event.
+        """
+        try:
+            self._wait_for_changes(self.callback)
+        except (OSError, musicpd.MPDError) as err:
+            self.log.error('%s: Something went wrong: %s',
+                           type(err).__name__, err)
+
+if __name__ == '__main__':
+    cli = MyClient()
+    # You can overrides host here or in init
+    #cli.host = 'example.org'
+    # Connect MPD server
+    try:
+        cli.connect()
+    except musicpd.ConnectionError as err:
+        cli.log.error(err)
+
+    # Monitor MPD changes, blocking/timeout idle approach
+    try:
+        cli.socket_timeout =  20 # seconds
+        ret = cli.idle()
+        cli.log.info('Leaving idle, got: %s', ret)
+    except TimeoutError as err:
+        cli.log.info('Nothing occured the last %ss', cli.socket_timeout)
+
+    # Reset connection
+    try:
+        cli.socket_timeout = None
+        cli.disconnect()
+        cli.connect()
+    except musicpd.ConnectionError as err:
+        cli.log.error(err)
+
+    # Monitor MPD changes, non blocking idle approach
+    try:
+        cli.monitor()
+    except KeyboardInterrupt as err:
+        cli.log.info(type(err).__name__)
+        cli.send_noidle()
+        cli.disconnect()
+
diff --git a/doc/source/examples/connect.py b/doc/source/examples/connect.py
new file mode 100644 (file)
index 0000000..0c74448
--- /dev/null
@@ -0,0 +1,30 @@
+import musicpd
+import logging
+
+import musicpd
+
+# Set logging to debug level
+# it should log messages showing where defaults come from
+logging.basicConfig(level=logging.DEBUG, format='%(levelname)-8s %(message)s')
+log = logging.getLogger()
+
+client = musicpd.MPDClient()
+# use MPD_HOST/MPD_PORT env var if set else
+# test ${XDG_RUNTIME_DIR}/mpd/socket for existence
+# fallback to localhost:6600
+# connect support host/port argument as well
+client.connect()
+
+status = client.status()
+if status.get('state') == 'play':
+    current_song_id = status.get('songid')
+    current_song = client.playlistid(current_song_id)[0]
+    log.info(f'Playing   : {current_song.get("file")}')
+    next_song_id = status.get('nextsongid', None)
+    if next_song_id:
+        next_song = client.playlistid(next_song_id)[0]
+        log.info(f'Next song : {next_song.get("file")}')
+else:
+    log.info('Not playing')
+
+client.disconnect()
diff --git a/doc/source/examples/connect_host.py b/doc/source/examples/connect_host.py
new file mode 100644 (file)
index 0000000..a7bdccc
--- /dev/null
@@ -0,0 +1,17 @@
+import sys
+import logging
+
+import musicpd
+
+# Set logging to debug level
+logging.basicConfig(level=logging.DEBUG, format='%(levelname)-8s %(message)s')
+
+client = musicpd.MPDClient()
+try:
+    client.connect(host='example.lan')
+    client.password('secret')
+    client.status()
+except musicpd.MPDError as err:
+    print(f'An error occured: {err}')
+finally:
+    client.disconnect()
diff --git a/doc/source/examples/findadd.py b/doc/source/examples/findadd.py
new file mode 100644 (file)
index 0000000..922cae1
--- /dev/null
@@ -0,0 +1,8 @@
+import musicpd
+
+# Using a context manager
+# (use env var if you need to override default host)
+with musicpd.MPDClient() as client:
+    client.clear()
+    client.findadd("(artist == 'Monkey3')")
+    client.play()
diff --git a/doc/source/examples/playback.py b/doc/source/examples/playback.py
new file mode 100644 (file)
index 0000000..ce7eb78
--- /dev/null
@@ -0,0 +1,7 @@
+import musicpd
+
+# Using a context manager
+# (use env var if you need to override default host)
+with musicpd.MPDClient() as client:
+    client.play()
+    client.setvol('80')
index 9b4b43d15ed725808f0da536a618508dfff4fda2..d16644bf2488e33129453af7f60fe1c7f222996a 100644 (file)
@@ -69,6 +69,7 @@ Contents
    use.rst
    doc.rst
    commands.rst
+   examples.rst
    contribute.rst
 
 
index 106ce90984cb1383437781081e1a72f672bd65e5..702968425fa802b82993f0b4f0fe1d28a2f2bade 100644 (file)
@@ -36,10 +36,16 @@ strings. In the example above, an integer can be used as argument for the
 written to the socket. To avoid confusion use regular string instead of relying
 on object string representation.
 
-:py:class:`musicpd.MPDClient` methods returns different kinds of objects depending on the command. Could be :py:obj:`None`, a single object as a :py:obj:`str` or a :py:obj:`dict`, a list of :py:obj:`dict`.
+:py:class:`musicpd.MPDClient` methods returns different kinds of objects
+depending on the command. Could be :py:obj:`None`, a single object as a
+:py:obj:`str` or a :py:obj:`dict`, a list of :py:obj:`dict`.
 
-For more about the protocol and MPD commands see the `MPD protocol
-documentation`_.
+Then :py:class:`musicpd.MPDClient` **methods signatures** are not hard coded
+within this module since the protocol is handled on the server side. Please
+refer to the protocol and MPD commands in `MPD protocol documentation`_ to
+learn how to call commands and what kind of arguments they expect.
+
+Some examples are provided for the most common cases, see :ref:`examples`.
 
 For a list of currently supported commands in this python module see
 :ref:`commands`.