]> kaliko git repositories - python-musicpdaio.git/commitdiff
Update documentation
authorkaliko <kaliko@azylum.org>
Sat, 9 Mar 2024 14:39:11 +0000 (15:39 +0100)
committerkaliko <kaliko@azylum.org>
Sat, 9 Mar 2024 14:39:11 +0000 (15:39 +0100)
doc/extract_supported_commands.py [new file with mode: 0644]
doc/make.bat [new file with mode: 0644]
doc/source/changelog.rst [new file with mode: 0644]
doc/source/commands.rst [new file with mode: 0644]
doc/source/explanations.rst
doc/source/index.rst
doc/source/reference.rst
doc/source/tutorial.rst
doc/source/tutorial/mpdaio [deleted symlink]
doc/source/tutorial/tutorial-00.py
doc/source/tutorial/tutorial-01.py

diff --git a/doc/extract_supported_commands.py b/doc/extract_supported_commands.py
new file mode 100644 (file)
index 0000000..d6a7283
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/python3
+import re
+import sys
+
+START = 'self._commands = {'
+END = '}'
+
+def find_start(fd):
+    line = fd.readline()
+    while START not in line:
+        line = fd.readline()
+        if not line:
+            break
+    if not line:
+        print('Reach end of file!', file=sys.stderr)
+        sys.exit(1)
+
+
+def main():
+    with open('mpdaio/client.py', 'r', encoding='utf-8') as fd:
+        # fast forward to find self._commands
+        find_start(fd)
+        cmd_patt = '"(?P<command>.*)":'
+        tit_patt = '# ?(?P<title>.*)'
+        cmd_regex = re.compile(cmd_patt)
+        tit_regex = re.compile(tit_patt)
+        # Now extract supported commands
+        line = 'foo'
+        while line and END not in line:
+            line = fd.readline()
+            cmd = cmd_regex.search(line)
+            tit = tit_regex.search(line)
+            if tit:
+                print(f'\n{tit[1]}')
+                print('^'*len(tit[1]))
+            if cmd:
+                print(f'* {cmd[1]}')
+
+
+if __name__ == '__main__':
+    main()
diff --git a/doc/make.bat b/doc/make.bat
new file mode 100644 (file)
index 0000000..747ffb7
--- /dev/null
@@ -0,0 +1,35 @@
+@ECHO OFF\r
+\r
+pushd %~dp0\r
+\r
+REM Command file for Sphinx documentation\r
+\r
+if "%SPHINXBUILD%" == "" (\r
+       set SPHINXBUILD=sphinx-build\r
+)\r
+set SOURCEDIR=source\r
+set BUILDDIR=build\r
+\r
+%SPHINXBUILD% >NUL 2>NUL\r
+if errorlevel 9009 (\r
+       echo.\r
+       echo.The 'sphinx-build' command was not found. Make sure you have Sphinx\r
+       echo.installed, then set the SPHINXBUILD environment variable to point\r
+       echo.to the full path of the 'sphinx-build' executable. Alternatively you\r
+       echo.may add the Sphinx directory to PATH.\r
+       echo.\r
+       echo.If you don't have Sphinx installed, grab it from\r
+       echo.https://www.sphinx-doc.org/\r
+       exit /b 1\r
+)\r
+\r
+if "%1" == "" goto help\r
+\r
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%\r
+goto end\r
+\r
+:help\r
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%\r
+\r
+:end\r
+popd\r
diff --git a/doc/source/changelog.rst b/doc/source/changelog.rst
new file mode 100644 (file)
index 0000000..c39c502
--- /dev/null
@@ -0,0 +1,10 @@
+Changelog
+=========
+
+`Semantic Versioning`_. is used.
+
+Unreleased
+----------
+
+
+.. _Semantic Versioning: https://semver.org/spec/v2.0.0.html
diff --git a/doc/source/commands.rst b/doc/source/commands.rst
new file mode 100644 (file)
index 0000000..3e29512
--- /dev/null
@@ -0,0 +1,168 @@
+
+Status Commands
+^^^^^^^^^^^^^^^
+
+* clearerror
+* currentsong
+* idle
+* noidle
+* status
+* stats
+
+Playback Option Commands
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+* consume
+* crossfade
+* mixrampdb
+* mixrampdelay
+* random
+* repeat
+* setvol
+* getvol
+* single
+* replay_gain_mode
+* replay_gain_status
+* volume
+
+Playback Control Commands
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+* next
+* pause
+* play
+* playid
+* previous
+* seek
+* seekid
+* seekcur
+* stop
+
+Queue Commands
+^^^^^^^^^^^^^^
+
+* add
+* addid
+* clear
+* delete
+* deleteid
+* move
+* moveid
+* playlist
+* playlistfind
+* playlistid
+* playlistinfo
+* playlistsearch
+* plchanges
+* plchangesposid
+* prio
+* prioid
+* rangeid
+* shuffle
+* swap
+* swapid
+* addtagid
+* cleartagid
+
+Stored Playlist Commands
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+* listplaylist
+* listplaylistinfo
+* listplaylists
+* load
+* playlistadd
+* playlistclear
+* playlistdelete
+* playlistmove
+* rename
+* rm
+* save
+
+Database Commands
+^^^^^^^^^^^^^^^^^
+
+* albumart
+* count
+* getfingerprint
+* find
+* findadd
+* list
+* listall
+* listallinfo
+* listfiles
+* lsinfo
+* readcomments
+* readpicture
+* search
+* searchadd
+* searchaddpl
+* update
+* rescan
+
+Mounts and neighbors
+^^^^^^^^^^^^^^^^^^^^
+
+* mount
+* unmount
+* listmounts
+* listneighbors
+
+Sticker Commands
+^^^^^^^^^^^^^^^^
+
+* sticker get
+* sticker set
+* sticker delete
+* sticker list
+* sticker find
+
+Connection Commands
+^^^^^^^^^^^^^^^^^^^
+
+* close
+* kill
+* password
+* ping
+* binarylimit
+* tagtypes
+* tagtypes disable
+* tagtypes enable
+* tagtypes clear
+* tagtypes all
+
+Partition Commands
+^^^^^^^^^^^^^^^^^^
+
+* partition
+* listpartitions
+* newpartition
+* delpartition
+* moveoutput
+
+Audio Output Commands
+^^^^^^^^^^^^^^^^^^^^^
+
+* disableoutput
+* enableoutput
+* toggleoutput
+* outputs
+* outputset
+
+Reflection Commands
+^^^^^^^^^^^^^^^^^^^
+
+* config
+* commands
+* notcommands
+* urlhandlers
+* decoders
+
+Client to Client
+^^^^^^^^^^^^^^^^
+
+* subscribe
+* unsubscribe
+* channels
+* readmessages
+* sendmessage
index 48724bfeb60c46b24f5f5dd653252a2fa2f50877..15155a0df07dd35d6ac35a541ecaa3cace63394e 100644 (file)
@@ -18,8 +18,8 @@ Should I use it?
 ----------------
 
  * If you need a plain MPD client to manage you MPD server, then stick with
