Ghost Assembly QuickSpot

GNOME Shell extension

QuickSpot

A Spotify speaker, controlled from your top bar.

Spotify Soloist playback, Liked Songs, and named playlist shortcuts. Set up your speaker in preferences, then control it from the GNOME panel.

  • GNOME Shell 50
  • Spotify Premium
  • GPL-3.0-or-later

Install Source on GitHub

QuickSpot in the top bar · illustrated playback
On this page
  1. 01Overview
  2. 02Install
  3. 03Player setup and pairing
  4. 04Playback controls
  5. 05Playlists and library login
  6. 06Preferences
  7. 07Audio quality
  8. 08Troubleshooting
  9. 09Storage and security
  10. 10Uninstall
  11. 11Architecture
  12. 12Testing
  13. 13Packaging
  14. 14Development

01

Overview

QuickSpot turns this computer into a Spotify speaker and puts playback controls in the GNOME top bar. It uses Spotify Soloist for audio playback, downloaded separately from Spotify.

The extension, the player service, and the optional playlist library login have separate lifetimes. Disabling the extension leaves the player and its MPRIS media controls running. Pairing the speaker does not connect the playlist library.

A Spotify speaker

Install and manage Soloist from preferences. Pair once through Spotify’s phone or desktop app.

Your music in the panel

Previous, play/pause, next, device activation, shuffle, Liked Songs, and named playlist shortcuts.

02

Install

Requires GNOME Shell 50; GJS, libsecret, libsoup 3, GTK 4, and libadwaita; Python 3.12 or newer; a graphical systemd user session; and PipeWire or PulseAudio. Spotify Premium and your own Soloist API key are required. Official player downloads support x86_64, aarch64, and armv7l Linux.

With mise activated in your shell and just available, install from a checkout with mise. GNOME libraries come from the host; mise supplies development tools.

Shell
just setup
just install

The build creates quickspot@napalm255.github.io.shell-extension.zip. Installation unpacks it and compiles its settings schema. Log out and back in so GNOME discovers the extension, then enable it and open preferences:

Shell
just enable
just prefs

After updating a loaded extension, log out and back in to load its new panel code. Opening preferences does not reload GNOME Shell.

03

Player setup and pairing

  1. On the Player page, choose Install. Get your own Soloist API key, enter it, and choose Save.
  2. Choose Start and wait for Ready to pair.
  3. Open Spotify’s phone or desktop app on the same local network. Play something and select QuickSpot in its device menu.

The web player cannot discover an unpaired speaker. The device name can be changed in preferences. QuickSpot remembers pairing through Soloist’s stored device identity.

State Meaning
Player not installed Install Soloist before starting.
Player needs setup Choose Repair to restore the service.
API key needed Save a key in GNOME Keyring.
Player stopped The service is available but stopped.
Player running · connection pending The service is running; its local API is not connected yet.
Ready to pair The local API is connected; pair through Spotify.
Paired · ready to play Pairing is complete; this speaker is not the active device.
Connected · this device is active Spotify has selected this speaker. Check audio output separately.

A running service alone does not prove pairing or audible playback. Stop remains available while the player runs, including when GNOME Keyring is locked.

04

Playback controls

Open the top-bar item to use the menu. While a track is available, its label shows artist and title. Playback actions become available when the local speaker is paired.

Control Behavior
Previous / Play or Pause / Next Control playback on the Soloist speaker.
Use this device Activate this speaker in Spotify.
Shuffle → On / Off Activate the speaker and change ordinary shuffle.
Playlist shortcuts Play a saved playlist by its chosen name.
Liked Songs / Your playlists Use the optional connected library account.
Refresh playlists Reload the saved playlist list.
Start / Stop Control the independent player service when setup permits it.
Open Spotify in browser Open the Spotify web player.
QuickSpot settings Open GTK preferences.

Smart Shuffle is displayed when Soloist reports it. Enable that mode in Spotify’s phone app with this speaker selected; About Smart Shuffle… explains the limitation.

05

Playlists and library login

Named playlist shortcuts

On Library → Playlist shortcuts, enter a name and a playlist ID, Spotify link, or URI. These three forms identify the same example playlist:

Playlist input
37i9dQZF1DXcBWIGoYBM5
https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5
spotify:playlist:37i9dQZF1DXcBWIGoYBM5

