A Spotify speaker and playback controls for GNOME Shell 50, powered by Spotify Soloist. Part of Ghost Assembly.
QuickSpot shows the active artist and song in the top bar and provides play/pause, previous/next, device activation, shuffle, Liked Songs, saved playlists, and named playlist shortcuts. Preferences install or update Soloist and manage its systemd user service. The service exports MPRIS controls for desktop media keys and other media clients, even while the extension is disabled. When no track is available on the active device, the top bar shows only the music icon.
Documentation → — player setup, playlist examples, troubleshooting, architecture, testing, and packaging.
- GNOME Shell 50 with GJS, libsecret, libsoup 3, GTK 4, and libadwaita.
- Python 3.12 or newer, a graphical systemd user session, and PipeWire or PulseAudio.
- A Spotify Premium account and your own Soloist API key.
- An x86_64, aarch64, or armv7l Linux system for the official Soloist download.
- mise for development tools and installation from source.
GNOME libraries come from the host. mise.toml pins development runtimes and tools;
Python development checks use the pinned interpreter.
With mise activated in your shell and just available, from this checkout:
just setup
just installLog out and back in so GNOME discovers the extension, then run:
just enable
just prefsLog out and back in after updating a loaded extension to load its new panel code. Opening preferences does not reload GNOME Shell.
On the Player page:
- Choose Install and save your Soloist API key.
- Choose Start and wait for Ready to pair.
- Open Spotify on your phone or desktop on the same local network, play something, and select QuickSpot in the device menu. The name can be changed in preferences.
First pairing requires the phone or desktop app; the web player cannot discover an unpaired speaker. Preferences distinguish a running service, a connected local API, and a paired speaker. Stop remains available while the player runs, including when the keyring is locked. Start at login follows systemd's configuration. Saving a device name or API key restarts a running player to apply it. An update attempts to restore a previously running service even if downloading fails or the preferences window closes.
Library → Playlist shortcuts accepts a name and a playlist's 22-character ID,
Spotify link, or spotify:playlist:… URI. Select its saved name from the panel to
play it. Shortcuts work without a library login, including playlists such as
Discover Weekly that Spotify may omit from the library API. Add the same playlist
with a new name to rename it; choose Remove to delete its shortcut.
To browse saved playlists and play Liked Songs:
- Create or use a Spotify developer app
and register
http://127.0.0.1:43821/callbackas its redirect URI. - On the Library page, enter its client ID and choose Connect. Keep preferences open to finish browser authorization; Cancel stops the login.
- Authorize the same account paired with the speaker. Liked Songs uses that account's collection; the library login and speaker pairing are separate.
No client secret is needed. Development-mode apps require the app owner to retain
Premium and allow the connecting account. New apps have limits of one client ID per
developer and five users; see Spotify's development-mode requirements.
Login uses PKCE with playlist-read-private and playlist-read-collaborative.
Playlist loading follows pagination, refreshes expired tokens, and observes rate limits.
Credentials can also be imported from an .env file containing
SPOTIFY_SOLOIST_KEY and/or SPOTIFY_CLIENT_ID. Use Import credentials in
preferences or just import-credentials for this checkout's .env.
The file is parsed as literal values and excluded from the extension bundle.
Shuffle → On/Off activates this speaker before changing ordinary shuffle. QuickSpot follows changes made in Spotify and displays Smart Shuffle when reported by Soloist. Enable Smart Shuffle in Spotify's phone app with this speaker selected; Soloist's local API does not expose a command to enable that mode.
Choose audio quality in Spotify with this device selected. Soloist's command line and local API do not expose quality controls or the active bitrate, so QuickSpot cannot confirm that a stream is lossless.
Run just doctor to check installation, service state, saved-key
presence, local API connectivity, and pairing without printing credentials or
account information. A running service alone does not confirm pairing or audible
playback. If Soloist has expired, choose Update in preferences.
For a missing speaker, use the phone or desktop app on the same local network. Allow Spotify local-network access on iOS. Guest Wi-Fi, client isolation, and VPN routing can prevent discovery. Soloist uses multicast DNS (UDP 5353) and a dynamic TCP pairing port, separate from its loopback API. Check network and firewall rules; see Spotify Connect troubleshooting.
Use just logs for extension logs and just logs-player
for fixed launcher diagnostics. Raw Soloist output is silenced because it can
contain credentials and account information.
API keys and OAuth tokens live in GNOME Keyring, outside GSettings, service files, and the extension bundle. Playlist names, shortcut URIs, and the device name live in GSettings. The following paths use the standard XDG 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 its 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, but upstream provides no authentication or Origin validation.
Loopback binding restricts network access without isolating the API from local
processes or browser code able to reach the port.
The installer bounds download and extracted sizes, rejects unsafe archive members, restricts redirects to Spotify's HTTPS download origin, and checks the binary's version response before replacing it. Downloads use mutable upstream URLs with no independent signature or checksum verification; archive validation does not prove authenticity beyond HTTPS. Soloist is downloaded separately and is never included in QuickSpot's bundle.
just uninstallThis 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 systemctl --user stop quickspot-soloist.service.
The project uses native GJS ES modules without a transpilation step or npm runtime
dependencies. justfile defines project commands; run just to list them.
just ci
just test-live
just test-docs
just pack-check
just docsci runs ESLint and Ruff security rules, formatting checks, schema validation,
Node unit tests, Python installer and bundle tests, native GJS integration tests,
documentation browser checks in Chromium and Firefox,
secret scans of working files and Git history, and the build. Dependency checks can
be run with mise exec -- npm audit --ignore-scripts.
setup installs Chromium and Firefox for test-docs. The documentation suite
checks accessibility in both color schemes, mobile layout, keyboard navigation,
reduced motion, local assets, links, and project metadata. docs serves the static
site at http://127.0.0.1:8000; there is no documentation build step or JavaScript.
test-live uses temporary XDG directories, private D-Bus/dconf state, and a headless
GNOME Shell to test startup rollback, populated menus through disable/re-enable,
native GTK preferences, and command-line uninstall. It does not change your
desktop's enabled extensions. Both suites use local fixtures; actual Spotify
authorization, audible playback, discovery from another device, and stream quality
require a real account and manual verification.
just build writes quickspot@napalm255.github.io.shell-extension.zip at the
repository root, assembled
from an explicit runtime file allowlist using Python’s standard library.
just install builds and installs that ZIP for the current user. just pack-check
compares its files and contents with GNOME’s official packer and runs before
just test-live. See AGENTS.md for contribution
instructions. QuickSpot is GPL-3.0-or-later; Soloist has separate upstream
terms and third-party notices.