- Env.py now reads SPOTIFY_CLIENT_ID/SPOTIFY_CLIENT_SECRET (and optional path overrides) from the environment instead of hardcoding them. - Add .env.example and ignore .env / .venv. - Rewrite README with setup, usage and layout (drops the leaked secret). Note: secrets are also purged from prior history in this push. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
100 lines
3.4 KiB
Markdown
100 lines
3.4 KiB
Markdown
# MusicIndexer
|
|
|
|
Pull your Spotify library and listening stats via the Spotify Web API, index a
|
|
local music library (audio tags + iTunes XML), and match the two so you can see
|
|
which tracks you own, what's missing, and your top artists/tracks/playlists — in
|
|
a Streamlit GUI.
|
|
|
|
## Features
|
|
|
|
- **Spotify backend** — OAuth (Authorization Code) login, then fetch the user
|
|
profile, liked tracks, all playlists and their tracks, long-term top tracks
|
|
and top artists, and playlist/profile cover art. Resilient paginated fetching
|
|
(follows `next`, retries dropped connections, honours `429` rate limits) with
|
|
progress bars.
|
|
- **Local backend** — index a folder of audio files via `mutagen` tags.
|
|
- **iTunes backend** — parse an iTunes Library XML export.
|
|
- **Matching** — map local tracks to Spotify tracks (fuzzy matcher; ISRC/MBID
|
|
matching planned).
|
|
- **Stats & lyrics** — generate listening stats and fetch lyrics.
|
|
- **GUI** — browse libraries as artist → album → track tables.
|
|
|
|
## Setup
|
|
|
|
Requires Python 3.13+.
|
|
|
|
```bash
|
|
python -m venv .venv
|
|
source .venv/bin/activate
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
### Credentials
|
|
|
|
Create an app at https://developer.spotify.com/dashboard and add
|
|
`http://127.0.0.1:8888` as a **Redirect URI**. Credentials are read from the
|
|
environment — never commit them.
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
# edit .env with your client id/secret
|
|
source .env
|
|
```
|
|
|
|
`Env.py` reads `SPOTIFY_CLIENT_ID` / `SPOTIFY_CLIENT_SECRET` (plus optional
|
|
`MUSIC_LIBRARY_PATH` and `WORK_DIR`) from the environment.
|
|
|
|
## Usage
|
|
|
|
Edit `main.py` to uncomment the steps you want, then run:
|
|
|
|
```bash
|
|
python main.py
|
|
```
|
|
|
|
The flow steps (see `Flow.py`) include:
|
|
|
|
| Step | What it does |
|
|
|------|--------------|
|
|
| `fetch_spotify()` | OAuth login + download all Spotify data into `work_dir/spotify/` |
|
|
| `fetch_local()` | index local audio files into `work_dir/local/` |
|
|
| `parse_spotify_library()` / `parse_itunes_library()` / `parse_local_library()` | build normalized libraries |
|
|
| `load_libraries()` / `save_libraries()` | (de)serialize libraries to `work_dir` |
|
|
| `map_local_to_spotify()` | match local tracks against the Spotify library |
|
|
| `fetch_and_save_lyrics()` | fetch lyrics for tracks |
|
|
| `log_stats()` | generate stats |
|
|
|
|
On first `fetch_spotify()` a browser opens for the Spotify login; a local server
|
|
on `127.0.0.1:8888` catches the redirect and exchanges the code for a token.
|
|
|
|
### GUI
|
|
|
|
```bash
|
|
./gui.sh # runs: .venv/bin/streamlit run Gui.py
|
|
```
|
|
|
|
## Layout
|
|
|
|
```
|
|
main.py entry point (CLI flow)
|
|
Gui.py / gui.sh Streamlit GUI
|
|
Flow.py orchestrates fetch / parse / map / stats
|
|
Env.py config (reads credentials from the environment)
|
|
src/
|
|
Library.py data model (Library / Artist / Album / Track)
|
|
LibrarySerializer.py load/save libraries
|
|
backends/
|
|
spotify/ Web API client, OAuth, parser
|
|
local/ local-file indexer, parser, playlist generator
|
|
itunes/ iTunes XML parser
|
|
navidrome/ Navidrome backend
|
|
mappers/ local↔Spotify matching (fuzzy / search)
|
|
lyrics/ lyrics fetching
|
|
work_dir/ fetched data and serialized libraries (gitignored)
|
|
```
|
|
|
|
## Notes
|
|
|
|
- Data is cached as JSON under `work_dir/` (gitignored); re-running reuses it.
|
|
- The deprecated Spotify endpoints (audio-features, recommendations, etc.) are
|
|
not used — only currently-supported endpoints.
|