Choose Add, then select the name in the panel. Shortcuts work without the optional library login, including Discover Weekly and other playlists Spotify may omit from the library API. Add the same playlist under a new name to rename it; Remove deletes its shortcut. Up to 100 shortcuts can be saved.

Saved playlists and Liked Songs

  1. Create or use a Spotify developer app and register http://127.0.0.1:43821/callback as its redirect URI.
  2. Enter the app’s client ID on the Library page and choose Connect. Finish authorization in the browser while keeping preferences open.
  3. Authorize the same account paired with the speaker. Then use Your playlists or Liked Songs in the panel.

No client secret is needed. Login uses PKCE with playlist-read-private and playlist-read-collaborative. Tokens are bound to the client ID that issued them. Playlist loading follows pagination, refreshes expired tokens, and observes rate limits.

Cancel stops the current login; closing preferences cancels it too. Reconnect authorizes again, and Disconnect removes the saved playlist login without unpairing the speaker.

Development-mode apps require their owner to retain Premium and allow the connecting account. See Spotify’s development-mode requirements for current app and user limits.

06

Preferences

Open preferences with just prefs or QuickSpot settings in the panel.

Setting or action Effect
Install / Repair / Update Download Soloist or restore its user service, according to installation state.
Start at login Enable or disable the systemd user service for login.
Name shown in Spotify Default: QuickSpot. Saving restarts a running player.
Soloist API key Store the key in GNOME Keyring. Saving restarts a running player.
Import credentials Read a selected .env file with a Soloist key and/or library client ID.
Spotify client ID / Connect Authorize the optional playlist library in your browser.
Playlist shortcuts Add, rename, and remove saved playlist choices.

An update attempts to restore a previously running service even if downloading fails or preferences closes. Soloist builds expire after 90 days; use Update to install a newer build. See Spotify’s downloads and updates documentation.

Credential import example

Use literal values in a private .env file. Replace these placeholders with your own values; do not commit the file:

.env (placeholders)
SPOTIFY_SOLOIST_KEY=your-soloist-api-key
SPOTIFY_CLIENT_ID=your-developer-app-client-id

Select it with Import credentials, or import this checkout’s .env:

Shell
just import-credentials

Importing the client ID does not authorize the library. Choose Connect separately. The importer parses values literally rather than executing shell code.

07

Audio quality

Choose quality in Spotify with this speaker selected. Soloist’s command line and local API do not expose quality controls or the active bitrate to QuickSpot. QuickSpot cannot confirm that a stream is lossless.

08

Troubleshooting

Start with the credential-safe diagnostic command:

Shell
just doctor

It checks installation, service state, saved-key presence, local API connectivity, and pairing without printing credentials or account information.

Symptom Next step
Extension not found after installation Log out and back in, then enable QuickSpot.
Player needs setup Choose Repair in preferences.
Player failed to start Check the saved API key, network, and audio output. An expired build needs Update.
Local connection stays pending Restart the player and run doctor again.
Speaker missing in Spotify Use the phone or desktop app on the same network. Check guest Wi-Fi, client isolation, VPN routing, and local-network permission on iOS.
Library login fails Check the exact loopback redirect URI, client ID, developer-app access, and Premium requirements. Keep preferences open.
Playlist missing from library Refresh playlists or add a manual playlist shortcut.
Paired but silent Select this speaker and check the host audio output; pairing alone does not verify audio.

Discovery uses multicast DNS (UDP 5353) and a dynamic TCP pairing port, separate from the loopback API. Review applicable network and firewall rules. See Spotify Connect troubleshooting.

Shell
just logs
just logs-player
systemctl --user stop quickspot-soloist.service
systemctl --user start quickspot-soloist.service

Extension logs and fixed launcher diagnostics omit credentials, account data, and track metadata. Raw Soloist output is silenced because it can contain sensitive information.

09

Storage and security

API keys and OAuth tokens live in GNOME Keyring, outside GSettings, service files, and the extension bundle. Device names and playlist shortcut names and URIs live in GSettings. XDG paths fall back to their standard defaults when unset.

Data Location
Soloist binary and upstream notices $XDG_DATA_HOME/quickspot/
Device identity and pairing $XDG_DATA_HOME/quickspot/player/
Audio cache (limited to 1 GiB) $XDG_CACHE_HOME/quickspot/
User service $XDG_CONFIG_HOME/systemd/user/quickspot-soloist.service