-   no-ansynio module python-musicpd_
- * If you're building a interactive client, concurrent access to MPD or plugin
+   non-asyncio module python-musicpd_
+ * If you're building an interactive client, concurrent access to MPD or plugin
    into another asyncio project then use musicpdaio.
 
 
@@ -63,15 +63,32 @@ learn how to call commands and what kind of arguments they expect.
 
 Some examples are provided for the most common cases, see :ref:`tutorial`.
 
-For a list of currently supported commands in this python module see
-:ref:`commands`.
-
 **musicpdaio** tries to come with sane defaults, then running
-:py:class:`mpdaio.MPDClient` with no explicit argument will try defaults values
-to connect to MPD. Cf. :ref:`reference` for more about defaults.
+:py:class:`mpdaio.MPDClient` with no explicit argument will try default values
+to connect to MPD. Cf. :ref:`reference` for more about
+:ref:`defaults<default_settings>`.
+
+.. _socket_connections:
+.. index:: pair: connection pool; socket
+
+Socket connection
+-----------------
 
+**musicpdaio** uses a connection pool internally to keep already opened socket
+and reuse it.
+
+When first instantiated :py:class:`mpdaio.MPDClient` comes with an empty pool,
+when the first MPD command is called a connection is opened, saved and
+potentially reused later. In case a concurrent MPD command is called while the
+connection is still in use a new connection is made and kept in the pool.
+
+.. code-block:: python
 
