Skip to content

feat(spotify): add Spotify playback adapter#560

Open
bhutano wants to merge 6 commits intojackwener:mainfrom
bhutano:feat/spotify-adapter
Open

feat(spotify): add Spotify playback adapter#560
bhutano wants to merge 6 commits intojackwener:mainfrom
bhutano:feat/spotify-adapter

Conversation

@bhutano
Copy link
Copy Markdown

@bhutano bhutano commented Mar 28, 2026

Summary

  • Adds a new spotify adapter under src/clis/spotify/
  • Uses Strategy.PUBLIC — no browser required, direct calls to the Spotify Web API
  • OAuth2 authentication with automatic token refresh (tokens stored in ~/.opencli/spotify-tokens.json)
  • Credentials loaded from ~/.opencli/spotify.env or environment variables

Note: Spotify Premium is required for all playback control commands (play, pause, next, prev, volume, queue, shuffle, repeat). The search and status commands work with free accounts.

Note: This adapter does not interact with the Spotify desktop app directly. It sends commands to the Spotify Web API, which forwards them to whichever Spotify client is currently active on your account (desktop app, mobile app, or web player at open.spotify.com). At least one of these must be open and logged in for playback commands to work — otherwise the API returns a 404 "No active device" error.

Commands

Command Description Requires Premium
opencli spotify auth OAuth authentication (run once) No
opencli spotify status Show current playback No
opencli spotify search <query> Search tracks No
opencli spotify play [query] Search and play a track/artist, or resume Yes
opencli spotify pause Pause playback Yes
opencli spotify next Skip to next track Yes
opencli spotify prev Skip to previous track Yes
opencli spotify volume <0-100> Set volume Yes
opencli spotify queue <query> Add track to queue Yes
opencli spotify shuffle on|off Toggle shuffle Yes
opencli spotify repeat off|track|context Set repeat mode Yes

Setup

  1. Create an app on Spotify Developer Dashboard with redirect URI http://127.0.0.1:8888/callback
  2. Create ~/.opencli/spotify.env with your SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET
  3. Run opencli spotify auth once to authenticate
  4. Open Spotify on any device (desktop app, mobile app, or web player) and make sure you are logged in
  5. Use any playback command — it will control whichever device is active

Test plan

  • opencli spotify auth opens browser and saves tokens
  • opencli spotify play "Bohemian Rhapsody" starts playback
  • opencli spotify status returns current track info
  • opencli spotify pause / next / prev work correctly
  • opencli spotify volume 50 sets volume
  • Token refresh works automatically after expiry

bhutano and others added 6 commits March 28, 2026 14:08
Adds a new adapter for controlling Spotify via the official Web API.
Uses Strategy.PUBLIC with OAuth2 — no browser session required.

Commands: auth, status, play, pause, next, prev, volume, search, queue, shuffle, repeat.
Credentials are loaded from ~/.opencli/spotify.env or environment variables.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Renamed src/clis/spotify/index.ts to spotify.ts so the build-manifest
  picks it up (index.js is intentionally excluded from manifest scanning)
- Fixed 4 CliError calls: constructor now requires (code, message, hint?)
  so each throw now passes an appropriate error code as first argument

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…alidation

- refreshAccessToken: check res.ok before parsing; construct Tokens object
  directly instead of mutating loadTokens() result to avoid writing
  undefined/NaN on Spotify error responses; preserve existing refresh_token
  when Spotify omits it from the response
- loadEnv: split on first '=' only so values containing '=' are preserved
- SCOPES: remove write/library/top scopes not used by any command
- status: guard against data.item being null (active device but no track)
- volume: validate 0-100 range before API call
- auth: check tokenRes.ok on initial token exchange; add server.on('error')
  handler for EADDRINUSE; add 5-minute timeout with clearTimeout on close
…tall

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…, corrupted tokens, invalid search limit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants