Jack Atkinson

Scientist, Archer, Coder

Spotify from the command line

7 minutes
December 11, 2022
computing,  howto,  arch,  cli,  spotify, 

During the setup and build of a new machine I was making efforts to explore and learn the Linux environment in deeper detail. A large part of this involved setting up various utilities from (closer-to-)scratch. One of these was spotify from the command line. Since I had to implement a couple of workarounds I thought I’d write about it in the hope others might find it useful in future.

`

Why spotify from the command line?

  1. I’m currently in the command line hipster mindset. Let’s just be honest, that has a lot to do with it. In serious though I am terrible at having multiple windows and tabs open cluttering up my computer and mind. Reducing spotify to a command line tool that is easily opened from a terminal when needed should help reduce this.
  2. It should throw up a number of interesting learning opportunities around audio and software.
  3. Spotify’s linux app is proprietry. Whilst I have nothing against spotify providing an audio streaming service, this fits in with the FOSS ethos and knowing exactly what is on my computer.

To achieve this we are going to make use of two pieces of software, spotifyd to stream audio, and spotify-tui to access the API and provide an interface.

A significant amount of this was aided by an article similar to this one written by Sophia Brandt and tha package documentation. However, anything in Linux is rarely straightforward, and there are a few differences in the way I did things.

spotifyd client

The first step is to install a client for streaming music from spotify. To do this I used spotifyd as recommended by the command-line client I planned to use (spotify-tui).

Instructions for setting this up on the github repo are fairly minimal. On Arch this involved running sudo pacman -S spotifyd. Access to your account then requires a config file which I placed at ~/.config/spotifyd/spotifyd.conf. If you do enough digging there is an example of this in the repo.

For my purposes I used pulseaudio, though this was established through a process of trial and error. Since I am using wayland I have PipeWire which features compatability interfaces on to both ALSA and PulseAudio. Setting pulseaudio is what worked for me.

device_name is how this device will appear in spotify’s ‘device list’ to be controlled from other devices. I chose the name of the laptop I am installing it on.

[global]
# Your Spotify account name.
username = "<your spotify username>"

# Your Spotify account password.
password = "<your spotify 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 = "pass show spotify | head -n 1"

# The audio backend used to play music. To get
# a list of possible backends, run `spotifyd --help`.
backend = "pulseaudio"

# The name that gets displayed under the connect tab on
# official clients. Spaces are not allowed!
device_name = "<your device name>"

# 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 = "computer"

This script can now be run through spotifyd --verbose to view any outputs and aid with debugging. spotifyd recommend you then create a system daemon service through systemctl --user enable --now spotifyd.service. You can check that it is running properly with systemctl --user status spotifyd.service and journalctl.

I did not do this, however, as I want to make use of pass, the Linux password manager. The setup for doing this in spotifyd is currently buggy (GitHub issue #696) so I’ll implement a workaround below. Perhaps once I have had a play around I might look at this if it hasn’t been resolved.

spotify-tui

install

The next step is to install spotify-tui through which we will interact with spotify. This does not stream music, but instead interacts with the spotify API to display information and provide navigation and control, it interfaces with spotifyd to then stream and play music. spotify-tui is available on the AUR and can be installed by your method of choice (mine is pikaur): pikaur -S spotify-tui.

Here there is a slight nuance as, for me, the default install raises issues with locating OpenSSL headers. Whilst the relevant issues on GitHub were not helpful, there is a reddit post that came in useful. The solution was to update the PKGBUILD when pikaur asks and change

  cargo build --release --frozen

to

  cargo update
  cargo build --release

I suspect this occurs because spotify-tui has not been updated in a year (need to keep an eye on this in case it becomes unsupported) and the --frozen flag now refers to packages that are now out of date.

API access

The next step is to generate a key to access the spotify API. The instructions in the documentation are very clear for this:

  1. Go to the Spotify dashboard
  2. Click ‘Create an app’ You now can see your Client ID and Client Secret
  3. Now click ‘Edit Settings’
  4. Add http://localhost:8888/callback to the Redirect URIs
  5. Scroll down and click ‘Save’
  6. You are now ready to authenticate with Spotify!
  7. Go back to the terminal
  8. Run spt
  9. Enter your Client ID when prompted
  10. Enter your Client Secret when propmted
  11. Press enter to confirm the default port (8888) or enter a custom port
  12. You will be redirected to an official Spotify webpage to ask you for permissions.
  13. After accepting the permissions, you’ll be redirected to localhost. If all goes well, the redirect URL will be parsed automatically and now you’re done. If the local webserver fails for some reason you’ll be redirected to a blank webpage that might say something like “Connection Refused” since no server is running. Regardless, copy the URL and paste into the prompt in the terminal.

configuration

This first run generates a YAML config file at ~/.config/spotify-tui/config.yml (and a client file for authentication). The documentation has an example.

Launching

As mentioned above, I did not set spotifyd up as a systemd process as I wanted to implement a password workaround so that I could use the Linux password manager pass. It also means that I don’t need to have spotifyd running in the background unless I need it which might save on some energy. This was inspired by a youtube video for launching spotifyd when required, and I built on top of it to add pass functionality.

I added the following alias function to my ~/.bashrc allowing me to successfully launch spt with the command spotify:

# launch spotify-tui with spotifyd (if
#   not already running)
spotify() {
    if ! pgrep -c "spotifyd" > /dev/null
    then
      echo "starting spotifyd..."
      pass show spotify >/dev/null
      spotifyd
    fi

    spt
}

The command starts a process that first checks if spotifyd is already running. If it is, great, if not then the password is requested from pass and redirected to /dev/null. This has the effect of prompting us for our gpg key to release the password. I have a 5 second cache on my gpg key (set default-cache-ttl 5 in ~/.gnupg/gpg-agent.conf) meaning that it is still available when called through spotifyd. Note that we need to comment out password = "<your spotify password>" and uncomment password_cmd = "pass show spotify | head -n 1" in ~/.config/spotifyd/spotifyd.conf.

Closing

At the end of all this I am able to control and play spotify through my laptop using minimalist FOSS from the command line. It took me a while to realise that I search by typing /<your search term>, and whilst some windows support looping scrolling, others need to be navigated in a pgdn, pgup fashion with ctrl+d and ctrl+u. My final bit of coding involved binding the play/pause and skip buttons to the

bindsym XF86AudioPlay exec spt playback --toggle
bindsym XF86AudioNext exec spt playback --next
bindsym XF86AudioPrev exec spt playback --previous

My one main gripe is more with spotify than the software here. The spotify API only allows control over spotify clients on other devices, so whilst I can control playback on my laptop from my phone and vice versa I can’t control my third-party speaker system from spotify-tui, only from the proprietry client on my phone.

I’ve also come across an issue where one of the podcasts I listen to returns an API error when I try and select it in spotify-tui. Interestingly the episodes play if I am controlling spotify from my phone (playing through my laptop). Something to investigate in future perhaps.

A final comment would be that spotify-tui currently displays minimal metadata. It might be nice if it could display a little more info such as album release year etc. This should hopefully be relatively straightforward based on the current code, and I have been meaning to take a look at Rust…