diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b089568..fa1b0108 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,7 @@ on: - '**.rs' - 'Cargo.toml' - 'Cargo.lock' + - 'contrib/spotifyd.conf' jobs: codestyle: @@ -50,7 +51,7 @@ jobs: command: clippy args: --all-targets --all-features -- -D warnings - check: + test: needs: [lint] runs-on: ${{ matrix.os }} strategy: @@ -83,5 +84,5 @@ jobs: - name: Checking Rust code uses: actions-rs/cargo@v1 with: - command: check + command: test args: --locked --no-default-features --features ${{ matrix.features }} diff --git a/Cargo.lock b/Cargo.lock index 7310f5d2..b58a005e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3022,6 +3022,15 @@ dependencies = [ "syn 2.0.93", ] +[[package]] +name = "serde_ignored" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8e319a36d1b52126a0d608f24e93b2d81297091818cd70625fcf50a15d84ddf" +dependencies = [ + "serde", +] + [[package]] name = "serde_json" version = "1.0.134" @@ -3238,6 +3247,7 @@ dependencies = [ "log", "pledge", "serde", + "serde_ignored", "sha-1", "syslog", "thiserror 2.0.9", diff --git a/Cargo.toml b/Cargo.toml index 142d0704..53c60c7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ directories = "5.0.1" thiserror = "2.0" time = { version = "0.3.37", default-features = false, features = ["formatting"] } clap = { version = "4.5.23", features = ["derive"] } +serde_ignored = "0.1.10" [target."cfg(unix)".dependencies] daemonize = "0.5" diff --git a/contrib/spotifyd.conf b/contrib/spotifyd.conf new file mode 100644 index 00000000..ac037e0e --- /dev/null +++ b/contrib/spotifyd.conf @@ -0,0 +1,115 @@ +[global] + +#---------# +# GENERAL # +#---------# + +# The name that gets displayed under the connect tab on +# official clients. +#device_name = "device_name_in_spotify_connect" + +# The displayed device type in Spotify clients. +# Can be unknown, computer, tablet, smartphone, speaker, t_v, +# a_v_r (Audio/Video Receiver), s_t_b (Set-Top Box), and audio_dongle. +#device_type = "speaker" + +# The directory used to store credentials and audio cache. +# Default: infers a sensible cache directory (e.g. on Linux: $XDG_CACHE_HOME) +# +# Note: The file path does not get expanded. Environment variables and +# shell placeholders like $HOME or ~ don't work! +#cache_path = "/full/path/to/cache/directory" + +# If set to true, audio data does NOT get cached. +# In this case, the cache is only used for credentials. +#no_audio_cache = true + +# The maximal size of the cache directory in bytes +# The example value corresponds to ~ 1GB +#max_cache_size = 1000000000 + +# If set to true, `spotifyd` tries to bind to dbus (default is the session bus) +# and expose MPRIS controls. When running headless, without the session bus, +# you should set this to false, to avoid errors. If you still want to use MPRIS, +# have a look at the `dbus_type` option. +#use_mpris = true + +# The bus to bind to with the MPRIS interface. +# Possible values: "session", "system" +# The system bus can be used if no graphical session is available +# (e.g. on headless systems) but you still want to be able to use MPRIS. +# NOTE: You might need to add appropriate policies to allow spotifyd to +# own the name. +#dbus_type = "session" + +#-----------# +# DISCOVERY # +#-----------# + +# If set to true, this disables zeroconf discovery. +# This can be useful, if one prefers to run a single-user instance. +#disable_discovery = false + +# The port at which `spotifyd` is going to offer its service over the network (TCP). +# If not set, a random port > 1024 is used. For the service to be discoverable on the +# local network via mDNS, both the mDNS port (5353 UDP) and the random or fixed +# zeroconf port need to be allowed through any active firewall. +#zeroconf_port = 1234 + +#-------# +# AUDIO # +#-------# + +# The audio backend used to play music. To get +# a list of possible backends, run `spotifyd --help`. +#backend = "alsa" # use portaudio for macOS [homebrew] + +# The alsa audio device to stream audio. To get a +# list of valid devices, run `aplay -L`, +#device = "default" # omit for macOS + +# The PCM sample format to use. Possible values +# are F32, S32, S24, S24_3, S16. +# Change this value if you encounter errors like +# "Alsa error PCM open ALSA function 'snd_pcm_hw_params_set_format' failed with error 'EINVAL: Invalid argument'" +#audio_format = "S16" + +# The volume controller. Each one behaves different to +# volume increases. For possible values, run +# `spotifyd --help`. +#volume_controller = "softvol" # use softvol for macOS + +# ! Only relevant for ALSA ! +# The alsa control device. By default this is the same +# name as the `device` field. +#control = "default" + +# ! Only relevant for ALSA ! +# The alsa mixer used by `spotifyd`. +#mixer = "PCM" # omit for macOS + +# The audio bitrate. 96, 160 or 320 kbit/s +#bitrate = 160 + +# Volume on startup between 0 and 100 +#initial_volume = 90 + +# If set to true, enables volume normalisation between songs. +#volume_normalisation = true + +# The normalisation pregain that is applied for each song. +#normalisation_pregain = -10 + +#-------ä +# OTHER # +#-------# + +# After the music playback has ended, start playing similar songs based on the previous tracks. +# By default, `spotifyd` infers this setting from the user settings. +#autoplay = true + +# A command that gets executed in your shell after each song changes. +#on_song_change_hook = "echo \"hook executed on $PLAYER_EVENT\"" + +# The proxy `spotifyd` will use to connect to spotify. +#proxy = "http://proxy.example.org:8080" diff --git a/docs/src/Introduction.md b/docs/src/Introduction.md index faa4b524..1f3d40c9 100644 --- a/docs/src/Introduction.md +++ b/docs/src/Introduction.md @@ -1,8 +1,10 @@ # Introduction -This is the documentation of [spotifyd][spotifyd] -> An open source Spotify client running as a UNIX daemon. +This is the documentation of [spotifyd][spotifyd], which covers the installation and setup process as well as some advanced topics. -These docs should be regarded as an extension of the [README][spotifyd] so please check there first before looking through the docs. +## Getting Help -[spotifyd]: https://github.com/Spotifyd/spotifyd \ No newline at end of file +If you're stuck in the setup process or have a question, please join the [community matrix server][matrix]. We're always willing to help! + +[spotifyd]: https://github.com/Spotifyd/spotifyd +[matrix]: https://matrix.to/#/#spotifyd:matrix.org diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 820e006a..04313c8b 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -2,20 +2,19 @@ [Introduction](./Introduction.md) -- [Installation Instructions](./installation/README.md) - - [Installing on a Raspberry Pi](./installation/Raspberry-Pi.md) - - [Installing on Ubuntu (from source)](./installation/Ubuntu.md) - - [Cross Compiling on Ubuntu](./installation/Cross-Compiling-on-Ubuntu.md) - - [Cross Compilation using Docker](./installation/cross-compile-using-docker.md) - - [Installing with Homebrew on macOS](./installation/MacOS.md) - - [Installing on FreeBSD](./installation/FreeBSD.md) - - [Installing on OpenBSD](./installation/OpenBSD.md) -- [Configuration](./config/README.md) - - [CLI options](./config/Cli.md) - - [Configuration file](./config/File.md) - - [Running as a Service](./config/services/README.md) - - [Running as systemd service](./config/services/Systemd.md) - - [Running as launchd service (MacOS)](./config/services/MacOS.md) -- [Other]() - - [D-Bus control](./other/D-Bus-control.md) - +- [Installation](./installation/README.md) + - [Running as a service](./installation/service.md) + - [Installing on RaspberryPi OS 64-bit](./installation/raspberrypi64.md) + - [Building from source](./installation/source.md) + - [Cross-Compile using Docker](./installation/cross-compile-using-docker.md) +- [Configuration](./configuration/README.md) + - [Authentication](./configuration/auth.md) + - [Audio](./configuration/audio.md) + - [Other settings](./configuration/other.md) +- [Advanced Setup](./advanced/README.md) + - [Running as systemd service](./advanced/systemd.md) + - [Running as launchd service](./advanced/launchd.md) + - [Using D-Bus to control `spotifyd`](./advanced/dbus.md) + - [MPRIS on headless systems](./advanced/mpris.md) + - [Extending spotifyd with hooks](./advanced/hooks.md) +- [Troubleshooting](./troubleshooting.md) diff --git a/docs/src/advanced/README.md b/docs/src/advanced/README.md new file mode 100644 index 00000000..7efabca2 --- /dev/null +++ b/docs/src/advanced/README.md @@ -0,0 +1,3 @@ +# Advanced Setup + +In this section, you will learn how to persist `spotifyd` as a system service, run hook scripts on certain events and control `spotifyd` via DBUS on headless systems. diff --git a/docs/src/advanced/dbus.md b/docs/src/advanced/dbus.md new file mode 100644 index 00000000..86ad696c --- /dev/null +++ b/docs/src/advanced/dbus.md @@ -0,0 +1,118 @@ +# Using D-Bus to control spotifyd + +If MPRIS support is built into your version and enabled (`--use-mpris` cli flag / `use_mpris = true` in config), `spotifyd` exposes some interfaces via D-Bus through which it provides information and can be controlled. + +Most of the time, you won't have to worry to much about the details, since tools like `playerctl` work out of the box with `spotifyd`. If you have some custom requirements or want to write custom scripts to control `spotifyd`, this section is for you. + +## Available Interfaces + +Directly after startup, no interfaces will be available. Once we are connected to Spotify, `spotifyd` will request the name `rs.spotifyd.instance$PID` (where `PID=$(pidof spotifyd)`) and expose the interface `rs.spotifyd.Controls`. + +As soon as we are the playback device (e.g. because we are selected from another client or the `TransferPlayback` method has been called), `spotifyd` will additionally expose the MPRIS interfaces and request the name `org.mpris.MediaPlayer2.spotifyd.instance$PID`. + +### Spotifyd Controls + +The `rs.spotifyd.Controls` interface exposes a few useful controls that are available even if we're not the active playback device. + +- Method `TransferPlayback`: transfers Spotify playback to `spotifyd` +- Method `VolumeUp`: increases player volume +- Method `VolumeDown`: decreases player volume + +Examples: +```bash +dest=rs.spotifyd.instance$(pidof spotifyd) +# increase volume +dbus-send --print-reply --dest=$dest /rs/spotifyd/Controls rs.spotifyd.Controls.VolumeUp +# become the active playback device +dbus-send --print-reply --dest=$dest /rs/spotifyd/Controls rs.spotifyd.Controls.TransferPlayback +``` + +### MPRIS + +The `org.mpris.MediaPlayer2` and `org.mpris.MediaPlayer2.Player` interfaces from the [MPRIS specification](https://specifications.freedesktop.org/mpris-spec/latest/) are implemented. + +Example usage: +```bash +dest=org.mpris.MediaPlayer2.spotifyd.instance$(pidof spotifyd) +# Start playback of some Spotify URI +dbus-send --print-reply --dest=$dest /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.OpenUri string:spotify:track:4PTG3Z6ehGkBFwjybzWkR8 +# Get metadata of the currently playing track +dbus-send --print-reply --dest=$dest /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:org.mpris.MediaPlayer2.Player string:Metadata +``` + +## Examples + +Starting Playback without Client: +```bash +#!/bin/bash + +# optionally, we can start `spotifyd` here +if ! pidof -q spotifyd +then + spotifyd --use-mpris +fi + +dest=rs.spotifyd.instance$(pidof spotifyd) + +wait_for_name() { + dst=$1 + counter=0 + + # check if controls are available + until [ $counter -gt 10 ] || (dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames | grep -q "$dest") + do + sleep 0.3 + ((counter++)) + done + + if [ $counter -gt 10 ] + then + echo "waiting for spotifyd timed out" >&1 + exit 1 + fi +} + +controls_name=rs.spotifyd.instance$(pidof spotifyd) +wait_for_name $controls_name +echo "Transferring Playback" +dbus-send --print-reply --dest=$controls_name /rs/spotifyd/Controls rs.spotifyd.Controls.TransferPlayback + +# if URI is specified, start the playback there +if [ -n "$1" ] +then + uri="$1" + mpris_name=org.mpris.MediaPlayer2.spotifyd.instance$(pidof spotifyd) + wait_for_name $mpris_name + echo "Starting Playback of $uri" + dbus-send --print-reply --dest=$mpris_name /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.OpenUri "string:$uri" +else + echo "Hint: specify an argument to start playback of a specific Spotify URI" +fi +``` + +Sleep Timer: +```bash +#!/bin/bash + +usage() { + echo "Usage: $0 " >&1 + exit 1 +} + +[ -n "$1" ] || usage + +echo "Sleeping for $1 seconds" +sleep $1 + +dest=org.mpris.MediaPlayer2.spotifyd.instance$(pidof spotifyd) +dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames | grep -q "$dest" + +if [ "$?" = "0" ] +then + dbus-send --print-reply --dest=$dest /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Stop + # alternatively just pause: + # dbus-send --print-reply --dest=$dest /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Pause +else + echo "No active spotifyd playback." +fi +``` diff --git a/docs/src/other/User-supplied-scripts.md b/docs/src/advanced/hooks.md similarity index 72% rename from docs/src/other/User-supplied-scripts.md rename to docs/src/advanced/hooks.md index 620e520a..86f8fb96 100644 --- a/docs/src/other/User-supplied-scripts.md +++ b/docs/src/advanced/hooks.md @@ -1,5 +1,13 @@ # User supplied Scripts +If you want to create custom behaviour around `spotifyd`, one option is to look into the [D-Bus functionality](./dbus.md). But on headless systems or smaller projects, we also offer a hook API. On certain events, a hook can be executed with event details given as environment variables. + +To point `spotifyd` to such a script, use the `--onevent /path/to/script` cli arg / `on_song_change_hook = "/path/to/script"` configuration value. + +In order to learn about the available events and the available details, you can either create simple scripts which log the given environment variables or look at the output of `spotifyd`, which logs whenever the script is executed. + +The following scripts are intended to serve as inspiration for your own scripts. If you have written own scripts which you think might be useful to others, please create a PR adding them here! + ## Dunst Notifications (Using Spotify API) This script will show a dunst notification when you play/change/stop Spotify (and when the music change). It is using spotify APIs to get music details. @@ -48,19 +56,5 @@ This script will show a dunst notification when you play/change/stop Spotify (an fi ``` -* Make this script executable (```chmod +x ntification_script.sh```) -* Add the line ```onevent = "bash /home/YOU_USER/bin/spotifyNotifications.sh"``` to your ```spotifyd.conf``` - -## Dunst Notifications (Using Playerctl metadata) - -This script is a modification of the script supplied above, however instead of calling the Spotify API for track information, the metadata of the current track is used instead, leading to a more performant script. - -### Dependencies - -* [Playerctl](https://github.com/altdesktop/playerctl) - -### How to Use: - -* Download this [gist](https://gist.github.com/ohhskar/efe71e82337ed54b9aa704d3df28d2ae) -* Make the script executable (```chmod +x notifications.sh```) -* Add the line ```onevent = "/path/to/file/spotifyNotifications.sh"``` to your ```spotifyd.conf``` \ No newline at end of file +* Make this script executable (`chmod +x notification_script.sh`) +* Add the line `onevent = "bash /home/YOU_USER/bin/spotifyNotifications.sh"` to your `spotifyd.conf` diff --git a/docs/src/config/services/MacOS.md b/docs/src/advanced/launchd.md similarity index 90% rename from docs/src/config/services/MacOS.md rename to docs/src/advanced/launchd.md index 069df39f..b48147a3 100644 --- a/docs/src/config/services/MacOS.md +++ b/docs/src/advanced/launchd.md @@ -1,6 +1,6 @@ -# Running spotifyd as a service on macOS +# Running as launchd service -On macOS the system wide and per-user daemon/agent manager is known as `launchd`. Interfacing with `launchd` is performed through `launchctl`. +On macOS, the system wide and per-user daemon/agent manager is known as `launchd`. Interfacing with `launchd` is performed through `launchctl`. In order to use `spotifyd` as a service on macOS one must specify a `.plist` that represents the service, and place it in `/Library/LaunchDaemons`. diff --git a/docs/src/advanced/mpris.md b/docs/src/advanced/mpris.md new file mode 100644 index 00000000..52976024 --- /dev/null +++ b/docs/src/advanced/mpris.md @@ -0,0 +1,49 @@ +# MPRIS on headless systems + +D-Bus offers two types of communication buses, the system and the session bus. By default and in most setups, MPRIS is expected to run on the session bus (for example, `playerctl` requires that). However, in headless contexts, the session bus is usually not available. + +In this case, you basically have two options: + +## Option 1: Launch with `dbus-launch` + +By creating a wrapper script and using `dbus-launch`, `spotifyd` can be run with its own bus. This could look like the following + +`./spotify_wrapper.sh`: +```bash +#!/bin/bash + +echo "$DBUS_SESSION_BUS_ADDRESS" > /tmp/spotifyd_bus +echo "To use spotifyd's session bus, run 'export DBUS_SESSION_BUS_ADDRESS=$(cat /tmp/spotifyd_bus)'" +spotifyd --no-daemon --use-mpris +``` + +Then, execute this script using `dbus-launch ./spotify_wrapper.sh` and follow the instructions in the output. + +## Option 2: Using the system bus + +Instead of creating a new session bus, we can instead make use of the always existing system bus. +To instruct `spotifyd` to use the system instead of the session bus, set the `--dbus-type system` cli flag / `dbus_type = "system"` config value. + +By default, requesting names on the system bus requires special priveleges, which `spotifyd` doesn't have. So, unless being run as root, this will fail. To allow a non-root user to request the `spotifyd` name, we need to create the following file (replacing `your user` by something sensible): + +`/usr/share/dbus-1/system.d/spotifyd.conf`: +```xml + + + + + + + + + + + + + + +``` + +Make sure to reload the D-Bus configuration with `systemctl reload dbus`. diff --git a/docs/src/config/services/Systemd.md b/docs/src/advanced/systemd.md similarity index 81% rename from docs/src/config/services/Systemd.md rename to docs/src/advanced/systemd.md index c16edd0b..9a8b304a 100644 --- a/docs/src/config/services/Systemd.md +++ b/docs/src/advanced/systemd.md @@ -1,8 +1,8 @@ -# Running spotifyd as a systemd service +# Running as systemd service ## As as a user service -A `systemd.service` unit file is provided to help run spotifyd as a service on systemd-based systems. The file `contrib/spotifyd.service` should be copied to either: +A `systemd.service` unit file is provided in the project sources to help run spotifyd as a service on systemd-based systems. The file `contrib/spotifyd.service` should be copied to either: ```bash /etc/systemd/user/ @@ -23,7 +23,7 @@ systemctl --user enable spotifyd.service --now When running spotifyd as a system wide service, it is not possible to access a user's keyring to obtain login credentials. Do not set `use_keyring = true` and do not specify `--use-keyring`, when running as a system wide service. To be able to access login credentials stored in the user's keyring, run spotifyd as a user service, as decribed above. -Additionally, `use_mpris = true` or `--use-mpris` should not be used, since their intended usage is within user sessions (and not system-wide daemons). If you have very specific requirements and still want to control a system-wide `spotifyd` instance, there is some help available [here](https://github.com/Spotifyd/spotifyd/issues/244). +Additionally, `use_mpris = true` or `--use-mpris` should not be used, since their intended usage is within user sessions (and not system-wide daemons). If you have very specific requirements and still want to control a system-wide `spotifyd` instance, head over to [MPRIS on headless systems](./mpris.md). diff --git a/docs/src/config/Cli.md b/docs/src/config/Cli.md deleted file mode 100644 index e43ae1df..00000000 --- a/docs/src/config/Cli.md +++ /dev/null @@ -1,7 +0,0 @@ -# Command Line Options - -`Spotifyd` can be configured using CLI arguments. For a detailed description as well as possible values for each flag, run - -```bash -spotifyd --help -``` \ No newline at end of file diff --git a/docs/src/config/File.md b/docs/src/config/File.md deleted file mode 100644 index a0871817..00000000 --- a/docs/src/config/File.md +++ /dev/null @@ -1,183 +0,0 @@ -# Configuration file - -`Spotifyd` is able to load configuration values from a [TOML](https://toml.io/en/v0.5.0) file too. The file has to be named `spotifyd.conf` and reside in the user's configuration directory (`~/.config/spotifyd`) or the system configuration directory (`/etc` or `/etc/xdg/spotifyd`). This also applies to macOS! - -The configuration file consists of two sections, `global` and `spotifyd`, whereas `spotifyd` takes priority over `global`. - -The configuration file has the following format: - -```toml -[global] -# Your Spotify account name. -username = "username" - -# Your Spotify account password. -password = "password" - -# A command that gets executed and can be used to -# retrieve your password. -# The command should return the password on stdout. -# -# This is an alternative to the `password` field. Both -# can't be used simultaneously. -password_cmd = "command_that_writes_password_to_stdout" - -# If set to true, `spotifyd` tries to look up your -# password in the system's password storage. -# -# Note, that the `password` field will take precedence, if set. -use_keyring = true - -# If set to true, `spotifyd` tries to bind to dbus (default is the session bus) -# and expose MPRIS controls. When running headless, without the session bus, -# you should set this to false, to avoid errors. If you still want to use MPRIS, -# have a look at the `dbus_type` option. -use_mpris = true - -# The bus to bind to with the MPRIS interface. -# Possible values: "session", "system" -# The system bus can be used if no graphical session is available -# (e.g. on headless systems) but you still want to be able to use MPRIS. -# NOTE: You might need to add appropriate policies to allow spotifyd to -# own the name. -dbus_type = "session" - -# The audio backend used to play music. To get -# a list of possible backends, run `spotifyd --help`. -backend = "alsa" # use portaudio for BSD and macOS [homebrew] - -# The alsa audio device to stream audio. To get a -# list of valid devices, run `aplay -L`, -device = "alsa_audio_device" # omit for macOS - -# The PCM sample format to use. Possible values -# are F32, S32, S24, S24_3, S16. -# Change this value if you encounter errors like -# "Alsa error PCM open ALSA function 'snd_pcm_hw_params_set_format' failed with error 'EINVAL: Invalid argument'" -audio_format = "S16" - -# The alsa control device. By default this is the same -# name as the `device` field. -control = "alsa_audio_device" # omit for macOS - -# The alsa mixer used by `spotifyd`. -mixer = "PCM" # omit for macOS - -# The volume controller. Each one behaves different to -# volume increases. For possible values, run -# `spotifyd --help`. -volume_controller = "alsa" # use softvol for BSD and macOS - -# A command that gets executed in your shell after each song changes. -on_song_change_hook = "command_to_run_on_playback_events" - -# The name that gets displayed under the connect tab on -# official clients. -device_name = "device_name_in_spotify_connect" - -# The audio bitrate. 96, 160 or 320 kbit/s -bitrate = 160 - -# The directory used to cache audio data. This setting can save -# a lot of bandwidth when activated, as it will avoid re-downloading -# audio files when replaying them. -# -# Note: The file path does not get expanded. Environment variables and -# shell placeholders like $HOME or ~ don't work! -cache_path = "cache_directory" - -# The maximal size of the cache directory in bytes -# The example value corresponds to ~ 1GB -max_cache_size = 1000000000 - -# If set to true, audio data does NOT get cached. -no_audio_cache = true - -# Volume on startup between 0 and 100 -# NOTE: This variable's type will change in v0.4, to a number (instead of string) -initial_volume = "90" - -# If set to true, enables volume normalisation between songs. -volume_normalisation = true - -# The normalisation pregain that is applied for each song. -normalisation_pregain = -10 - -# After the music playback has ended, start playing similar songs based on the previous tracks. -autoplay = true - -# The port at which `spotifyd` is going to offer its service over the network (TCP). -# If not set, a random port > 1024 is used. For the service to be discoverable on the -# local network via mDNS, both the mDNS port (5353 UDP) and the random or fixed -# zeroconf port need to be allowed through any active firewall. -zeroconf_port = 1234 - -# The proxy `spotifyd` will use to connect to spotify. -proxy = "http://proxy.example.org:8080" - -# The displayed device type in Spotify clients. -# Can be unknown, computer, tablet, smartphone, speaker, t_v, -# a_v_r (Audio/Video Receiver), s_t_b (Set-Top Box), audio_dongle, -# game_console, cast_audio, cast_video, automobile, smartwatch, chromebook, -# unknown_spotify, car_thing, observer and home_thing. -device_type = "speaker" -``` - -## Alternatives to storing your password in the config file - -- use zeroconf authentication from Spotify Connect - - Spotifyd is able to advertise itself on the network without credentials. To enable this, you must omit / comment any `username` / `username_cmd` or `password` / `password_cmd` in the configuration. Spotifyd will receive an authentication blob from Spotify when you choose it from the devices list. - - > **Note:** If you choose to go with this, it is also recommended to omit the `cache_path` and `cache_directory` options. Otherwise the first user to connect to the service will have its authentication blob cached by the service and nobody else will be able to connect to the service without clearing the cache. - - This way, a Spotifyd instance can also be made available to multiple users. - - For more information, have a look at the [librespot documentation][librespot-docs]. - -- **`password_cmd`** config entry - - This feature allows you to provide a command that prints your password to `stdout`, which saves you from having to store your password in the config file directly. To use it, set the `password_cmd` config entry to the command you would like to use and remove the `password` config entry. - - For example (using the password-management utility [pass][pass-homepage]). - - ```toml - # ~/.config/spotifyd/spotifyd.conf - password_cmd = "pass spotify" - ``` - -- **`use_keyring`** config entry / **`--use-keyring`** CLI flag - - > **Note:** If choosing the user's keyring to store login credentials, running spotifyd as a systemd _system service_ is no longer possible. A system wide service cannot access a specific user's keyring. In this case, make sure to run spotifyd as a systemd _user service_. See [systemd configuration](services/Systemd.md). - - This features leverages [Linux's DBus Secret Service API][secret-storage-specification] or native macOS keychain in order to forgo the need to store your password directly in the config file. To use it, compile with the `dbus_keyring` feature and set the `use-keyring` config entry to `true` or pass the `--use-keyring` CLI flag during start to the daemon. Remove the `password` and/or `password_cmd` config entries. - - Your keyring entry needs to have the following attributes set: - - ```yaml - application: rust-keyring - service: spotifyd - username: - ``` - - To add such an entry into your keyring, you can use `secret-tool`, a CLI used to communicate with agents that support the Secret Service API: - - ```bash - secret-tool store --label='name you choose' application rust-keyring service spotifyd username - ``` - - You can use the keychain GUI on macOS to add an item respectively, or with the built-in `security` tool: - - ```bash - security add-generic-password -s spotifyd -D rust-keyring -a -w - ``` - -## Shell used to run commands indicated by `password_cmd` or `on_song_changed_hook` - -If either of these options is given, the shell `spotifyd` will use to run its commands is the shell indicated by the `SHELL` environment variable, if set. If the `SHELL` environment variable is not set, `spotifyd` will use the user's default shell, which, on Linux and BSD, is the shell listed in `/etc/passwd`. On macOS it is the shell listed in the output of `dscl . -read /Users/ UserShell`. - -[pass-homepage]: https://www.passwordstore.org/ -[playerctl-homepage]: https://github.com/altdesktop/playerctl -[secret-storage-specification]: https://www.freedesktop.org/wiki/Specifications/secret-storage-spec/ -[sp-homepage]: https://gist.github.com/wandernauta/6800547 -[librespot-docs]: https://github.com/librespot-org/librespot/blob/master/docs/authentication.md#zeroconf-based-authentication diff --git a/docs/src/config/README.md b/docs/src/config/README.md deleted file mode 100644 index e5d5bd02..00000000 --- a/docs/src/config/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Configuration - -`Spotifyd` is able to run without configuration at all and will assume default values for most of the fields. However, running without configuration will only allow you to connect to it via Spotify Connect if you're on the same network as the daemon diff --git a/docs/src/config/services/README.md b/docs/src/config/services/README.md deleted file mode 100644 index 8a75d45b..00000000 --- a/docs/src/config/services/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Running as a Service - -You can run Spotifyd as a service that automatically starts in the background. diff --git a/docs/src/configuration/README.md b/docs/src/configuration/README.md new file mode 100644 index 00000000..25fa390c --- /dev/null +++ b/docs/src/configuration/README.md @@ -0,0 +1,14 @@ +# Configuration + +`Spotifyd` is able to run without configuration at all and will assume default values for most of the fields. However, running without configuration will only allow you to connect to it via Spotify Connect if you're on the same network as the daemon. + +All configuration options can be specified directly as command line arguments or alternatively (in particular for permanent changes) be written into a configuration file. Throughout this section, we will always give both possibilities, e.g. `--cli-arg` for the cli variant / `config_value` for the config file variable. + +## Config File + +`spotifyd` will look for its configuration at `/etc/spotifyd.conf`, `$XDG_CONFIG_PATH/spotifyd/spotifyd.conf` or if that is not set `~/.config/spotifyd/spotifyd.conf`. For other needs, you can point `spotifyd` to it's config file with the command line argument `--config-path `. + +You can start with the following documented config as an example and read through the subpages of this section: +```toml +{{#include ../../../contrib/spotifyd.conf}} +``` diff --git a/docs/src/configuration/audio.md b/docs/src/configuration/audio.md new file mode 100644 index 00000000..0f751b7e --- /dev/null +++ b/docs/src/configuration/audio.md @@ -0,0 +1,38 @@ +# Audio Configuration + +On most setups, audio should be Just Working™. If you have specific needs or something's not working, you might need to touch some of the config values. + +## Backend + +> `-b/--backend` or `backend` in the config file. + +There are different audio backends available to choose from. See `spotifyd --help` to get the available names. + +## Device selection + +> `--device` or `device` in the config file. + +Instead of using the default device, which can sometimes be different to what you'd prefer, you can ask `spotifyd` to use a specific audio device. The interpretation and available values depends on the backend you're using. + +- For ALSA, you can use `aplay -L` to get a list of possible devices. +- For PulseAudio, run `pactl list short sinks` to get a list of possible names. + +## Bitrate + +> `-B/--bitrate` or `bitrate` in the config file. + +To reduce bandwidth usage or increase quality, you can play with the bitrate. + +## Volume Controller + +> `--volume-controller` or `volume_controller` in the config file. + +In most cases, leaving this at the default (`softvol`) should be fine. + +If you want your `spotifyd` volume to be synchronized with an output device's hardware volume, you can set this to `alsa` or `alsa_linear`. In both cases, you might also want to set the `mixer` device to set which device's volume should be changed. + +If you want to prevent the user to be able to adjust the volume, set this instead to `none`. + +## Other + +For more interesting but less relevant audio options, have a look at `spotifyd --help` or [the example config](./). diff --git a/docs/src/configuration/auth.md b/docs/src/configuration/auth.md new file mode 100644 index 00000000..97cb22d7 --- /dev/null +++ b/docs/src/configuration/auth.md @@ -0,0 +1,41 @@ +# Authentication + +There are two different ways of authentication supported. + +## Discovery on LAN + +By default, `spotifyd` advertises itself on the local network as a Spotify Connect device and will thus appear in **official** clients. After selecting it over there, you should be able to hear the sound coming out of your `spotifyd` device. + +For this to work, you need to make sure that your firewall isn't blocking the discovery. In particular, `spotifyd` uses two ports: + +- `5353 UDP`: MDNS service advertisement +- A zeroconf port which uses TCP. By default, it is randomly chosen, but if you want to, you can configure it with the `--zeroconf-port` cli option / `zeroconf_port` config value. + +If you don't want discovery, because you're using one of the methods below, you can disable it via the `--disable-discovery` cli option / `disable_discovery = true` config value. + +> __Note:__ By default, the last active session will be remembered and reconnected once the service is restarted. + +## Manual Login (via OAuth) + +If for some reason, discovery is not a viable option for your use case or you prefer a single-user instance, you can manually log in to your account and `spotifyd` will connect to this account by default. + +> __Note:__ Since the login method requires a web browser, trying this on headless systems is not recommended. As a workaround, you can log in on a machine with a working web browser and then copy the credential file onto the headless system. The location of the credential file will be `/oauth/credentials.json`. + +Before you begin the login flow, make sure that you won't need to change `cache_path` later on, because that location will be used to store the login data. + +Now, you're ready to run `spotifyd authenticate` (for available options, see `spotifyd auth --help`). +This will ask you to browse to a link with your preferred web browser. On the page, you need to log into your Spotify account and confirm the connection. + +If the process was successful, you should see the message "Go back to your terminal :)" in your browser window. You can now close the tab and return to the terminal. + +Now, when running `spotifyd --no-daemon`, you should see that `spotifyd` automatically connects to your account. + +``` +Loading config from "..." +[...] +Login via OAuth as user . +[...] +Authenticated as '' ! +``` + +> __Note:__ Even if you logged into `spotifyd` using this method, discovery will still be enabled by default and any incoming connection will interrupt the current session. If you don't want or need this, you can disable it via the `--disable-discovery` cli option / `disable_discovery = true` config value. diff --git a/docs/src/configuration/other.md b/docs/src/configuration/other.md new file mode 100644 index 00000000..bd32c55d --- /dev/null +++ b/docs/src/configuration/other.md @@ -0,0 +1,13 @@ +# Other settings + +## Appearance + +You can customize, how your device is displayed in clients with `--device-name` / `device_name` and `--device-type` / `device_type` options. + +## Caching + +You can enable audio data caching by setting a `--cache-path` / `cache_path` and limit its size with `--max-cache-size` / `max_cache_size`. + +## MPRIS + +On linux desktop systems, you can enable `--use-mpris` / `use_mpris` (if your version has enabled that feature). This will give your desktop environment or tools like `playerctl` the option to display information about and control `spotifyd`. diff --git a/docs/src/installation/Cross-Compiling-on-Ubuntu.md b/docs/src/installation/Cross-Compiling-on-Ubuntu.md deleted file mode 100644 index ea8ecd2f..00000000 --- a/docs/src/installation/Cross-Compiling-on-Ubuntu.md +++ /dev/null @@ -1,36 +0,0 @@ -# Ubuntu compilation guide - -These are some notes on cross-compiling, that worked on WSL xenial Ubuntu. - -### Activate the cross compilation in dpkg - -```bash -dpkg --add-architecture armhf -sed 's/deb http/deb \[arch=amd64,i386\] http/' -i /etc/apt/sources.list -echo >/etc/apt/sources.list <_backend` as a feature flag. We currently support `alsa`, `pulseaudio` and `portaudio`. - -`Spotifyd` provides the following additional functionality: - -| Feature Flag | Description | -|--------------|-------------------------------------------------------------------------------------| -| dbus_keyring | Provides password authentication over the system's keyring (supports all platforms) | -| dbus_mpris | Provides multimedia key support (Linux only) | - -> __Note:__ Compiling Spotifyd with all features and the pulseaudio backend on Ubuntu would result in the following command: `cargo build --release --no-default-features --features pulseaudio_backend,dbus_keyring,dbus_mpris` - -## Media controls - -Spotifyd implements the [MPRIS D-Bus Interface Specification][mpris-specification], meaning that it can be controlled by generic media playback controllers such as [playerctl][playerctl-homepage] as well as some tools specifically designed for use with the official Spotify client such as [sp][sp-homepage]. - -> __Note:__ Make sure to rename the service name within the `sp` script to `spotifyd`! - -Although the code greatly improved, this feature is still considered experimental. Make sure to open an issue if you encounter any issues while using other players to control `spotifyd`. - -## Audio Backends - -By default, the audio backend is ALSA, as ALSA is available by default on a lot of machines and usually doesn't require extra dependencies. There is also support for `pulseaudio` and `portaudio`. - -> __Note:__ To disable this audio backend, pass `--no-default-features` down during compilation. - -### PulseAudio - -To use PulseAudio, compile with the `--features` flag to enable -it: - -```bash -cargo build --release --features "pulseaudio_backend" -``` - -You will need the development package for PulseAudio, as well -as `build-essential` or the equivalent package of your distribution. - -### PortAudio - -To use PortAudio (works on macOS), compile with the `--features` flag to enable it: - -```bash -cargo build --release --no-default-features --features="portaudio_backend" -``` - -> __Note:__ It is important that you also pass down `--no-default-features` as macOS doesn't support the `alsa_backend` feature! - -### Rodio - -To use Rodio (works on Windows, OSX, Linux), compile with the `--features` flag to enable it: - -```bash -cargo build --release --no-default-features --features="rodio_backend" -``` - -On Linux you will need the development package for alsa and make/gcc. (`libasound2-dev`,`build-essential` on debian, `alsa-lib-devel`,`make`,`gcc` on fedora) - -[mpris-specification]: https://specifications.freedesktop.org/mpris-spec/latest/ - -### JACK Audio Connection Kit - -To use the [JACK](http://jackaudio.org) backend on Linux, compile with the `--features` flag to enable it: - -```bash -cargo build --release --no-default-features --features="rodiojack_backend" -``` - -You will need the development packages for alsa, make/gcc, and JACK. (`libasound2-dev`, `build-essential`, and `libjack-dev` on Debian; `alsa-lib-devel`, `make`, `gcc`, and `jack-audio-connection-kit-devel` on Fedora.) - -> __Note__: when Spotifyd starts with this backend, it will create a JACK output device named `cpal_client_out` with two ports: `out_0` for the left channel and `out_1` for the right. diff --git a/docs/src/installation/Fedora.md b/docs/src/installation/Fedora.md deleted file mode 100644 index 554d1d35..00000000 --- a/docs/src/installation/Fedora.md +++ /dev/null @@ -1,22 +0,0 @@ -# Fedora installation guide - -## Install the requirements (not including Rust) - -`sudo dnf install portaudio-devel` - -## Clone the repository - -`git clone https://github.com/Spotifyd/spotifyd.git` - -## Building spotifyd - -```bash -cd spotifyd -cargo build --release -``` - -The resulting binary will be placed in `target/release/spotifyd` - -## Running spotifyd - -You can run it using `./target/release/spotifyd` \ No newline at end of file diff --git a/docs/src/installation/FreeBSD.md b/docs/src/installation/FreeBSD.md deleted file mode 100644 index 0217d780..00000000 --- a/docs/src/installation/FreeBSD.md +++ /dev/null @@ -1,35 +0,0 @@ -# FreeBSD install guide - -This guide will help you to install `spotifyd` on FreeBSD and have it always running. - -`spotifyd` is available for the FreeBSD architectures : - -* amd64 -* i386 -* arm64 - -## Install - -```sh -sudo pkg install spotifyd -``` - -## Configuring spotifyd - -If you installed spotifyd using the above method, you'll either need to supply `--backend portaudio` as a command-line argument or add `backend = "portaudio"` to `/usr/local/etc/spotifyd.conf`. - -Apart from that, spotifyd comes pre-configured with defaults that should be working in most cases, but if you want to tweak it further to your needs, have a look at the [configuration section](../config/) of this book. - -## Start the service - -```bash -sudo service spotifyd onestart -``` - -Now see if you can find it in the normal Spotify client (Devices in right bottom corner). Retry the above steps if you can't find it. - -## Starting spotifyd at boot - -```sh -sudo sysrc spotifyd_enable=YES -``` diff --git a/docs/src/installation/MacOS.md b/docs/src/installation/MacOS.md deleted file mode 100644 index f3d6b67a..00000000 --- a/docs/src/installation/MacOS.md +++ /dev/null @@ -1,9 +0,0 @@ -# MacOS installation Guide - -spotifyd is available via Homebrew and can be installed as follows: - -`brew install spotifyd` - -One can then enable it as a service at startup: - -`brew services start spotifyd` \ No newline at end of file diff --git a/docs/src/installation/OpenBSD.md b/docs/src/installation/OpenBSD.md deleted file mode 100644 index 4de23376..00000000 --- a/docs/src/installation/OpenBSD.md +++ /dev/null @@ -1,25 +0,0 @@ -# OpenBSD install guide - -`spotifyd` is available on all supported Rust architectures: - -* aarch64 -* amd64 -* i386 -* powerpc64 -* riscv64 -* sparc64 - -## Install - -```sh -# pkg_add spotifyd -``` - -## Configuring spotifyd - -The official package uses PortAudio and works out of the box, no configuration is required. - -## Running spotifyd - -You may start `spotifyd` as background daemon in your `~/.xsession` X11 startup script -or have clients like `spotify-qt` start/stop it accordingly. diff --git a/docs/src/installation/README.md b/docs/src/installation/README.md index 2dd2d4eb..4d374dce 100644 --- a/docs/src/installation/README.md +++ b/docs/src/installation/README.md @@ -1,88 +1,74 @@ # Installation -## Provided binaries +Getting `spotifyd` on your system should be as easy as downloading a binary in most cases. +If you'd like to learn how to compile `spotifyd` yourself, head over to [building from source](./source.md). And if you're running a 64-bit RaspbianOS system, have a look [here](./raspbian64.md). -We provide pre-built binaries through GitHub Actions for the more popular platforms: Linux, macOS and ARMv7. You can find them [here](https://github.com/Spotifyd/spotifyd/releases). For extra integrity, the file's SHA-512 gets calculated and uploaded as well. +## Linux -The provided binaries come in two flavours, `slim` and `full`. Each are compiled with different features. `slim` only contains the platform's most used audio backend, `full` has also all optional features enabled (see [Feature Flags](#feature-flags)). +Some linux distributions include `spotifyd` in their official repositories. Have a look at [Repology](https://repology.org/project/spotifyd/versions) +for a list of the distributions that currently ship an up-to-date version of `spotifyd`. -## Provided packages +If your distribution is not supported or the provided version is too old, skip to [this section](#installing-from-releases) in order to install one of our pre-built binaries. -There are packages for the following systems: +## macOS -- [Arch Linux (via the Extra repository)](https://archlinux.org/packages/extra/x86_64/spotifyd/) -- [MacOS (via homebrew)](./MacOS.md) +If you're a homebrew user, installing `spotifyd` is as easy as running -## Building from source +```console +brew install spotifyd +``` -You can also compile `Spotifyd` yourself, allowing you to make use of feature flags. `Spotifyd` is written in Rust. You can download the toolchain (compiler and package manager) over at [rustup.rs](https://rustup.rs). Follow their instructions to get started. +## FreeBSD -> __Note:__ Please make sure that you compile the package using the most recent `stable` version of Rust available through `rustup`. Some distro versions are quite outdated and might result in compilation errors. +On FreeBSD, a package is available and can be installed with `pkg install spotifyd`. -`Spotifyd` might require additional libraries during build and runtime, depending on your platform and the way to compile it (static or dynamic). The following table shows the libraries needed for each OS respectively. +## OpenBSD -| Target Platform | Libraries | -|-----------------|------------------------------------------------------| -| Fedora | alsa-lib-devel make gcc | -| openSUSE | alsa-devel make gcc | -| Debian | libasound2-dev libssl-dev libpulse-dev libdbus-1-dev | -| Arch | base-devel alsa-lib libogg libpulse dbus | -| macOS | dbus pkg-config portaudio | +On OpenBSD, a package is available and can be installed with `pkg_add spotifyd`. -> __Note:__ The package names for Linux are the ones used on Debian based distributions (like Ubuntu). You will need to adapt the packages for your distribution respectively. +## Installing from releases -To compile the binary, run +If none of the above methods work for you, you can also use our provided binaries. -```bash -cargo build --release -``` +First, you need to find a suitable binary for your platform. The provided binaries differ in the available features +and the platform architecture that they were built for. You can find the latest binaries [here](https://github.com/Spotifyd/spotifyd/releases). -To install the resulting binary, run +**Feature Sets:** -```bash -cargo install --path . --locked -``` +- `full`: **all audio backends** and **MPRIS** support +- `default`: **one audio backend** (depending on your platform: PulseAudio, PortAudio, ALSA) and **MPRIS** support +- `slim`: **one audio backend** (depending on your platform) and **no MPRIS** support (good for headless systems) -### Installing with Cargo +If you're unsure which version to choose, just go for `default` on desktop systems and `slim` on headless systems. -If you have `cargo` installed, you can directly install `spotifyd` by running: +**Architecture:** -```bash -cargo install spotifyd --locked -``` +If you're on Linux, check your platform architecture with `uname -m`: -That will compile and install `spotifyd`'s latest version under `$HOME/.cargo/bin` for you. +- `x86_64`: Download one of the `spotifyd-linux-{full,default,slim}.tar.gz` packages. +- `armhf`, `armv7`: Download one of the `spotifyd-linux-armhf-{full,default,slim}.tar.gz` packages. +- `armv6`: Download the `spotifyd-linux-armv6-slim.tar.gz` package. +- `aarch64`: Head over to the [RaspberryPi OS 64-bit installation guide](./raspberrypi64.md). -### Building a Debian package +If you're on macOS, download one of the `spotifyd-macos-{full,default,slim}.tar.gz` packages. -You can use the `cargo-deb` create in order to build a Debian package from source. -Install it by: +You should now extract the downloaded archive, make the `spotifyd` file executable and copy it to a sensible location. This can be done using the following commands: -```bash -cargo install cargo-deb +```console +$ tar xzf spotifyd-*.tar.gz # extract +$ cd spotifyd-*/ +$ chmod +x spotifyd # make binary executable +$ # move to correct location, e.g. on Linux: +$ # for a user-wide installation (make sure that your $PATH includes ~/.local/bin) +$ mv spotifyd ~/.local/bin/spotifyd +$ # for a system-wide installation +$ sudo chown root:root spotifyd +$ sudo mv spotifyd /usr/local/bin/spotifyd ``` -Then you can build and install the Debian package with: - -```bash -cargo deb --install -``` - -Note, that when building a Debian package, the `--release` is passed to the -build command already and you do not need to specify it yourself. See for the -flags that are set by default in `Cargo.toml`. - -### Feature Flags - -`Spotifyd` is split into a base package plus additional features that can be toggled on or off during compilation. Those can be split into two groups: The audio backend features that are responsible for playing back the music and additional functionality features, which enhance your experience using `spotifyd`. - -To enable an additional audio backend, pass `_backend` as a feature flag. We currently support `alsa`, `pulseaudio` and `portaudio`. - -`Spotifyd` provides the following additional functionality: +## Running -| Feature Flag | Description | -|--------------|-------------------------------------------------------------------------------------| -| dbus_keyring | Provides password authentication over the system's keyring (supports all platforms) | -| dbus_mpris | Provides multimedia key support (Linux and BSD only) | +Now that you have installed `spotifyd`, you can check if everything was successful by running `spotifyd --version`. -> __Note:__ Compiling Spotifyd with all features and the pulseaudio backend on Ubuntu would result in the following command: `cargo build --release --no-default-features --features pulseaudio_backend,dbus_keyring,dbus_mpris` +You should be ready to go now and after running `spotifyd --no-daemon`, it should appear in an **official** Spotify client which is on the same network. +If this does not work, you can head over to the [troubleshooting section](../troubleshooting.md) or look at [different methods of authentication](../configuration/auth.md). diff --git a/docs/src/installation/Raspberry-Pi.md b/docs/src/installation/Raspberry-Pi.md deleted file mode 100644 index b241a09c..00000000 --- a/docs/src/installation/Raspberry-Pi.md +++ /dev/null @@ -1,47 +0,0 @@ -# Raspberry Pi install guide - -This guide will help you to install `spotifyd` on a Raspberry Pi and have it always running. - -## Download - -1. Download the latest ARMv6 from (use `wget`) -2. Unzip the file: `tar xzf spotifyd-linux-arm6*` -You will now see a file called `spotifyd`. You can run it with `./spotifyd --no-daemon` - -## Systemd daemon file - -Create a systemd service file and copy the [default configuration](https://github.com/Spotifyd/spotifyd/blob/master/contrib/spotifyd.service) into it. Change **ExecStart** to where you unzipped the `spotifyd` binary. - -```bash -sudo nano /etc/systemd/user/spotifyd.service -``` - -if you want to run as user instead of root or have some `Failed to get D-Bus connection: Connection refused`, you define `spotifyd.service` in your home directory: - -```bash -mkdir -p ~/.config/systemd/user/ -nano ~/.config/systemd/user/spotifyd.service -systemctl --user daemon-reload -``` - -## Configuring spotifyd - -Spotifyd comes pre-configured with defaults that should be working in most cases, but if you want to tweak it further to your needs, have a look at the [configuration section](../config/) of this book. - -## Start the service - -```bash -systemctl --user start spotifyd.service -``` - -Now see if you can find it in the normal Spotify client (Devices in right bottom corner). Retry the above steps if you can't find it. - -## Starting spotifyd at boot - -```bash -sudo loginctl enable-linger -systemctl --user enable spotifyd.service -``` - -The first command is required to enable your user to run long-running services. Without it `systemd` would kill the `spotifyd` process as soon as you log out, and only run it when you log in. -Now `spotifyd` is always running on the Pi, so you can use it as a listening device remotely! diff --git a/docs/src/installation/Ubuntu.md b/docs/src/installation/Ubuntu.md deleted file mode 100644 index 93e3cdd7..00000000 --- a/docs/src/installation/Ubuntu.md +++ /dev/null @@ -1,37 +0,0 @@ -# Ubuntu install guide - -## Install the rust toolchain - -To install the latest rust toolchain, follow the installation instructions on [rustup.rs][rustup]. - -> **Note:** If you installed rust before via apt, you need to remove it before installing rustup. -> We recommend to always use the latest version and don't guarantee compatibility with older ones. - -## Install the requirements - -```bash -sudo apt install libasound2-dev libssl-dev pkg-config -``` - -## Clone the repository - -```bash -git clone https://github.com/Spotifyd/spotifyd.git -``` - -## Building spotifyd - -This takes a while... - -```bash -cd spotifyd -cargo build --release -``` - -The resulting binary will be placed in `target/release/spotifyd` - -## Running spotifyd - -You can run it using `./target/release/spotifyd` - -[rustup]: https://rustup.rs/ diff --git a/docs/src/installation/raspberrypi64.md b/docs/src/installation/raspberrypi64.md new file mode 100644 index 00000000..e30deca4 --- /dev/null +++ b/docs/src/installation/raspberrypi64.md @@ -0,0 +1,30 @@ +# Installation on RaspberryPi OS 64-bit + +Unfortunately, we do not yet provide 64-bit binaries for ARM. +Trying to run them will result in `cannot execute: required file not found`. + +To run spotifyd on a 64-bit Raspberry Pi OS, you have two possiblities. Build the 64-bit binary by yourself or add the 32-bit architecture as an additional architecture to your 64-bit Raspberry Pi OS. + +## Option 1: Building yourself + +To build `spotifyd` yourself, head over to [Building from source](./source.md). Note, however, that building can take a long time, especially on low-power devices like a RaspberryPi. + +## Option 2: Add the 32-bit architecture + +### Adding architecture and dependency packages + +These commands add the architecture and install the required packages for the architecure: + +```bash +dpkg --add-architecture armhf +sudo apt update +sudo apt install libasound2-plugins:armhf +``` + +Now you can go on with the [regular install guide](./), by assuming the `armhf` architecture. + +Downloading other variants than thin like full or default may require further armhf packages to be installed with the command like above: + +```console +sudo apt install packagename:armhf +``` diff --git a/docs/src/installation/service.md b/docs/src/installation/service.md new file mode 100644 index 00000000..fc2cf90c --- /dev/null +++ b/docs/src/installation/service.md @@ -0,0 +1,34 @@ +# Running as a service + +Most people want to have `spotifyd` always running in the background. The preferred method to do this depends on the OS you're using. + +## Linux + +If you installed `spotifyd` directly from your distribution, chances are that the installation includes a service definition such that you can run + +```console +$ systemctl --user start spotifyd # start spotifyd using systemd +$ systemctl --user enable --now spotifyd # start spotifyd and enable starting on login +``` + +If you installed `spotifyd` some other way, head over to [the advanced section](../advanced/systemd.md) for further instructions. + +## macOS + +If you installed `spotifyd` using brew, the following commands should do the trick + +```console +$ brew services run spotifyd # start the service once +$ brew services start spotifyd # start spotifyd and enable starting on boot +``` + +If you installed `spotifyd` without brew, [the advanced section](../advanced/launchd.md) has got you covered. + +## FreeBSD + +When installed via the package manager, the following commands are available: + +```console +$ sudo service spotifyd onestart # start spotifyd once +$ sudo sysrc spotifyd_enable=YES # enable starting spotifyd on boot +``` diff --git a/docs/src/installation/source.md b/docs/src/installation/source.md new file mode 100644 index 00000000..a29ce955 --- /dev/null +++ b/docs/src/installation/source.md @@ -0,0 +1,81 @@ +# Building from source + +You can also compile `spotifyd` yourself, allowing you to tailor it perfectly to your needs or get the latest fixes. `spotifyd` is written in Rust. You can download the toolchain (compiler and package manager) over at [rustup.rs](https://rustup.rs). Follow their instructions to get started. + +> __Note:__ Please make sure that you compile the package using the most recent `stable` version of Rust available through `rustup`. Some distro versions are quite outdated and might result in compilation errors. + +## Required packages + +`spotifyd` might require additional libraries during build and runtime, depending on your platform and the way to compile it (static or dynamic). The following table shows the libraries needed for each OS respectively. + +| Target Platform | Libraries | +|-----------------|------------------------------------------------------| +| Fedora | alsa-lib-devel make gcc | +| openSUSE | alsa-devel make gcc | +| Debian | libasound2-dev libssl-dev libpulse-dev libdbus-1-dev | +| Arch | base-devel alsa-lib libogg libpulse dbus | +| macOS | dbus pkg-config portaudio | + +## Installing with cargo + +To build and install the latest version of `spotifyd`, you can use the package manager for rust. The base command is the following + +```console +cargo install spotifyd --locked +``` + +If you would rather install from the latest commit on GitHub, download or clone the project, enter the directory and run + +```console +cargo install --path . --locked +``` + +> __Note:__ Both methods will install the binary in `$XDG_DATA_HOME/cargo/bin` or `$HOME/.cargo/bin`. To execute it, you must make sure that this location is part of your shell's `$PATH` variable. Also, you might have to change the paths when following other parts of this documentation. + +## Compiling with cargo + +To just build the binary without installing, run + +```console +cargo build --release --locked +``` + +This will build the binary and leave the result at `./target/release/spotifyd`. + +## Building a Debian package + +You can use the `cargo-deb` crate in order to build a Debian package from source. +Install it by: + +```console +cargo install cargo-deb +``` + +Then you can build and install the Debian package with: + +```console +cargo deb --install +``` + +Note, that when building a Debian package, the `--release` is passed to the +build command already and you do not need to specify it yourself. See for the +flags that are set by default in `Cargo.toml`. + +## Feature Flags + +`spotifyd` is split into a base package plus additional features that can be toggled on or off during compilation. Those can be split into two groups: The audio backend features that are responsible for playing back the music and additional functionality features, which enhance your experience using `spotifyd`. + +| Feature Flag | Description | +|--------------|-------------------------------------------------------------------------------------| +| `alsa_backend` | Provides support for the ALSA backend. Should work in most setups and is enabled by default. | +| `pulseaudio_backend` | Support for PulseAudio. | +| `rodio_backend` | Rust-native implementation of audio backends on all platforms. Does not need any external packages to be installed. | +| `portaudio_backend` | Audio backend that can be used on non-Linux systems. | +| `rodiojack_backend` | Support for the Jack backend. | +| `dbus_mpris` | Provides multimedia key support (Linux and BSD only) | + +To customize your build, pass a subset of the features listed above to any of the `cargo` commands above via `--features ,,...`. Disable the default feature `alsa_backend` with `--no-default-features`. So an example command could look like the following: + +``` +cargo install spotifyd --locked --no-default-features --features rodio_backend,dbus_mpris +``` diff --git a/docs/src/other/D-Bus-control.md b/docs/src/other/D-Bus-control.md deleted file mode 100644 index 4d9b13c4..00000000 --- a/docs/src/other/D-Bus-control.md +++ /dev/null @@ -1,57 +0,0 @@ -# D-Bus control - -`Spotifyd` can be configured to bind to D-Bus, exposing controls including standard MPRIS interfaces. - -To configure D-Bus, see `use_mpris` and `dbus_type` in the [configuration file](../config/File.md). `Spotifyd` must also be built with the `dbus_mpris` feature, which is available in the `full` flavour of the [provided binaries](https://github.com/Spotifyd/spotifyd/releases). - -The D-Bus service name will be in the format `org.mpris.MediaPlayer2.spotifyd.instance`, where `` is the process id. - -## Interfaces - -### MPRIS - -The `org.mpris.MediaPlayer2` and `org.mpris.MediaPlayer2.Player` interfaces from the [MPRIS specification](https://specifications.freedesktop.org/mpris-spec/latest/) are implemented. - -Note the `Volume` property of the `org.mpris.MediaPlayer2.Player` interface is read-only, despite supporting writes in the specification. - -### Spotifyd Controls - -The `rs.spotifyd.Controls` interface includes additional non-standard controls. - -- Method `TransferPlayback`: transfers Spotify playback to `spotifyd` -- Method `VolumeUp`: increases player volume -- Method `VolumeDown`: decreases player volume - -## Usage - -`Spotifyd` can be controlled by applications which support MPRIS such as the [playerctl](https://github.com/altdesktop/playerctl) command-line utility. - -The `dbus-send` command can also be used to control `spotifyd`. For example: - -- Find the service registered by `spotifyd`: `dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames | grep spotifyd` -- Transfer playback to `spotifyd`: `dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotifyd.instancexxx /rs/spotifyd/Controls rs.spotifyd.Controls.TransferPlayback` -- Get metadata for the current track: `dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotifyd.instancexxx /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:org.mpris.MediaPlayer2.Player string:Metadata` - -## Troubleshooting - -### "Failed to initialize DBus connection" on a headless system - -Where no graphical session is available, the system bus can be used by setting the `dbus_type` configuration option to `system`. - -### "Failed to register dbus player name" using the system bus - -`Spotifyd` may not have permission to register the D-Bus service due to D-Bus security policies. It should be granted permission to own any service with the prefix "org.mpris.MediaPlayer2.spotifyd". - -For example, this statement can be added to the default policy in `/usr/share/dbus-1/system.conf`. - -```xml - -``` - -It may also be necessary to add a statement to allow clients to send messages. - -```xml - -``` - -Make sure to reload the D-Bus configuration after making changes. For example `sudo systemctl reload dbus`. diff --git a/docs/src/other/Troubleshooting.md b/docs/src/other/Troubleshooting.md deleted file mode 100644 index 090a2e1a..00000000 --- a/docs/src/other/Troubleshooting.md +++ /dev/null @@ -1,17 +0,0 @@ -# Troubleshooting on FreeBSD - -On FreeBSD 11.2, I installed `spotifyd` via the official binary package from the FreeBSD repos. -I configured it accordingly with `backend = portaudio`, but I wasn't getting any sound. The issue was that the device I needed to output sound to is not PortAudio's default. I don't know how PortAudio determines its default, and I initially couldn't figure out the format or device names that spotifyd wanted in its configuration. Here are some pointers that may help you if you find yourself in the same situation. - -If you have `portaudio` as your backend and set your device to `?`, spotifyd will output all of the available PortAudio devices it can find on your system. For mine, that looks like this: - -```bash -- /dev/dsp0 (default) -- /dev/dsp1 -- /dev/dsp2 -- /dev/dsp -``` - -The 4th device (index 3, starting from 0) (`/dev/dsp`) is the output device that I needed. That coincides with the `pcm3` (also index 3, starting from 0) device that FreeBSD lists in `dmesg` as well as the `hw.snd.default_unit=3` sysctl that I use to set the device as OSS's default. It seems like the index number correlates across each of those enumerations. - -Once I set `device = "/dev/dsp"` (quotes here seem necessary) in the config, the sound started working. It may take some experimentation to find the correct output on other systems. \ No newline at end of file diff --git a/docs/src/troubleshooting.md b/docs/src/troubleshooting.md new file mode 100644 index 00000000..6144c18b --- /dev/null +++ b/docs/src/troubleshooting.md @@ -0,0 +1,18 @@ +# Troubleshooting + +## no sound on FreeBSD + +If you have correctly configured `spotifyd` to use `portaudio` and everything seems to be working except that there's no sound, you might have to switch to a different audio device. + +If you have `portaudio` as your backend and set your device to `?`, spotifyd will output all of the available PortAudio devices it can find on your system. This could look like the following + +```bash +- /dev/dsp0 (default) +- /dev/dsp1 +- /dev/dsp2 +- /dev/dsp +``` + +Assume that the 4th device (index 3, starting from 0, `/dev/dsp`) is the output device that is needed. That coincides with the `pcm3` (also index 3, starting from 0) device that FreeBSD lists in `dmesg` as well as the `hw.snd.default_unit=3` sysctl that is used to set the device as OSS's default. It seems like the index number correlates across each of those enumerations. + +After setting `device = "/dev/dsp"` in the config, the sound should start working. If not, you can try the other possible values that are available. diff --git a/src/config.rs b/src/config.rs index 7a31a097..78f99e6e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -285,7 +285,7 @@ pub struct SharedConfigValues { /// The audio backend to use #[arg(long, short, value_parser = possible_backends())] - #[serde(deserialize_with = "deserialize_backend")] + #[serde(deserialize_with = "deserialize_backend", default)] backend: Option, /// The volume controller to use @@ -420,6 +420,24 @@ impl FileConfig { } } +fn get_missing_feature(path: &serde_ignored::Path<'_>) -> Option<&'static str> { + const DISABLED_CONFIGS: &[(&str, &[&str])] = &[ + #[cfg(not(feature = "alsa_backend"))] + ("alsa_backend", &["control", "mixer"]), + #[cfg(not(feature = "dbus_mpris"))] + ("dbus_mpris", &["use_mpris", "dbus_type"]), + ]; + + if let serde_ignored::Path::Map { key, .. } = path { + for (feature, params) in DISABLED_CONFIGS { + if params.contains(&key.as_str()) { + return Some(*feature); + } + } + } + None +} + impl CliConfig { pub fn load_config_file_values(&mut self) -> Result<(), Report> { let config_file_path = match self.config_path.clone().or_else(get_config_file) { @@ -439,7 +457,14 @@ impl CliConfig { } }; - let config_content: FileConfig = toml::from_str(&content)?; + let toml_de = toml::Deserializer::new(&content); + let config_content: FileConfig = serde_ignored::deserialize(toml_de, |path| { + if let Some(feature) = get_missing_feature(&path) { + warn!("Warning: The config key '{path}' is ignored, because the feature '{feature}' is missing in this build"); + } else { + warn!("Warning: Unknown key '{path}' in config will be ignored"); + } + })?; // The call to get_merged_sections consumes the FileConfig! if let Some(merged_sections) = config_content.get_merged_sections() { @@ -734,4 +759,57 @@ mod tests { spotifyd_section.device_name = Some("spotifyd-test".to_string()); assert_eq!(merged_config, spotifyd_section); } + + #[test] + fn test_example_config() { + let example_config = include_str!("../contrib/spotifyd.conf"); + + let toml_de = toml::Deserializer::new(example_config); + + let config: FileConfig = serde_ignored::deserialize(toml_de, |path| { + panic!("Unknown key in (commented) example config: '{}'", path) + }) + .expect("Commented example config should be valid"); + + assert_eq!( + (config.global, config.spotifyd), + (Some(SharedConfigValues::default()), None), + "example config should not do anything by default, but contain the global section" + ); + + let uncommented_example_config = example_config + .lines() + .map(|line| { + // uncomment any line starting with #[a-zA-Z] + line.strip_prefix("#") + .filter(|rest| { + // uncomment if the rest is a valid config line + // if alsa_backend is not enabled, ignore the 'backend = "alsa"' line + rest.starts_with(char::is_alphabetic) + && (cfg!(feature = "alsa_backend") || !rest.starts_with("backend")) + }) + .unwrap_or(line) + }) + .collect::>() + .join("\n"); + + let toml_de = toml::Deserializer::new(&uncommented_example_config); + let config: FileConfig = serde_ignored::deserialize(toml_de, |path| { + if get_missing_feature(&path).is_none() { + panic!("Unknown configuration key in example config: {}", path); + } + }) + .expect("Uncommented example config should be valid"); + + assert!( + config.spotifyd.is_none(), + "example config should not have a spotifyd section" + ); + assert!( + config + .global + .is_some_and(|global| global != SharedConfigValues::default()), + "uncommented example config should contain some values" + ); + } }