soulsync/requirements.txt
BoulderBadgeDad 06f11dc95a Full public playlists via optional SpotipyFree (no creds), MIT-clean
The in-house anonymous-token path is blocked by Spotify (429 without the web
player's rotating client-auth). Switch the full-fetch to SpotipyFree — the
maintained no-creds spotipy drop-in spotDL uses, which tracks that machinery.

- core/spotify_public_api.fetch_public_playlist_full now uses a SpotipyFree
  client (playlist + playlist_items + next), normalising the spotipy-shaped
  items to the embed scraper's shape. Injectable client_factory keeps it
  unit-testable without the library or network. Dropped the dead in-house
  token/pagination code.
- Licensing: SpotipyFree is GPL-3.0, so it is NOT bundled/required (SoulSync is
  MIT). Optional, user-installed: the import is soft, and on ImportError (or any
  failure) fetch_spotify_public falls back to the embed scraper (~100). So the
  shipped project stays cleanly MIT and the link path never regresses.
- requirements.txt: documents it as a commented optional extra
  (pip install SpotipyFree) with the GPL/MIT rationale.
- 9 tests: normalisation, pagination past 100, library-missing -> raises (->
  fallback), and the embed-fallback orchestration.

Needs a live click-through with SpotipyFree installed to confirm the exact
class/method names match (SpotipyFree.Spotify / playlist / playlist_items).
2026-06-02 22:43:34 -07:00

76 lines
2.3 KiB
Text

# SoulSync requirements
# Web application dependencies only
# All dependencies pinned for reproducible builds.
# Core web framework
Flask==3.1.3
Flask-Limiter==4.1.1
# Music service APIs
spotipy==2.26.0
PlexAPI==4.18.1
# HTTP and async support
requests==2.33.1
aiohttp==3.13.5
# Security and encryption
cryptography==48.0.0
# Media metadata handling
mutagen==1.47.0
Pillow==12.2.0
# Text processing
Unidecode==1.4.0
beautifulsoup4==4.14.3
# System monitoring
psutil==7.2.2
# IANA timezone data — required by ``zoneinfo`` on Windows hosts and
# minimal Docker base images that ship without the system tz database.
# Consumed by ``core/automation/schedule.py`` for daily / weekly /
# monthly schedule next-run computation in the user's local timezone.
# Loose-pinned because IANA tz data changes a few times a year for
# real-world DST policy updates; pinning to one snapshot would freeze
# the app's tz knowledge to the build date.
tzdata>=2024.1
# Cross-platform IANA timezone detection — returns the server's local
# tz as a string ('America/Los_Angeles', not 'PDT'). Consumed by the
# automation engine to preserve historic behaviour for daily / weekly
# trigger rows that don't carry an explicit ``tz`` field: the old
# engine computed delays from naive ``datetime.now()``, which is
# implicitly the server's local tz, so falling back to the same tz
# keeps existing schedules running at the same wall-clock time.
tzlocal>=5.0
# YouTube support -- unpinned; yt-dlp must track upstream releases to stay functional
yt-dlp>=2026.3.17
# Lyrics support
lrclibapi==0.3.1
# Audio fingerprinting for download verification
pyacoustid==1.3.1
# WebSocket client for Hydrabase connection
websocket-client==1.9.0
# Tidal download support
tidalapi==0.8.11
# WebSocket server for real-time UI updates
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