A Python library and CLI tool for interacting with Spotify and Last.FM APIs. Focuses on playlist management, track discovery, and music library analytics. Data syncs to a local SQLite database for offline querying and analysis.
- Spotify Integration: Manage playlists, discover tracks, analyze library
- Last.FM Integration: Fetch scrobbling history and analyze listening patterns
- Local Database: SQLite backend for offline querying and analytics
- Duplicate Detection: Find duplicate tracks by ID and fuzzy-match similar tracks
- Smart Caching: Three-tier caching (pickle → SQLite → API) for performance
- Python 3.14 or higher
- uv (fast Python package manager)
# Clone the repository
git clone https://github.com/jmlrt/spotfm.git
cd spotfm
# Install dependencies (creates .venv)
make install
# or directly:
uv sync --all-extrasConfiguration is stored in ~/.spotfm/spotfm.toml. Start by copying the example:
cp spotfm.example.toml ~/.spotfm/spotfm.tomlRequired settings:
[spotify]
client_id = "your_spotify_client_id"
client_secret = "your_spotify_client_secret"
excluded_playlists = ["Playlist Name 1", "Playlist Name 2"]
sources_playlists = ["Source Playlist 1", "Source Playlist 2"]
discover_playlist = "Discover Weekly"
[lastfm]
api_key = "your_lastfm_api_key"
api_secret = "your_lastfm_api_secret"
username = "your_username"
password_hash = "your_password_hash"OAuth tokens are automatically cached in ~/.spotfm/spotify-token-cache.
# Update all playlists with latest tracks
spfm spotify update-playlists
# Discover new tracks from source playlists (adds to discover_playlist)
spfm spotify discover-from-playlists
# Add tracks from a file (one per line, format: "artist - track")
spfm spotify add-tracks-from-file tracks.txt
# Count total tracks across playlists
spfm spotify count-tracks
# Find duplicate track IDs (same track in multiple playlists)
spfm spotify find-duplicate-ids
spfm spotify find-duplicate-ids -o output.csv # Save to CSV
# Find similar track names (fuzzy matching)
spfm spotify find-duplicate-names
spfm spotify find-duplicate-names -t 90 # Adjust similarity threshold (0-100)
spfm spotify find-duplicate-names -o output.csv # Save to CSV
# Find relinked tracks (Spotify replaces deleted tracks)
spfm spotify find-relinked-tracks
spfm spotify find-relinked-tracks -o output.csv # Save to CSV# Fetch recent scrobbles (auto-tracks state: first run initializes, subsequent runs fetch new only)
spfm lastfm recent-scrobbles
# Filter by minimum scrobbles in period window
spfm lastfm recent-scrobbles --period-minimum 2
# Open results in editor with automatic deduplication
spfm lastfm recent-scrobbles -i
# Combine config defaults with interactive mode (if configured)
spfm lastfm recent-scrobbles -i -s 3 --period-minimum 2Configuration (optional, in spotfm.toml):
[lastfm]
api_key = "..."
api_secret = "..."
username = "..."
password_hash = "..."
scrobbles_minimum = 2 # Minimum total scrobbles (default: 4)
period_minimum = 1 # Minimum in period window (unset/omitted: no filter; 1: require ≥1 in period)See CONTRIBUTING.md for comprehensive development documentation including:
- Setup and installation
- Testing (running tests, coverage requirements)
- Code quality checks (linting, formatting, type checking)
- Pre-commit hooks
- Writing tests with proper database isolation
- Git workflow and commit message standards
Quick reference:
make install # Install dependencies
make test # Run all tests
make lint # Check code style
make lint-fix # Auto-fix code style
make pre-commit # Run all pre-commit hooksFor other make targets, see make help or Makefile.
Data is stored in SQLite at ~/.spotfm/spotify.db. Key tables:
playlists- Playlist metadatatracks- Track information with lifecycle timestamps (created_at,last_seen_at)albums- Album metadataartists- Artist metadataplaylists_tracks- Many-to-many withadded_attimestamptracks_artists,albums_tracks,albums_artists- Relationship tablesartists_genres- Genre associations
See hacks/create-tables.sql for full schema.
spotfm uses a three-tier caching strategy for performance:
- Pickle cache (
~/.cache/spotfm/) - Fastest (local file cache) - SQLite database (
~/.spotfm/spotify.db) - Persistent (offline querying) - Spotify API - Source of truth (fallback)
Important: Tracks that are removed from all playlists become "orphaned" and accumulate in the database. This is intentional—they prevent the discovery feature from re-adding tracks you intentionally removed.
For comprehensive architecture details, design decisions, and entity lifecycle patterns, see SPEC.md.
We welcome contributions! Please see CONTRIBUTING.md for detailed guidelines on:
- Development workflow and branch naming
- Code style and testing requirements
- Writing commit messages
- Running quality checks
- Common tasks (adding commands, fixing bugs, etc.)
Quick start:
make install # Setup development environment
make test # Run tests
make lint # Check code style
git checkout -b feature/your-feature # Create feature branchMIT
For issues, feature requests, or questions, please open an issue on GitHub.