]> 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
    use.rst
    doc.rst
    commands.rst
+   examples.rst
    contribute.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.
 
 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`.
 
 For a list of currently supported commands in this python module see
 :ref:`commands`.