From a0630d6b4f25a6021ee22b78fa024e681824544d Mon Sep 17 00:00:00 2001 From: Roderick van Domburg Date: Fri, 22 Nov 2024 16:33:17 +0100 Subject: [PATCH] feat: configure command-line options via environment variables --- CHANGELOG.md | 15 ++++++++------- README.md | 26 ++++++++++++++++++++++++-- src/main.rs | 26 +++++++++++++++----------- 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c614e8..3af1ad0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,23 +8,24 @@ and [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). ## [Unreleased] ### Added -- [proxy] Proxy support using `HTTPS_PROXY` environment variable -- [remote] Eavesdropping on the Deezer Connect websocket +- [main] Support for configuring all command-line options via environment variables with `PLEEZER_` prefix +- [proxy] HTTPS proxy support via the `HTTPS_PROXY` environment variable +- [remote] Websocket monitoring mode for Deezer Connect protocol analysis ### Changed -- [docs] Improve consistency and readability of the README, Code of Conduct, Contributing guidelines, and Security Policy -- [main] Improve command-line argument help text -- [player] Store tracks to skip in a `HashSet` +- [docs] Enhanced documentation clarity and consistency across all policy documents +- [main] Improved command-line argument descriptions and examples +- [player] Optimized track skipping using `HashSet` for better performance ### Deprecated ### Removed ### Fixed -- [protocol] Deserialize `connect` messages without `offer_id` +- [protocol] Correctly handle `connect` messages missing the `offer_id` field ### Security -- [arl] Redact ARL from logs +- [arl] Prevent ARL token exposure in debug logs [Unreleased]: https://github.com/roderickvd/pleezer/compare/v0.1.0...HEAD diff --git a/README.md b/README.md index 74bc691..68da285 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,11 @@ - [Features](#features) - [Installation](#installation) - [Usage](#usage) + - [Command-Line Arguments](#command-line-arguments) + - [Environment Variables](#environment-variables) + - [Proxy Configuration](#proxy-configuration) + - [Stateless Configuration](#stateless-configuration) + - [Configuring the Secrets File](#configuring-the-secrets-file) - [Troubleshooting](#troubleshooting) - [Setting Up Your Build Environment](#setting-up-your-build-environment) - [Contributing](#contributing) @@ -168,15 +173,32 @@ Your music will start playing on the selected device. pleezer --version ``` +### Environment Variables + +All command-line options can be set using environment variables by prefixing `PLEEZER_` to the option name in SCREAMING_SNAKE_CASE. For example: + +```bash +# Using environment variables +export PLEEZER_NAME="Living Room" +export PLEEZER_NO_INTERRUPTIONS=true + +# Command-line arguments override environment variables +pleezer --name "Kitchen" # Will use "Kitchen" instead +``` + +Command-line arguments take precedence over environment variables if both are set. + ### Proxy Configuration -**pleezer** supports proxy connections through the `HTTPS_PROXY` environment variable. The value must include the `https://` schema prefix. +**pleezer** supports proxy connections through the `HTTPS_PROXY` environment variable. he value must include either the `http://` or `https://` schema prefix. Examples: ```bash # Linux/macOS -export HTTPS_PROXY="https://proxy.company.com:8080" +export HTTPS_PROXY="http://proxy.example.com:8080" +export HTTPS_PROXY="https://proxy.example.com:8080" + # Windows (Command Prompt) set HTTPS_PROXY=https://proxy.company.com:8080 diff --git a/src/main.rs b/src/main.rs index 2788e15..9ac6668 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,7 +26,6 @@ const BUILD_PROFILE: &str = "release"; const ARGS_GROUP_LOGGING: &str = "logging"; /// Command line arguments as parsed by `clap`. -// TODO : add env support #[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord, Parser)] #[command(author, version, about, long_about = None)] struct Args { @@ -34,13 +33,13 @@ struct Args { /// /// Keep this file secure and private, as it contains sensitive information /// that can grant access to your Deezer account. - #[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath, default_value_t = String::from("secrets.toml"))] + #[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath, default_value_t = String::from("secrets.toml"), env = "PLEEZER_SECRETS_FILE")] secrets_file: String, /// Set the player's name as shown to Deezer clients /// /// If not specified, uses the system hostname. - #[arg(short, long, value_hint = ValueHint::Hostname)] + #[arg(short, long, value_hint = ValueHint::Hostname, env = "PLEEZER_NAME")] name: Option, /// Select the audio output device @@ -48,31 +47,36 @@ struct Args { /// Format: [][:][:][:] /// Use "?" to list available devices. /// If omitted, uses the system default output device. - #[arg(short, long, default_value = "")] - device: String, + #[arg(short, long, default_value = None, env = "PLEEZER_DEVICE")] + device: Option, /// Prevent other clients from taking over the connection /// /// By default, other clients can interrupt and take control of playback. - #[arg(long, default_value_t = false)] + #[arg(long, default_value_t = false, env = "PLEEZER_NO_INTERRUPTIONS")] no_interruptions: bool, /// Suppress all output except warnings and errors - #[arg(short, long, default_value_t = false, group = ARGS_GROUP_LOGGING)] + #[arg(short, long, default_value_t = false, group = ARGS_GROUP_LOGGING, env = "PLEEZER_QUIET")] quiet: bool, /// Enable verbose logging /// /// Use -v for debug logging /// Use -vv for trace logging - #[arg(short, long, action = clap::ArgAction::Count, group = ARGS_GROUP_LOGGING)] + #[arg(short, long, action = clap::ArgAction::Count, group = ARGS_GROUP_LOGGING, env = "PLEEZER_VERBOSE")] verbose: u8, /// Monitor the Deezer Connect websocket without participating /// /// A development tool that observes websocket traffic. Requires verbose /// logging (-v or -vv). For best results, use trace logging (-vv). - #[arg(long, default_value_t = false, requires = "verbose")] + #[arg( + long, + default_value_t = false, + requires = "verbose", + env = "PLEEZER_EAVESDROP" + )] eavesdrop: bool, } @@ -157,7 +161,7 @@ fn parse_secrets(secrets_file: impl AsRef) -> Result { /// This function returns `Err` when an error occurs. This could be due to the /// user interrupting the application or an unrecoverable network error. async fn run(args: Args) -> Result<()> { - if args.device == "?" { + if args.device.as_ref().is_some_and(|device| device == "?") { // List available devices and exit. let devices = Player::enumerate_devices(); if devices.is_empty() { @@ -284,7 +288,7 @@ async fn run(args: Args) -> Result<()> { } }; - let player = Player::new(&config, &args.device).await?; + let player = Player::new(&config, args.device.as_deref().unwrap_or_default()).await?; let mut client = remote::Client::new(&config, player)?; // Restart after sleeping some duration to prevent accidental denial of