From 883318e9f96462c2f264f5dd70aee567dcda7f3c Mon Sep 17 00:00:00 2001 From: "Jewelle L. Mello" <47869149+jlmello57@users.noreply.github.com> Date: Tue, 30 May 2023 20:40:15 -0700 Subject: [PATCH] Set config directory according to runtime platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit changes the definition of the persistent state and configuration files to derive from the output of [platform.system()][1], rather than being fixed to an eponymous, dot-prefixed directory in the top level of the user's `$HOME`. Furthermore, on POSIX-compliant platforms it tests for the presence of the XDG_CONFIG_HOME environment variable and establishes the config directory there, with a fallback to the `$HOME/.config` directory as defined in the [XDG Base Directory Specification][2]. On Microsoft Windows® systems, it places the directory inside the path defined by the `%LOCALAPPDATA%` environment variable, which is the vendor-specified path for all machine- specific application data belonging to the active user. On all other platforms the former behavior is retained. Several individual definitions of this path were consolidated into the `SOCO_CLI_DIR` constant already present in the file, which itself was relocated along with the attendant `_confirm_soco_cli_dir` method earlier in the file, nearer to the other defined constants. Include updated documentation sections in README.md that relate to where configuration and data are stored on various platforms, and what to delete for a complete uninstall. Validate markup syntax using NodeJS markdownlint module, and supply syntax- highlighting keywords for fenced code blocks a la github-linguist. [1]: https://docs.python.org/3/library/platform.html#platform.system [2]: https://specifications.freedesktop.org/basedir-spec/latest/index.html --- README.md | 480 ++++++++++++++++++++++--------------------- soco_cli/aliases.py | 57 +++-- soco_cli/speakers.py | 88 +++++--- soco_cli/utils.py | 190 +++++++++++------ 4 files changed, 461 insertions(+), 354 deletions(-) diff --git a/README.md b/README.md index 2b1eb0d..a1bb577 100644 --- a/README.md +++ b/README.md @@ -1,85 +1,84 @@ # SoCo-CLI: Control Sonos from the Command Line -* [SoCo-CLI: Control Sonos from the Command Line](#soco-cli-control-sonos-from-the-command-line) - * [Overview](#overview) - * [Supported Environments](#supported-environments) - * [Installation](#installation) - * [User Guide](#user-guide) - * [The sonos Command](#the-sonos-command) - * [Speaker Discovery by Name](#speaker-discovery-by-name) - * [Simple Usage Examples](#simple-usage-examples) - * [The SPKR Environment Variable](#the-spkr-environment-variable) - * [Using Shell Aliases](#using-shell-aliases) - * [Options for the sonos Command](#options-for-the-sonos-command) - * [Firewall Rules](#firewall-rules) - * [Operating on All Speakers: Using _all_](#operating-on-all-speakers-using-_all_) - * [Guidelines on Playing Content](#guidelines-on-playing-content) - * [Radio Stations](#radio-stations) - * [Single Tracks](#single-tracks) - * [Albums and Playlists](#albums-and-playlists) - * [Audio Files on the Local Filesystem](#audio-files-on-the-local-filesystem) - * [Local Playlists (M3U Files)](#local-playlists-m3u-files) - * [Directories of Audio Files](#directories-of-audio-files) - * [Spotify, Tidal, Deezer, and Apple Music Share Links](#spotify-tidal-deezer-and-apple-music-share-links) - * [Complete List of Available Actions](#complete-list-of-available-actions) - * [Volume and EQ Control](#volume-and-eq-control) - * [Playback Control](#playback-control) - * [Queue Actions](#queue-actions) - * [Favourites and Playlists](#favourites-and-playlists) - * [TuneIn Radio Station Favourites](#tunein-radio-station-favourites) - * [Grouping and Stereo Pairing](#grouping-and-stereo-pairing) - * [Alarms](#alarms) - * [Music Library Search Functions](#music-library-search-functions) - * [Speaker and Sonos System Information](#speaker-and-sonos-system-information) - * [Multiple Sequential Commands](#multiple-sequential-commands) - * [Chaining Commands Using the : Separator](#chaining-commands-using-the--separator) - * [Inserting Delays: wait and wait_until](#inserting-delays-wait-and-wait_until) - * [Waiting Until Playback has Started/Stopped: wait_start, wait_stop and wait_end_track](#waiting-until-playback-has-startedstopped-wait_start-wait_stop-and-wait_end_track) - * [The wait_stopped_for <duration> Action](#the-wait_stopped_for-duration-action) - * [Repeating Commands: The loop Actions](#repeating-commands-the-loop-actions) - * [Conditional Command Execution](#conditional-command-execution) - * [Interactive Shell Mode](#interactive-shell-mode) - * [Description](#description) - * [Usage](#usage) - * [Shell History and Auto-Completion](#shell-history-and-auto-completion) - * [Shell Aliases](#shell-aliases) - * [Push and Pop](#push-and-pop) - * [Alias Subroutines](#alias-subroutines) - * [Alias Arguments](#alias-arguments) - * [Saving and Loading Aliases](#saving-and-loading-aliases) - * [Single Keystroke Mode](#single-keystroke-mode) - * [Cached Discovery](#cached-discovery) - * [Usage](#usage-1) - * [Speaker Naming](#speaker-naming) - * [Refreshing the Local Speaker List](#refreshing-the-local-speaker-list) - * [Discovery Options](#discovery-options) - * [The sonos-discover Command](#the-sonos-discover-command) - * [Options for the sonos-discover Command](#options-for-the-sonos-discover-command) - * [The SoCo-CLI HTTP API Server](#the-soco-cli-http-api-server) - * [Server Usage](#server-usage) - * [Using the Local Speaker Cache](#using-the-local-speaker-cache) - * [HTTP Request Structure](#http-request-structure) - * [Return Values](#return-values) - * [Macros: Defining Custom HTTP API Server Actions](#macros-defining-custom-http-api-server-actions) - * [Macro Definition and Usage](#macro-definition-and-usage) - * [Macro Arguments](#macro-arguments) - * [Troubleshooting](#troubleshooting) - * [Specifying the Macro Definition File](#specifying-the-macro-definition-file) - * [Reloading the Macro Definition File](#reloading-the-macro-definition-file) - * [Return Values](#return-values-1) - * [Listing Macros](#listing-macros) - * [Listing Speakers](#listing-speakers) - * [Rediscovering Speakers](#rediscovering-speakers) - * [Inspecting the HTTP API](#inspecting-the-http-api) - * [Using SoCo-CLI as a Python Library](#using-soco-cli-as-a-python-library) - * [Importing the API](#importing-the-api) - * [Using the API](#using-the-api) - * [Convenience Functions](#convenience-functions) - * [Known Issues](#known-issues) - * [Uninstalling](#uninstalling) - * [Acknowledgments](#acknowledgments) - * [Resources](#resources) +- [SoCo-CLI: Control Sonos from the Command Line](#soco-cli-control-sonos-from-the-command-line) + - [Overview](#overview) + - [Supported Environments](#supported-environments) + - [Installation](#installation) + - [User Guide](#user-guide) + - [The sonos Command](#the-sonos-command) + - [Speaker Discovery by Name](#speaker-discovery-by-name) + - [Simple Usage Examples](#simple-usage-examples) + - [The SPKR Environment Variable](#the-spkr-environment-variable) + - [Using Shell Aliases](#using-shell-aliases) + - [Options for the sonos Command](#options-for-the-sonos-command) + - [Firewall Rules](#firewall-rules) + - [Operating on All Speakers: Using _all_](#operating-on-all-speakers-using-_all_) + - [Guidelines on Playing Content](#guidelines-on-playing-content) + - [Radio Stations](#radio-stations) + - [Single Tracks](#single-tracks) + - [Albums and Playlists](#albums-and-playlists) + - [Audio Files on the Local Filesystem](#audio-files-on-the-local-filesystem) + - [Local Playlists (M3U Files)](#local-playlists-m3u-files) + - [Directories of Audio Files](#directories-of-audio-files) + - [Spotify, Tidal, Deezer, and Apple Music Share Links](#spotify-tidal-deezer-and-apple-music-share-links) + - [Complete List of Available Actions](#complete-list-of-available-actions) + - [Volume and EQ Control](#volume-and-eq-control) + - [Playback Control](#playback-control) + - [Queue Actions](#queue-actions) + - [Favourites and Playlists](#favourites-and-playlists) + - [TuneIn Radio Station Favourites](#tunein-radio-station-favourites) + - [Grouping and Stereo Pairing](#grouping-and-stereo-pairing) + - [Alarms](#alarms) + - [Music Library Search Functions](#music-library-search-functions) + - [Speaker and Sonos System Information](#speaker-and-sonos-system-information) + - [Multiple Sequential Commands](#multiple-sequential-commands) + - [Chaining Commands Using the : Separator](#chaining-commands-using-the--separator) + - [Inserting Delays: wait and wait_until](#inserting-delays-wait-and-wait_until) + - [Waiting Until Playback has Started/Stopped: wait_start, wait_stop and wait_end_track](#waiting-until-playback-has-startedstopped-wait_start-wait_stop-and-wait_end_track) + - [The wait_stopped_for <duration> Action](#the-wait_stopped_for-duration-action) + - [Repeating Commands: The loop Actions](#repeating-commands-the-loop-actions) + - [Conditional Command Execution](#conditional-command-execution) + - [Interactive Shell Mode](#interactive-shell-mode) + - [Description](#description) + - [Usage](#usage) + - [Shell History and Auto-Completion](#shell-history-and-auto-completion) + - [Shell Aliases](#shell-aliases) + - [Push and Pop](#push-and-pop) + - [Alias Subroutines](#alias-subroutines) + - [Alias Arguments](#alias-arguments) + - [Saving and Loading Aliases](#saving-and-loading-aliases) + - [Single Keystroke Mode](#single-keystroke-mode) + - [Cached Discovery](#cached-discovery) + - [How to Use](#how-to-use) + - [Speaker Naming](#speaker-naming) + - [Refreshing the Local Speaker List](#refreshing-the-local-speaker-list) + - [Discovery Options](#discovery-options) + - [The sonos-discover Command](#the-sonos-discover-command) + - [Options for the sonos-discover Command](#options-for-the-sonos-discover-command) + - [The SoCo-CLI HTTP API Server](#the-soco-cli-http-api-server) + - [Server Usage](#server-usage) + - [Using the Local Speaker Cache](#using-the-local-speaker-cache) + - [HTTP Request Structure](#http-request-structure) + - [Return Values](#return-values) + - [Macros: Defining Custom HTTP API Server Actions](#macros-defining-custom-http-api-server-actions) + - [Macro Definition and Usage](#macro-definition-and-usage) + - [Macro Arguments](#macro-arguments) + - [Troubleshooting](#troubleshooting) + - [Specifying the Macro Definition File](#specifying-the-macro-definition-file) + - [Reloading the Macro Definition File](#reloading-the-macro-definition-file) + - [Macro Return Values](#macro-return-values) + - [Listing Macros](#listing-macros) + - [Listing Speakers](#listing-speakers) + - [Rediscovering Speakers](#rediscovering-speakers) + - [Inspecting the HTTP API](#inspecting-the-http-api) + - [Using SoCo-CLI as a Python Library](#using-soco-cli-as-a-python-library) + - [Importing the API](#importing-the-api) + - [Using the API](#using-the-api) + - [Convenience Functions](#convenience-functions) + - [Known Issues](#known-issues) + - [Uninstalling](#uninstalling) + - [Acknowledgments](#acknowledgments) @@ -87,7 +86,7 @@ ## Overview -SoCo-CLI is a powerful command line wrapper for the popular Python SoCo library [1], for controlling Sonos systems. SoCo-CLI is written entirely in Python and is portable across platforms. +SoCo-CLI is a powerful command line wrapper for the popular [Python SoCo library][1], for controlling Sonos systems. SoCo-CLI is written entirely in Python and is portable across platforms. A simple `sonos` command provides easy control over a huge range of speaker functions, including playback, volume, groups, EQ settings, sleep timers, alarms, speaker settings, the playback queue, etc. Multiple commands can be run in sequence, including the ability to insert delays between commands, to wait for speakers to stop or start playing, and to create repeated action sequences using loops. Audio files from the local filesystem can be played directly on Sonos. @@ -109,7 +108,7 @@ SoCo-CLI can also run as a simple [HTTP API server](#the-soco-cli-http-api-serve ## Installation -Install the latest version from PyPI [2] using **`pip install -U soco-cli`**. +Install the latest version from the [Python Package Index (PyPI)][2] using **`pip install -U soco-cli`**. Soco-CLI can also be easily installed as a self-contained application with [**pipx**](https://pypa.github.io/pipx/) using **`pipx install soco-cli`**. @@ -123,7 +122,7 @@ The installer adds the `sonos` command to the PATH. If the `sonos` command is no All commands have the form: -``` +```sh sonos SPEAKER ACTION ``` @@ -142,9 +141,9 @@ SoCo-CLI will try a number of approaches to find a speaker's IP address by speak ### Simple Usage Examples -- **`sonos "Living Room" volume`** Returns the current volume setting of the *Living Room* speaker. -- **`sonos Study volume 25`** Sets the volume of the *Study* speaker to 25. -- **`sonos Study group Kitchen`** Groups the *Study* speaker with the *Kitchen* speaker. +- **`sonos "Living Room" volume`** Returns the current volume setting of the _Living Room_ speaker. +- **`sonos Study volume 25`** Sets the volume of the _Study_ speaker to 25. +- **`sonos Study group Kitchen`** Groups the _Study_ speaker with the _Kitchen_ speaker. - **`sonos 192.168.0.10 mute`** Returns the mute state ('on' or 'off') of the speaker at the given IP address. - **`sonos 192.168.0.10 mute on`** Mutes the speaker at the given IP address. - **`sonos Kitchen play_favourite Jazz24 : wait 30m : Kitchen stop`** Plays 'Jazz24' for 30 minutes, then stops playback. @@ -158,29 +157,29 @@ To avoid typing the speaker name, or to parameterise the use of SoCo-CLI command Linux and macOS: -``` -$ export SPKR="Front Reception" -$ sonos play -$ sonos wait_stop : volume 10 +```sh +export SPKR="Front Reception" +sonos play +sonos wait_stop : volume 10 ``` Windows: -``` -C:\ set SPKR="Front Reception" -C:\ sonos play -C:\ sonos wait_stop : volume 10 +```console +C:\> set SPKR="Front Reception" +C:\> sonos play +C:\> sonos wait_stop : volume 10 ``` -IP addresses also work, e.g.: `$ export SPKR=192.168.0.50`. +IP addresses also work, e.g.: `export SPKR="192.168.0.50"`. If you want to ignore the `SPKR` environment variable for a specific `sonos` invocation, use the `--no-env` command line option. ### Using Shell Aliases -If your shell supports it, shell aliasing can be very convenient in creating shortcuts to SoCo-CLI commands. For example, I have the following in my `.zshrc` file: +If your shell supports it, shell aliasing can be very convenient in creating shortcuts to SoCo-CLI commands. For example, the following could be added to the `.bashrc`/`.zshrc` file: -``` +```sh # Sonos Aliases alias s="sonos" alias sk="sonos Kitchen" @@ -259,10 +258,10 @@ Albums and playlists from local libraries or music services can be added to your Or, to add to the current queue, then play the first playlist track: -``` -sonos add_playlist_to_queue -24 <-- Returns queue position of the first playlist track -sonos play_from_queue last_added +```console +$ sonos add_playlist_to_queue + 24 # Returns queue position of the first playlist track +$ sonos play_from_queue last_added ``` To add imported playlists from local libraries to the queue, use the `add_library_playlist_to_queue` action. @@ -297,11 +296,11 @@ This feature works by invoking the `play_file` action for each file in the playl ### Directories of Audio Files -To play every audio file in a local directory, use the `play_directory` (or `play_dir`) action. As with the `play_m3u` action this invokes `play_file` for each valid audio file in the directory. It does not traverse into subdirectories. +To play every audio file in a local directory, use the `play_directory` (or `play_dir`) action. As with the `play_m3u` action this invokes `play_file` for each valid audio file in the directory. It does not traverse into subdirectories. **Example**: `sonos Lounge play_directory "Music/Mozart/The Magic Flute/CD 1"` -On macOS (but not on Windows or Linux), if you have an attached CD drive, this action can be used to play a CD directly to your Sonos speakers, e.g.: +On macOS (but not on Windows or Linux), if you have an attached CD drive, this action can be used to play a CD directly to your Sonos speakers, e.g.: `sonos Lounge play_dir "/Volumes/Audio CD"`. @@ -322,10 +321,11 @@ Links can refer to tracks, albums, or playlists. The position of the first track - `https://music.apple.com/dk/album/black-velvet/217502930?i=217503142` **Example**: -``` -sonos Kitchen sharelink "https://open.spotify.com/track/6cpcorzV5cmVjBsuAXq4wD" -5 <-- Returns queue position of first track -sonos Kitchen play_from_queue 5 + +```console +$ sonos Kitchen sharelink "https://open.spotify.com/track/6cpcorzV5cmVjBsuAXq4wD" + 5 # Returns queue position of first track +$ sonos Kitchen play_from_queue 5 ``` ## Complete List of Available Actions @@ -339,7 +339,7 @@ sonos Kitchen play_from_queue 5 - **`dialog_mode`** (or **`dialog`**, **`dialogue_mode`**, **`dialogue`**): Returns the dialog mode setting of the speaker, 'on' or 'off' (if applicable). - **`dialog_mode `** (or **`dialog`**, **`dialogue_mode`**, **`dialogue`**): Sets the dialog mode setting of the speaker to 'on' of 'off' (if applicable). - **`fixed_volume`**: Returns whether the speaker's Fixed Volume feature is enabled, 'on' or 'off'. (Applies to Sonos Connect and Port devices only.) -- **`fixed_volume `**: Sets whether the speaker's Fixed Volume feature is enabled. +- **`fixed_volume `**: Sets whether the speaker's Fixed Volume feature is enabled. - **`group_mute`**: Returns the group mute state of a group of speakers, 'on' or 'off'. - **`group_mute `**: Sets the group mute state of a group of speakers to 'on' or 'off'. - **`group_relative_volume ` (or `group_rel_vol`, `grv`)**: Raises or lowers the group volume by `` which must be a number from -100 to 100. @@ -402,7 +402,7 @@ sonos Kitchen play_from_queue 5 - **`previous` (or `prev`)**: Move to the previous track (if applicable for the audio source). - **`repeat` (or `rpt`)**: Returns the repeat mode state: 'off', 'one', or 'all'. - **`repeat ` (or `rpt`)**: Sets the repeat mode state to one of: 'off' (or 'none'), 'one', or 'all'. -- **`seek