Soloist requires the API key in process arguments; processes with sufficient inspection access can see it. Its WebSocket API binds to 127.0.0.1 on a dynamic port. Upstream provides no authentication or Origin validation, so loopback binding does not isolate it from local processes or browser code able to reach the port.

The installer bounds downloads and extraction, rejects unsafe archive members, restricts redirects to Spotify’s HTTPS download origin, and checks the binary’s version response before replacement. Downloads use mutable upstream URLs without independent signature or checksum verification. Archive validation does not prove authenticity beyond HTTPS.

Soloist is downloaded separately and never included in QuickSpot’s bundle. Preserve its upstream terms and third-party notices.

10

Uninstall

Shell
just uninstall

This stops and disables Soloist, then removes the extension. It preserves keyring credentials, player data, the downloaded binary, and the disabled service definition.

Disabling the extension alone leaves the independent player service running. Stop it from preferences or with:

Shell
systemctl --user stop quickspot-soloist.service

11

Architecture

QuickSpot uses native GJS ES modules. The GNOME Shell panel, GTK preferences, and service runner execute in separate processes. Shell UI imports stay in the extension; GTK and Adwaita imports stay in preferences.

Component Responsibility
extension.js Top-bar item, menus, playback actions, and lifecycle teardown.
prefs.js GTK/Adwaita setup, credential entry, library login, and shortcuts.
modules/model.js Pure input validation and presentation decisions, shared with Node tests.
modules/player.js Installation, service, credentials, and playback as distinct states.
modules/soloist.js Loopback WebSocket connection and playback commands.
modules/spotify.js Web API requests, PKCE authorization, and client-bound tokens.
modules/secrets.js / credentials.js GNOME Keyring and bounded literal credential import.
modules/mpris.js Desktop media control bridge.
scripts/soloist-runner.js Player process and MPRIS bridge independent of the extension.
scripts/install_soloist.py Bounded download, safe extraction, service setup, and updates.

The panel and service bridge control Soloist through its local API. Library authorization supplies playlist choices and Liked Songs separately. Teardown releases signals, timers, sockets, subprocesses, and UI references; asynchronous completions are guarded against closed windows and replaced clients.

12

Testing

just test runs Node validation tests, Python installer and bundle tests, and native GJS integration tests. Fixtures use temporary XDG paths and private session buses, without the real account, keyring, player service, or desktop settings.

just test-live adds headless GNOME Shell and GTK checks for startup rollback, populated menus across disable/re-enable, preferences, and command-line uninstall. It leaves the desktop’s enabled extensions alone.

just test-docs checks this site in Chromium and Firefox: accessibility in both color schemes, keyboard navigation, mobile layout, reduced motion, links, assets, and agreement with project metadata. The site ships no JavaScript and loads assets only from its own origin.

Actual Spotify authorization, audible playback, discovery from another device, and stream quality require a real account and manual verification. Automated accessibility checks also need a human review of reading and focus order.

13

Packaging

Shell
just build

The output is quickspot@napalm255.github.io.shell-extension.zip at the repository root, like the other Quick projects. scripts/build.py validates the schema and packages an explicit runtime allowlist using Python’s standard library. just install builds that ZIP and installs it for the current user through gnome-extensions install --force.

just pack-check compares every runtime file and its contents with GNOME’s official extension packer. It also runs before just test-live. Bundle tests verify excluded files stay outside the archive.

Docs, tests, npm dependencies, credentials, downloaded player binaries, and planning artifacts stay outside the ZIP. Update the allowlist when adding runtime files. QuickSpot is GPL-3.0-or-later; Soloist has separate terms and notices.

The repository currently provides local build and verification commands, with no automated release or documentation deployment workflow.

14

Development

mise.toml pins tool versions, justfile owns commands, and npm manages development dependencies and the lockfile. There is no transpilation step or npm runtime dependency.

Shell
just              # list recipes
just setup        # tools, dependencies, docs browsers
just fmt          # format changes
just lint         # source, formatting, schemas
just test         # offline behavior suites
just test-docs    # Chromium and Firefox docs checks
just security     # credential-safe secret scans
just build        # extension ZIP at the repository root
just pack-check   # compare with GNOME’s official packer
just ci           # all checks and build
just test-live    # isolated Shell and GTK checks
just docs         # local docs at localhost:8000

Run ci before submitting changes and test-live when changing panel or preferences behavior. Keep documentation aligned with actual commands and code. See the engineering instructions for contribution conventions.