-.. _environment_variables:
+   client = mpdaio.MPDClient()
+   client.connections    # Returns an empty list: []
+   client.version        # Returns empty string: ''
+   await client.ping()   # A connection is made and kept open
+   client.connections    # Returns a list; [Connection<example.org:6600>]
 
 
 .. _snake case: https://en.wikipedia.org/wiki/Snake_case
index 0c204081a54a6c0fdb11b21f5025c40cb5e7ab06..5b5a51bee77123d05f4b8b838f6495a83bccbc41 100644 (file)
@@ -10,9 +10,13 @@ have some specific action to perform or goal to achieve.
    :maxdepth: 2
 
    tutorial
+
    explanations
+
    reference
 
+   changelog
+
 
 
 Indices and tables
index f71444ce1682f459528e5c1cce03cf6758761bd8..1459b922ef7aee6b1b57fc489d635136ff11aaa7 100644 (file)
@@ -3,6 +3,8 @@
 Reference
 =========
 
+.. _environment_variables:
+
 Environment variables
 ---------------------
 
@@ -39,15 +41,15 @@ Default host:
  * else set host to ``localhost``
 
 Default port:
- * use :envvar:`MPD_PORT` environment variable is set
+ * use :envvar:`MPD_PORT` environment variable if set
  * else use ``6600``
 
 Default timeout:
- * use :envvar:`MPD_TIMEOUT` is set
- * else use :py:obj:`mpdaio.CONNECTION_TIMEOUT`
+ * use :envvar:`MPD_TIMEOUT` if set
+ * else use :py:obj:`mpdaio.const.CONNECTION_TIMEOUT`
 
 
-Changelog
----------
+Supported commands
+------------------
 
-No release yet
+.. include:: commands.rst
index 31cbde9d51ed4f798c9ec362cbdd236cb28e0822..95e69488c895c9bbe913ff3d1ab99ca36920abbe 100644 (file)
@@ -23,9 +23,68 @@ For now the code is in early development stage. No releases are made.
 Getting started
 ----------------
 
+.. index:: single: command; searchadd
+
+**Connect, clear the queue, add tracks**
+
+.. sourcecode:: python
+
+   import mpdaio
+
+   client = mpdaio.MPDClient()
+   await client.ping()         # Plain connection test
+   print(client.version)       # Prints MPD's protocol version
+   print(await client.clear()) # Clears the current queue
+   # Add all tracks from artist "Amon Tobin"
+   print(await client.searchadd('(Artist == "Amon Tobin")'))
+   await client.play()
+   await client.setvol(60)
+   print(await client.currentsong())
+   await client.close()        # Finally close connection
+
+.. index:: single: command; password
+
+**Using a specific host, port and a password.**
+
+The password is sent when a connection is made, no need to explicitly send the
+password command.
+
+.. sourcecode:: python
+
+   client = mpdaio.MPDClient(host='example.org', port='6601', password='53(237')
+   await client.ping()
+
+**Wrapping some commands in a python script**
 
 .. literalinclude:: tutorial/tutorial-00.py
 
