mirror of
https://github.com/Ssenseii/harmoni.git
synced 2026-04-26 07:55:54 +03:00
[PR #4] [MERGED] Add Spotify Web API (OAuth PKCE) support: auth, token caching, resilient client, playlist/liked-songs downloads #6
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/harmoni#6
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/Ssenseii/harmoni/pull/4
Author: @TheRealAlexV
Created: 12/17/2025
Status: ✅ Merged
Merged: 12/18/2025
Merged by: @Ssenseii
Base:
main← Head:TRAV_spotify_api📝 Commits (7)
89936adchore(config): remove unused config file5b862c9feat(config): add spotify web api config options465cc49feat(config): add example configuration filef0c0277feat(spotify): enhance spotify authentication flow419a191feat(spotify): enhance spotify authentication flowb50c634fix(spotify): refresh token handling and error detailsa385960chore(config): remove spotify token from git📊 Changes
16 files changed (+2137 additions, -348 deletions)
View changed files
📝
.gitignore(+3 -1)📝
config.json.example(+11 -1)📝
config.py(+29 -0)📝
docker-compose.yml(+7 -10)📝
downloader/metadata.py(+1 -1)📝
menus/downloads_menu.py(+688 -215)📝
readme.md(+231 -118)📝
requirements.txt(+1 -0)➕
spotify_api/__init__.py(+20 -0)➕
spotify_api/auth.py(+270 -0)➕
spotify_api/client.py(+264 -0)➕
spotify_api/data_loader.py(+279 -0)➕
spotify_api/token_manager.py(+114 -0)📝
start.sh(+16 -2)➕
test_spotify_api_basic.py(+92 -0)➕
test_spotify_data_loader_limits.py(+111 -0)📄 Description
Summary
This PR introduces a complete Spotify Web API integration (Authorization Code + PKCE) so HARMONI can load tracks directly from a user’s Spotify account (Playlists + Liked Songs) and reuse the existing per-playlist selection + download pipeline.
Key deliverables:
spotify_api/package (PKCE auth, token cache, API client with retries/paging, data normalization)Motivation
File-based workflows (Exportify CSV / Spotify export JSON) remain supported, but direct Web API access is the most reliable and user-friendly source of up-to-date playlist + liked-song data.
What’s Included
1) OAuth PKCE implementation (no client secret)
SpotifyPKCEAuthSpotifyPKCEAuth.generate_pkce_pair()andcode_challenge_from_verifier()extract_code_from_redirect_url()SpotifyPKCEAuth.exchange_code_for_token()andSpotifyPKCEAuth.refresh_access_token()Dependency note:
httpx(import guarded with a clear runtime error when missing) inspotify_api/auth.pyhttpxis included inrequirements.txt2) Token caching + expiry
TokenManagerDEFAULT_TOKEN_CACHE_PATH(data/spotify_tokens.json)TokenManager.is_expired()Config controls:
spotify_cache_tokens: enable/disable disk cache (checked inTokenManager.should_cache())spotify_auto_refresh: enable/disable refresh-token flow (enforced inSpotifyClient.get_token())3) Resilient Spotify Web API client (stdlib networking)
SpotifyClientSpotifyClient.request_json()Retry-AfterSpotifyClient.get_user_playlists()SpotifyClient.get_playlist_tracks()SpotifyClient.get_liked_songs()Tunable retry keys (optional):
spotify_max_retries,spotify_backoff_base,spotify_retry_jitter(read inSpotifyClient.request_json()andSpotifyClient._sleep_with_jitter())4) High-level data loader + normalization compatible with existing workflows
SpotifyDataLoaderSpotifyDataLoader.list_all_playlists()SpotifyDataLoader.load_playlist_tracks()SpotifyDataLoader.load_liked_songs()artist+track):SpotifyDataLoader._normalize_track()5) CLI menu integration (auth + download UI)
downloads_menu()_spotify_api_menu()OAuth UX improvements:
_spotify_authenticate()0.0.0.0inside container when redirect is127.0.0.1):_spotify_authenticate()Download workflow integration:
_spotify_download_from_playlists()_spotify_download_liked_songs()select_songs_for_playlist()download_playlist()6) Configuration + docs
DEFAULT_CONFIGandCONFIG_SCHEMAspotify_client_id,spotify_redirect_uri,spotify_scopes,spotify_cache_tokens,spotify_auto_refreshreadme.mdClient ID behavior:
spotify_client_idis not set, falls back to Exportify’s public client id viaget_effective_spotify_client_id()(with warnings + guidance fromcheck_spotify_credentials())Testing
test_spotify_api_basic.pytest_spotify_data_loader_limits.pySecurity / Privacy notes
spotify_cache_tokensis enabled (seeTokenManager.should_cache()).SpotifyClient.request_json()).User-facing workflow
readme.md_spotify_authenticate()select_songs_for_playlist()🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.