SpotipyFree integration confirmed working (236 tracks live); deps + meta tweak

- Verified end-to-end: fetch_public_playlist_full pulled all 236 tracks of the
  test playlist via SpotipyFree (the library handles the client-auth that 429'd
  the raw approach). Name + tracks correct.
- requirements.txt: declare spotipyFree>=1.1.2 as a normal pip dependency (like
  spotDL, also MIT — aggregation, not vendored) + websockets (a transitive dep
  SpotipyFree/spotapi needs that pip doesn't pull automatically). Code still
  soft-imports + falls back to embed, so it's never a hard runtime requirement.
- meta fetch uses limit=1 (name/owner only) so we don't pull the whole list
  twice. 9 tests green.
This commit is contained in:
BoulderBadgeDad 2026-06-02 22:50:04 -07:00
parent 06f11dc95a
commit 77b8d7dd1f
3 changed files with 13 additions and 10 deletions

View file

@ -77,7 +77,9 @@ def fetch_public_playlist_full(
meta: Dict[str, Any] = {}
try:
meta = client.playlist(spotify_id) or {}
# limit=1: we only want name/owner here — tracks come from the paginated
# playlist_items call below, so don't pull the whole list twice.
meta = client.playlist(spotify_id, limit=1) or {}
except Exception as e: # metadata is nice-to-have; tracks are the point
logger.debug("playlist metadata fetch failed (%s); continuing", e)
name = meta.get('name', 'Unknown')

View file

@ -66,11 +66,12 @@ flask-socketio==5.6.1
gunicorn==26.0.0
simple-websocket==1.1.0
# ── Optional: full public-playlist link imports (no Spotify credentials) ──
# The "Spotify link" tab scrapes Spotify's embed widget, which caps at ~100
# tracks. SpotipyFree pulls the full list with no login. It is GPL-3.0, so it is
# intentionally NOT installed by default (SoulSync is MIT — bundling GPL would
# force the project to GPL). To enable full link imports, install it yourself:
# pip install SpotipyFree
# Without it, the link tab simply falls back to the ~100-track embed result.
# spotipyFree>=1.1.2,<2
# Full public-playlist link imports (no Spotify credentials). The "Spotify link"
# tab scrapes Spotify's embed widget, which caps at ~100 tracks; SpotipyFree
# (the no-creds spotipy drop-in spotDL uses) pulls the full list. It is GPL-3.0,
# used here as a normal pip dependency — aggregation, exactly like spotDL (also
# MIT). It is NOT vendored into SoulSync's own code, so the project stays MIT.
# The code soft-imports it and falls back to the embed scraper (~100 tracks) if
# it's missing or fails, so this is never a hard runtime requirement.
spotipyFree>=1.1.2,<2
websockets>=12 # required by SpotipyFree/spotapi, not pulled in automatically

View file

@ -43,7 +43,7 @@ class _FakeClient:
def __init__(self, total, *, fail_items=False):
self.total, self.fail_items = total, fail_items
def playlist(self, pid):
def playlist(self, pid, limit=-1, offset=0, *args, **kwargs):
return {'name': 'My Playlist', 'owner': {'display_name': 'Owner'}}
def _page(self, offset):