+.. index:: single: command; albumart
+
+**Fetch album art for the given track**
+
+The logic is similar with `readpicture` command.
+
+.. sourcecode:: python
+
+   client = mpdaio.MPDClient()
+   # Looking for cover art in 'Tool/2001-Lateralus/'
+   track = 'Tool/2001-Lateralus/09-Tool - Lateralus.flac'
+   aart = await cli.albumart(track, 0)
+   received = int(aart.get('binary'))
+   size = int(aart.get('size'))
+   with open('/tmp/cover', 'wb') as cover:
+       # aart = {'size': 42, 'binary': 2051, data: bytes(...)}
+       cover.write(aart.get('data'))
+       while received < size:
+           aart = await cli.albumart(track, received)
+           cover.write(aart.get('data'))
+           received += int(aart.get('binary'))
+       if received != size:
+           print('something went wrong')
+   await cli.close()
+
+Cf. `MPD protocol documentation`_ for more binary responses.
+
 
 Concurrency
 -----------
@@ -33,4 +92,5 @@ Concurrency
 .. literalinclude:: tutorial/tutorial-01.py
 
 
+.. _MPD protocol documentation: http://www.musicpd.org/doc/protocol/
 .. vim: spell spelllang=en
diff --git a/doc/source/tutorial/mpdaio b/doc/source/tutorial/mpdaio
deleted file mode 120000 (symlink)
index 7af2e50..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../../../mpdaio
\ No newline at end of file
index dea5826fc9465ba01ceaaf7a6e241393e9ab596a..6445a6e1c8436d82d45ed0cd52e19cd0dfc6cfbb 100644 (file)
@@ -1,7 +1,8 @@
+# mpd-client.py
 import asyncio
 import logging
 
-from mpdaio.client import MPDClient
+from mpdaio import MPDClient
 
 # Configure loggers
 logging.basicConfig(level=logging.INFO, format='%(levelname)-8s %(message)s')
@@ -25,6 +26,7 @@ async def run():
     # The connection is kept open an reused for later commands
     await client.ping()
 
+    # Get player status
     status = await client.status()
     if status.get('state') == 'play':
         current_song_id = status.get('songid')
@@ -37,6 +39,13 @@ async def run():
     else:
         log.info('Not playing')
 
+    # Add all songs form artist "The Doors"
+    await client.searchadd('(Artist == "The Doors")')
+    # Start playing
+    if (await client.status()).get('state') != 'play':
+        await client.play()
+
+
     # Closes any remaining connections to MPD server
     await client.close()
 
index 1ef066c692371e44da3c77ba6ad9a6187c30f6e1..c8197e57596ee1cd2ffdf44771094a59295d1a28 100644 (file)
@@ -1,7 +1,7 @@
 import asyncio
 import logging
 
-from mpdaio.client import MPDClient
+from mpdaio import MPDClient
 
 # Configure loggers
 logging.basicConfig(level=logging.INFO, format='%(levelname)-8s %(message)s')
@@ -11,20 +11,30 @@ log = logging.getLogger('mpdaio.client')
 log.setLevel(logging.DEBUG)
 
 
+async def search(fltr):
+    # Look for and add
+    await client.searchadd(fltr)
+
+
 async def run():
-    # Use defaults to access MPD server
-    client = MPDClient()
 
     # Make an initial connection to MPD server
     # The connection is kept open an reused for later commands
     await client.ping()
-
+    await client.clear()
+    filters = [
+            '(Artist == "Neurosis")',
+            '(Artist == "Isis")',
+            '(Artist == "Cult of Luna")',
+            ]
     # Each task gathered here will run with it's own connection
-    await asyncio.gather(...)
+    await asyncio.gather(*map(search, filters))
 
     # Closes all connections to MPD server
     await client.close()
 
 
 if __name__ == '__main__':
+    # Use defaults to access MPD server
+    client = MPDClient()
     asyncio.run(run())