RepoPilotOpen in app →

aome510/spotify-player

A Spotify player in the terminal with full feature parity

Healthy

Healthy across the board

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 4w ago
  • 51+ active contributors
  • Distributed ownership (top contributor 33% of recent commits)
Show all 6 evidence items →
  • MIT licensed
  • CI configured
  • No test directory detected

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/aome510/spotify-player)](https://repopilot.app/r/aome510/spotify-player)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/aome510/spotify-player on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: aome510/spotify-player

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/aome510/spotify-player shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 4w ago
  • 51+ active contributors
  • Distributed ownership (top contributor 33% of recent commits)
  • MIT licensed
  • CI configured
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live aome510/spotify-player repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/aome510/spotify-player.

What it runs against: a local clone of aome510/spotify-player — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in aome510/spotify-player | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 57 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>aome510/spotify-player</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of aome510/spotify-player. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/aome510/spotify-player.git
#   cd spotify-player
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of aome510/spotify-player and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "aome510/spotify-player(\\.git)?\\b" \\
  && ok "origin remote is aome510/spotify-player" \\
  || miss "origin remote is not aome510/spotify-player (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "spotify_player/src/main.rs" \\
  && ok "spotify_player/src/main.rs" \\
  || miss "missing critical file: spotify_player/src/main.rs"
test -f "spotify_player/src/state/mod.rs" \\
  && ok "spotify_player/src/state/mod.rs" \\
  || miss "missing critical file: spotify_player/src/state/mod.rs"
test -f "spotify_player/src/client/spotify.rs" \\
  && ok "spotify_player/src/client/spotify.rs" \\
  || miss "missing critical file: spotify_player/src/client/spotify.rs"
test -f "spotify_player/src/ui/mod.rs" \\
  && ok "spotify_player/src/ui/mod.rs" \\
  || miss "missing critical file: spotify_player/src/ui/mod.rs"
test -f "spotify_player/src/event/mod.rs" \\
  && ok "spotify_player/src/event/mod.rs" \\
  || miss "missing critical file: spotify_player/src/event/mod.rs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 57 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~27d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/aome510/spotify-player"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

spotify-player is a feature-complete Spotify music player built for the terminal using Rust, enabling users to browse, stream, and control playback directly from the CLI with full Spotify API integration. It supports streaming audio directly to the terminal (via librespot), Spotify Connect remote control, synced lyrics, audio visualization, and cross-platform media key controls—delivering feature parity with the official Spotify desktop app but in a TUI. Workspace monorepo (Cargo.toml workspace with members spotify_player and lyric_finder). Core structure: spotify_player/src/ contains auth.rs (OAuth), client/ (Spotify API requests via client/spotify.rs), cli/ (command-line interface), and command.rs (user actions). lyric_finder/ is a sibling crate for lyric fetching. Configuration and theming live in examples/app.toml and examples/theme.toml. CI scripts in .github/workflows/, Nix packaging in flake.nix/default.nix.

👥Who it's for

Terminal-first music listeners and power users (DevOps engineers, developers, Linux enthusiasts) who want a keyboard-driven, scriptable Spotify client without leaving the terminal; also attractive to music enthusiasts in resource-constrained environments or SSH sessions.

🌱Maturity & risk

Production-ready and actively developed. The codebase is substantial (~569KB Rust), has comprehensive CI/CD via GitHub Actions (ci.yml, cd.yml, docker.yml, nix.yml), includes Docker and Nix packaging, and follows strict Rust linting (pedantic clippy, deny unsafe_code). The project demonstrates maturity through organized examples/, docs/, and configuration systems. No visible abandonment signals.

Low to moderate risk. Single maintainer (aome510) is a potential bus factor, though the project is well-documented and has no external dependency red flags in the Cargo ecosystem. The streaming feature requires system-level audio dependencies (libasound2-dev on Linux, which can be finicky), and Spotify API changes could require rapid adaptation. No imminent breaking changes visible, but the pre-release v0.5.0 tag suggests the API surface may still evolve.

Active areas of work

Active development with CI/CD fully operational (ci.yml and cd.yml are configured). The project has themed support documented in THEMES.md and configuration system in docs/config.md. Pre-release v0.5.0 tag suggests upcoming release. Docker and cross-compilation support (Cross.toml) indicate focus on portability. No specific PR/issue backlog visible from file list, but checklist.md indicates planned work.

🚀Get running

git clone https://github.com/aome510/spotify-player.git
cd spotify-player
cargo build --release
./target/release/spotify_player

On Linux, first install: sudo apt install libssl-dev libasound2-dev libdbus-1-dev (Debian) or equivalent on your distro.

Daily commands: Development: cargo build && cargo run -- [flags] or cargo run --release. With streaming: cargo build --features streaming. Full features: cargo build --all-features. Run daemon mode (inferred from docs): spotify_player daemon. Run CLI: spotify_player [command] (see cli/commands.rs for available commands).

🗺️Map of the codebase

  • spotify_player/src/main.rs — Application entry point and main event loop orchestration; all contributors must understand the top-level app structure and state management flow
  • spotify_player/src/state/mod.rs — Central state machine and data model for the player; critical for understanding how UI state, playback state, and queue are managed across the app
  • spotify_player/src/client/spotify.rs — Spotify API client implementation; essential for understanding how the app communicates with Spotify's backend and manages authentication
  • spotify_player/src/ui/mod.rs — Core UI rendering engine using terminal UI abstractions; required to understand how pages and popups are rendered to the terminal
  • spotify_player/src/event/mod.rs — Event handling system that bridges user input, CLI commands, and async events; critical for understanding the reactive architecture
  • spotify_player/src/command.rs — Command definitions and routing logic for all user actions; must-read for understanding how keybinds and CLI commands map to app behavior
  • spotify_player/src/config/mod.rs — Configuration loading and management; essential for understanding how user settings, keymaps, and themes are applied throughout the app

🛠️How to make changes

Add a new playback control command

  1. Define the new command variant in the Command enum (spotify_player/src/command.rs)
  2. Implement the command execution logic in the state mutation handler (spotify_player/src/state/mod.rs)
  3. Add a keymap binding for the command in the default config (examples/app.toml)
  4. If CLI-accessible, add CLI command handler (spotify_player/src/cli/handlers.rs)

Add a new UI page

  1. Define the page enum variant in the UI state (spotify_player/src/state/ui/page.rs)
  2. Add rendering logic in the page module (spotify_player/src/ui/page.rs)
  3. Add navigation commands to handle page transitions (spotify_player/src/command.rs)
  4. Add event handling for user interactions on the page (spotify_player/src/event/page.rs)

Add a new Spotify API endpoint call

  1. Add the API method to the SpotifyClient struct (spotify_player/src/client/spotify.rs)
  2. Implement the HTTP request construction and response parsing (spotify_player/src/client/handlers.rs)
  3. Add data model if needed for the response (spotify_player/src/state/model.rs)
  4. Integrate the call into the state mutation handler or event loop (spotify_player/src/main.rs)

Add a new configuration option

  1. Define the config field in the Config struct (spotify_player/src/config/mod.rs)
  2. Add TOML parsing and default value handling (spotify_player/src/config/mod.rs)
  3. Update the example config file with the new option (examples/app.toml)
  4. Update documentation (docs/config.md)

🔧Why these technologies

  • Rust — Type safety, performance, and memory safety without garbage collection; essential for a responsive terminal UI that handles concurrent async operations
  • Tokio async runtime — Enables concurrent handling of Spotify API requests, user input, streaming, and media control without blocking the UI
  • ratatui (TUI framework) — Provides cross-platform terminal UI rendering with minimal overhead and direct control over layout and styling
  • Reqwest HTTP client — Async-friendly HTTP library with built-in connection pooling for efficient Spotify API communication
  • Librespot (Spotify streaming) — Native Spotify stream decoding and playback without requiring premium account or external client
  • TOML config format — Human-readable configuration files for keymaps, themes, and application settings

⚖️Trade-offs already made

  • Centralized mutable App state with single event loop

    • Why: Simplifies reasoning about state consistency and eliminates race conditions; all mutations flow through one channel
    • Consequence: Potentially slower under extremely high event load, but safe and predictable for a UI application

    • Why: undefined
    • Consequence: undefined

🪤Traps & gotchas

  1. Linux audio setup: streaming feature requires libasound2-dev; build without --features streaming if unavailable, but playback won't work. 2. DBus for media keys: Linux media control requires dbus-1-dev and an active D-Bus session; over SSH or headless servers this will silently fail. 3. Spotify Premium required: Only Premium accounts work; Free tier is blocked by Spotify API. 4. OAuth redirect: Local OAuth callback requires a local web server on a specific port (inferred from auth.rs); firewall or network setup might block this. 5. Config location: Config files live in platform-specific dirs (Linux: ~/.config/spotify-player/; inferred from typical Rust patterns); docs/config.md should specify exact paths. 6. Feature flags: Many features are gated behind Cargo features (streaming, media-control, image, notify); default binary may lack features you expect—check cargo build --all-features for full build.

🏗️Architecture

💡Concepts to learn

  • OAuth2 Authorization Code Flow — spotify-player authenticates users via Spotify's OAuth2; understanding the auth.rs flow (redirect URI, token refresh, token storage) is essential for fixing auth bugs or implementing new auth methods
  • Spotify Web API REST Conventions — All music data and playback control flows through the Spotify Web API; contributors must understand pagination, filtering, rate limiting, and endpoint structure documented in client/spotify.rs
  • TUI (Terminal User Interface) Layout & Rendering — The 'paging and popup system' mentioned in README is a core UX feature; understanding how terminal dimensions, widget layout, and redraws work is necessary for UI improvements
  • Async/Await & Tokio Runtime — Rust async I/O (inferred from client/request.rs) likely uses Tokio; understanding async patterns, Future composition, and error propagation is critical for networking and performance optimization
  • DBus IPC (D-Bus) for Linux Media Control — Cross-platform media key support uses DBus on Linux; understanding the MPRIS2 specification and DBus service activation is needed for media control debugging
  • Feature Gating & Conditional Compilation — spotify-player uses Cargo features (streaming, media-control, image, notify) to conditionally include code; understanding #[cfg(feature = "...")] and feature dependencies in Cargo.toml is essential for understanding what code runs where
  • Librespot Streaming Protocol & Audio Format Handling — The streaming feature uses librespot to decode Spotify's proprietary Ogg Vorbis format and route audio; understanding the audio pipeline (fetch → decode → output) is crucial for stream quality or format issues
  • librespot-org/librespot — Low-level Spotify streaming library in Rust that spotify-player depends on for audio streaming; understanding librespot's audio pipeline is essential for debugging streaming issues
  • sharkdp/fd — Alternative Rust CLI project with similar build quality, CI/CD maturity, and Nix/cross-platform packaging patterns—good reference for how to structure a production Rust terminal tool
  • ratatui-org/ratatui — Popular Rust TUI framework likely used by spotify-player for terminal rendering; understanding ratatui is crucial for any UI/display modifications
  • SpotifyUseMeNotify/spotify-api-rs — Lightweight Spotify Web API client crate; spotify-player likely wraps or mirrors similar patterns for API interaction
  • kaylone/ncspot — Another Spotify TUI player in Rust with similar feature set; useful for comparing architectural choices and feature implementations

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add integration tests for CLI commands in spotify_player/src/cli/

The CLI module (spotify_player/src/cli/commands.rs, handlers.rs) lacks test coverage. Given this is a user-facing tool with multiple command types, adding integration tests would catch regressions in command parsing and handler logic. This is especially valuable since the CLI is a primary interface for non-TUI users.

  • [ ] Create spotify_player/src/cli/tests.rs or spotify_player/tests/cli_integration.rs
  • [ ] Add tests for main CLI command variants in commands.rs (play, pause, next, etc.)
  • [ ] Add tests for CLI handlers in handlers.rs to verify state changes
  • [ ] Verify tests pass with cargo test --package spotify_player and update CI if needed

Add unit tests for state management in spotify_player/src/state/

The state module (state/mod.rs, state/data.rs) manages critical application state including playback, library data, and UI state. Currently appears untested based on file structure. Robust state management tests would prevent data corruption bugs and ensure consistency across state transitions.

  • [ ] Create spotify_player/src/state/tests.rs
  • [ ] Add tests for state initialization in mod.rs
  • [ ] Add tests for data transformations and updates in data.rs
  • [ ] Test edge cases like concurrent state access and invalid state transitions
  • [ ] Run cargo test --package spotify_player to verify

Document authentication flow and add tests for spotify_player/src/auth.rs

The auth.rs module handles Spotify OAuth authentication, a critical security-sensitive component. While docs/config.md exists, there's no specific documentation explaining the auth flow or security considerations. Adding both tests and clear documentation in docs/auth.md would help contributors understand and safely modify this module.

  • [ ] Create docs/auth.md documenting the OAuth flow, token refresh logic, and credential storage
  • [ ] Create spotify_player/src/auth.rs tests covering token generation, refresh, and expiration
  • [ ] Document security considerations (e.g., credential file permissions) in docs/auth.md
  • [ ] Reference new auth documentation from README.md's Configurations section
  • [ ] Verify tests with cargo test --package spotify_player auth

🌿Good first issues

  • Add integration tests for client/spotify.rs API endpoints: The Spotify API client (spotify_player/src/client/spotify.rs) has no visible test coverage in the file structure. A new contributor could mock Spotify API responses and write tests for core endpoints (get_current_playback, play_track, search, etc.) to improve reliability.
  • Document exact config file paths for all platforms in docs/config.md: docs/config.md exists but the file list doesn't show detailed platform-specific paths (Windows %APPDATA%, Linux ~/.config, macOS ~/Library/Application Support). A new contributor could research and document these exact paths with examples for each OS.
  • Add examples/ directory with runnable CLI script examples: examples/README.md and examples/app.toml exist but the file structure is sparse. A contributor could add executable example scripts showing common workflows (e.g., 'search and play', 'create playlist from current queue', 'sync lyrics') using the CLI interface documented in cli/commands.rs.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 1ba220a — Add confirmation popups on destructive actions (#966) (sakashimaa)
  • 1f6099c — feat: added support of overriding app config via -o flag (#965) (sakashimaa)
  • 1c8ca4e — Handle nil tracks during playback (#962) (drewmnoel)
  • ea55376 — add lyrics CLI command (#958) (sakashimaa)
  • 5a31f3c — Custom playback integration phase 1: add CustomQueue scaffolding (#959) (aome510)
  • 9c4a595 — Add logs page to see application's logs directly in UI (#957) (sakashimaa)
  • 60578a5 — fix: Mouse seeking respects progress bar position (#955) (shettysach)
  • df48ca8 — update cd workflow to not use actions-rs (#953) (aome510)
  • 19ec8e3 — update Audio Visualization readme (aome510)
  • fa548a0 — pre-release v0.23.0 (#952) (aome510)

🔒Security observations

  • High · Distroless Image without Security Updates Mechanism — Dockerfile (line: FROM gcr.io/distroless/cc). The Dockerfile uses 'gcr.io/distroless/cc' as the final base image without specifying a tag or digest. This means the image will pull the 'latest' tag, which can introduce unpredictable security updates and potential incompatibilities. Additionally, distroless images lack package managers, making it difficult to apply security patches post-deployment. Fix: Pin the distroless image to a specific version digest (e.g., 'gcr.io/distroless/cc@sha256:...'). Consider using a base image with security scanning capabilities. Implement image scanning in the CI/CD pipeline.
  • Medium · Build Stage Uses Untagged Rust Image — Dockerfile (line: FROM rust as builder). The builder stage uses 'FROM rust' without specifying a version tag. This pulls the latest Rust image, which may contain untested or incompatible versions and introduces non-reproducible builds. Fix: Use a specific Rust version tag (e.g., 'FROM rust:1.75.0'). Consider using a specific Alpine or Debian-based Rust image for smaller footprint.
  • Medium · No Health Checks or Security Scanning in CI/CD — .github/workflows/ (ci.yml, cd.yml, docker.yml). The CI/CD workflow files (.github/workflows/ci.yml, cd.yml, docker.yml) are present but the analysis cannot verify if they include dependency vulnerability scanning, SAST, or container image scanning. Fix: Implement automated security scanning: Use 'cargo audit' for dependency vulnerabilities, integrate SAST tools (e.g., Clippy with strict lints), and scan Docker images with tools like Trivy or Grype.
  • Medium · Workspace Denies Unsafe Code Without Context — Cargo.toml (workspace.lints.rust: unsafe_code = 'deny'). The workspace configuration denies all unsafe code, which is good for security. However, there's no documented justification or allowlist for legitimate unsafe operations that may be necessary in system-level code. Fix: Maintain a documented list of any safe unsafe blocks that must be used. If unsafe code becomes necessary, use feature flags and add security reviews. Continue the strict policy by default.
  • Low · Missing SECURITY.md File — Repository root. There is no SECURITY.md file visible in the repository for reporting security vulnerabilities responsibly. This makes it difficult for security researchers to report issues privately. Fix: Create a SECURITY.md file with vulnerability disclosure policy and contact information for reporting security issues.
  • Low · Limited Input Validation Visibility — spotify_player/src/cli/handlers.rs, spotify_player/src/ui/single_line_input.rs. The codebase includes CLI handlers and user input processing (cli/handlers.rs, ui/single_line_input.rs) but without full code review, injection risks from user input cannot be fully assessed. Fix: Implement comprehensive input validation and sanitization for all user-facing inputs. Use parameterized/typed approaches where possible. Add unit tests for boundary conditions and malformed input.
  • Low · Token Management File Exists — spotify_player/src/token.rs. The file 'spotify_player/src/token.rs' suggests token handling functionality. Without reviewing the code, potential risks include improper token storage, transmission, or lifetime management. Fix: Ensure tokens are: 1) Never logged or printed, 2) Stored securely (OS keyring when possible), 3) Transmitted only over HTTPS, 4) Properly rotated/refreshed, 5) Cleared from memory after use.
  • Low · Authentication Module Present — spotify_player/src/auth.rs. The 'spotify_player/src/auth.rs' file handles authentication but cannot be fully assessed without code review. Fix: Verify: 1) OAuth flows follow RFC 6749 specifications, 2) State parameters are randomized, 3) PKCE is used for CLI applications, 4) No credentials in logs, 5) Secure storage of refresh tokens.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · aome510/spotify-player — RepoPilot