Changelog¶
The full release history, in Keep a Changelog format.
Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased¶
[3.9.2] - 2026-06-26¶
Added¶
--no-hintCLI flag to suppress the one-time star hint for a single invocation (mirrorsSPOTIFYSCRAPER_NO_HINT=1). Thanks @knightxiaoxi (#147).
[3.9.1] - 2026-06-20¶
Fixed¶
- Correct the MCP registry namespace casing to
io.github.AliAkhtari78/…(inserver.json, the READMEmcp-namemarker, and the Dockerfile label) so the official-registry publish succeeds — the GitHub OIDC namespace is case-sensitive to the canonical username.
[3.9.0] - 2026-06-20¶
Added¶
- Official MCP Registry support. The
spotifyscraper-mcpserver is now published to the Model Context Protocol registry (registry.modelcontextprotocol.io) on each release tag, so AI clients and directories (Glama, mcp.so, PulseMCP, Smithery) can discover it. Adds a rootserver.json, anmcp-namemarker, a Dockerfile ownership label, and a failure-isolatedpublish-mcpworkflow authenticated via GitHub OIDC — no stored secret. - One-time CLI star hint. After a successful interactive command the CLI
prints a single, suppressible reminder to stderr pointing at the repo. It
never appears in piped/JSON/
--outputresults, shows only on a TTY, and only once; silence it permanently withSPOTIFYSCRAPER_NO_HINT=1.
Changed¶
- README gains an honest "SpotifyScraper vs. spotipy" comparison table, a
monthly-downloads badge, a star-history chart, and a note for developers
migrating off Spotify's deprecated official
audio-features/recommendations/related-artistsendpoints. The docs landing page gains a star call-to-action. No library API changed.
[3.8.0] - 2026-06-20¶
Changed¶
- CI / supply chain. Bumped every GitHub Actions dependency to its current
major, all SHA-pinned:
actions/checkoutv7,astral-sh/setup-uvv8,github/codeql-actionv4, thedocker/*build actions (setup-qemu, setup-buildx, login, metadata, build-push), andanthropics/claude-code-action. (#141) - Dev toolchain. Refreshed the locked dev environment and pre-commit hooks —
ruff0.9 → 0.15 (hook),pytest9.1,mcp1.28, and lockfile point releases. - Docs & packaging. Added author/site backlinks: a website link in the docs footer (shown on every page) and "Live Demo" / "Author" entries in the PyPI sidebar.
Internal¶
- Corrected the
httpx<1.0cap rationale: 1.0 is not yet released (only1.0.dev*), and the public-API change the comment cited actually shipped in 0.28 (already absorbed). The cap and runtime behavior are unchanged.
This is a maintenance release — no library getter, model, CLI, or MCP signature changed.
[3.7.0] - 2026-06-16¶
Added¶
- MCP batch tools. The
spotifyscraper-mcpserver now exposes the plural getters as tools —get_tracks/get_albums/get_artists/get_playlists/get_episodes/get_shows— fetching many IDs in one call. Each returns an ordered{value, ok, result, error}item per input (mirroringBatchItem), so a single bad or missing ID never sinks the batch.get_playlists/get_showsacceptmax_tracks/max_episodes. - MCP
get_track_visualstool. Returns a track with its covercolorsandcanvasin one round-trip — a convenience for visual, voice-driven front-ends.trackandcolorsare always present (anonymous);canvasis best-effort andnullwithout aSPOTIFY_SP_DCcookie or when the track has none.
No library getter, model, or CLI signature changed; this release only widens the MCP tool surface over capabilities the library already shipped.
[3.6.1] - 2026-06-16¶
Fixed¶
- Documentation examples. Standardized the canonical example IDs on Rick
Astley's "Whenever You Need Somebody" album (
6N9PS4QXF1D0OWPk0Sxtb4) — the previous album example was region-restricted (so it appeared "missing" in some markets) and an example podcast episode had been removed (HTTP 403). No library code changed. Also documented the multi-architecture (amd64 + arm64) container image.
[3.6.0] - 2026-06-16¶
Added¶
- Cover-art colors.
client.get_colors(source)returns a typedColors(raw/dark/light#RRGGBBhex +is_fallback) for UI theming. Anonymous and tier-1-only.sourcemay be a Spotify image URL, aspotify:image:uri, or any fetched entity that hasimages(the first image is used). CLI:colors. - Canvas.
client.get_canvas(track)returns aCanvas(a short, silent, non-DRM looping cover-video MP4 oncanvaz.scdn.co) orNonewhen the track has none.client.download_canvas(track_or_canvas, dest)saves the MP4. Canvas is cookie-authenticated (build withcookies=), exactly like lyrics. CLI:canvas. - Charts.
client.list_charts()enumerates the built-in editorial charts andclient.get_chart(key)(e.g."top-50-global","todays-top-hits") fetches one as aPlaylist. Charts are ordinary editorial playlists, so no new persisted query is involved. CLI:charts. - Related artists.
client.get_related_artists(artist)returns Spotify's "fans also like" artists (with images). Anonymous. CLI:related. - Full discography.
client.get_discography(artist, max_releases=None)paginates every release (albums, singles, compilations) asAlbumRefobjects. Anonymous. CLI:discography. - Recommendations.
client.get_similar_albums(track, limit=...)returns albums recommended from a track. Anonymous. CLI:similar. - Public user profiles.
client.get_user(user_id)returns aUserProfile(name, follower/following counts, public playlists, recently-played artists). Cookie-authenticated (the anonymous token is refused). CLI:user. - Track credits.
client.get_credits(track)returns aCredits(performers, writers, producers — each with their sub-roles). Cookie-authenticated. CLI:credits. - Artist concerts.
client.get_artist_events(artist)returns upcoming live events (Concert: title, start date, city, line-up). Anonymous; the set can vary by region. CLI:events. - MCP server. A Model Context Protocol server (
spotifyscraper-mcp, behind the newmcpextra) exposes every getter as a tool with structured JSON output, the six entity types asspotify://…resources, curated prompts, a cover-art image tool, and stdio + streamable-HTTP transports. Authenticated tools require theSPOTIFY_SP_DCenvironment variable. Install withpip install 'spotifyscraper[mcp]'. - Container image. Published to
ghcr.io/aliakhtari78/spotifyscraper; by default it serves the MCP server over streamable-HTTP (docker run -p 8000:8000 ghcr.io/aliakhtari78/spotifyscraper), or runs the CLI on demand. Built and pushed from CI with the repo'sGITHUB_TOKEN.
[3.5.0] - 2026-06-15¶
Added¶
- Optional response cache. Opt in with
SpotifyClient(cache=CacheConfig(store=FileCache()))for a persistent, off-by-default HTTP cache at the transport seam (composes with rate limiting, retries, andlocale). Only token-free pathfinderGETs that return200are cached; the token-bearing embed pages, the token endpoints, and the cookie-authenticated lyrics/transcript host are never cached, so no credential is written to disk. Default TTL is 24h; the stdlibFileCacheneeds no new dependency and theDiskCachebackend is pluggable. - Batch helpers. Plural
get_tracks,get_albums,get_artists,get_playlists,get_episodes, andget_showsfetch many inputs and return one ordered, index-alignedBatchItemper input. A dead or malformed input never aborts the batch — its captured error lands on that item'serror(item.ok/item.result/item.unwrap()). The async client runs them concurrently, bounded by the client'smax_concurrency(default 5) with the per-host rate limiter still governing pacing; the sync helpers run sequentially.
[3.4.0] - 2026-06-15¶
Added¶
- Search.
client.search(query, types=..., limit=...)runs one anonymous, aggregate query across tracks, albums, artists, playlists, shows, and episodes, returning a typedSearchResults(one tuple per type; lightweightAlbumRef/ShowReffor albums/shows).totalis Spotify's track-match count (Nonewhen tracks aren't requested). A no-match query returns empty results, not an error; an unrecognized type raisesURLErrorbefore any request. - Display-language localization. An optional
locale(a BCP-47 language tag such as"de"or"ja-JP") on the constructor and on every entity getter andsearch()sets theAccept-Languageheader so Spotify returns localized display names (per-call overrides the per-client default; invalid tags raiseURLErrorbefore any request).localeis a language preference, not a country/market code — a bare"US"is ignored — and does not filter regional availability; anonymous market filtering is intentionally not offered (the pathfindermarketvariable is inert and country is IP-bound).
[3.3.0] - 2026-06-15¶
Added¶
- Podcast transcripts.
client.get_transcript(value)returns aTranscript(a tuple of millisecond-offsetTranscriptLines) for a podcast episode, and aspotifyscraper transcriptCLI command emits it as JSON. Transcripts reuse the samesp_dccookie and token handshake as lyrics — one exchange serves both. An episode without a transcript (a 404, or a 200 with no spoken text) raisesNotFoundError; an unexpected payload shape raisesParsingError. - Browser-assisted login & session persistence.
client.login()opens a real (headed) browser, captures thesp_dccookie after you sign in by hand (no password is ever collected or stored), and persists it — with the cookie's real expiry — to an owner-only (0600) file or, withstore="keyring"and the newkeyringextra, the OS keyring.SpotifyClient.from_saved_session()reconnects headlessly;logout()revokes the local copy. Aspotifyscraper login/logoutCLI mirrors it. The cookie never appears in arepr, log, or error message. - Account-awareness & self-aware sessions.
client.get_account()returns the logged-in account's product state (product,country, locale) andclient.is_premium()is the convenience check.login(reuse=True)(the default) reuses a valid saved session and skips the browser;session_info()(and thespotifyscraper sessioncommand) report a saved session's status —exists,valid, expiry/days-remaining — without exposing the cookie.
[3.2.0] - 2026-06-13¶
Added¶
- Lyrics.
client.get_lyrics(track)returns time-synced (or unsynced) lyrics, and aspotifyscraper lyricsCLI command emits them as JSON. Lyrics require a usersp_dccookie (SpotifyClient(cookies=...)or--cookies/ theSPOTIFY_SP_DCenv var); the library performs Spotify's rotating-TOTP/api/tokenhandshake internally. Cookies and tokens stay local and are never logged. TheLyrics/LyricsLinemodels are now populated.
[3.1.0] - 2026-06-13¶
Added¶
- Command-line interface. Install with
pip install "spotifyscraper[cli]"for aspotifyscrapercommand with one subcommand per entity (track,album,artist,playlist,episode,show) plusdownload coveranddownload preview. Commands emit JSON (--pretty,-o FILE), accept client-tuning options (--proxy,--timeout,--rate-limit,--max-tracks/--max-episodes), and map library errors to clean messages and exit codes.
[3.0.0] - 2026-06-13¶
A complete clean-room rewrite. v3 replaces fragile HTML scraping with a token-based JSON strategy, returns typed immutable models instead of dicts, and raises typed exceptions instead of mixing errors into results.
Added¶
SpotifyClientandAsyncSpotifyClient— sync and async facades over one sans-io core, both context managers.get_track,get_album,get_artist,get_playlist,get_episode, andget_show, each accepting a URL, URI, or bare ID and returning a typed model.- Automatic pagination: full album track lists, bounded playlist tracks
(
max_tracks), and full show episode listings (max_episodes). - Typed, frozen dataclass models (
Track,Album,Artist,Playlist,Episode,Show, …) with JSON-safeto_dict()/from_dict(). - A two-tier extraction ladder: Spotify's pathfinder GraphQL API (rich data) with automatic degradation to the public embed page (core fields).
- Media downloads:
download_coveranddownload_preview, with optional ID3 cover embedding viamutagen(themediaextra). - Anti-ban resilience: per-host rate limiting (
RateLimit,host_rate_limits), retries with exponential backoff (RetryPolicy), transient-403 retry, user-agent rotation, and proxy support. - A Playwright browser transport as an optional drop-in fallback (the
browserextra), injectable viatransport=. - A typed exception hierarchy rooted at
SpotifyScraperError. - A MkDocs Material documentation site with a full v2→v3 migration guide, and a daily CI canary that detects Spotify-side breakage.
Changed¶
- BREAKING: every
get_*_info(url)method is replaced byget_*(value)returning a typed model (call.to_dict()for the old dict shape). - BREAKING: failures now raise exceptions instead of returning error strings or dicts.
- BREAKING: the minimum supported Python version is now 3.10.
- The core depends only on
httpx; everything else is an optional extra.
Removed¶
- BREAKING:
get_all_info— call the specificget_*method instead. - The Selenium browser backend (replaced by the Playwright transport extra).
Not yet included (returning in v3.1)¶
- Lyrics extraction and the command-line interface are not part of v3.0; both
ship in v3.1 (lyrics require an authenticated cookie + a token handshake). The
Lyrics/LyricsLinemodel types are present but not yet populated.
Migration¶
See the migration guide for a method-by-method map from v2.
[2.1.5] - 2025-06-12¶
Fixed¶
- Fixed critical NoneType error in JSON parser when handling tracks with null values (Issue #71)
- Added comprehensive null checks throughout track data extraction to prevent "argument of type 'NoneType' is not iterable" errors
- Improved error messages to clearly indicate when track data is missing or malformed
Changed¶
- Enhanced JSON parser robustness with defensive programming for all dictionary access operations
- Added specific type checking to ensure track_data is a dictionary before processing
Added¶
- Comprehensive test suite for NoneType handling in JSON parser
- Better error reporting for debugging track extraction issues
Technical Details¶
- Fixed issue where tracks with null artist, album, or other metadata fields would crash the parser
- All
inoperator checks now verify the container is not None before checking membership - Maintains full backward compatibility while improving reliability
[2.1.4] - 2025-06-09¶
Added¶
- Firefox browser support for Selenium backend with
browser_nameparameter - Automatic webdriver management via
webdriver-managerpackage (optional dependency) - Enhanced metadata extraction:
track_number,disc_number, andpopularityfields in JSON parser - Comprehensive webdriver-manager documentation and examples
use_webdriver_managerparameter to SpotifyClient for automatic driver downloads
Changed¶
- SeleniumBrowser now supports both Chrome (default) and Firefox browsers
- Improved browser initialization with better error messages
- Enhanced JSON parser to extract additional track metadata when available
Fixed¶
- Track number extraction now properly works for tracks in album context
- Improved error handling for missing webdriver-manager dependency
Technical Details¶
- Added
webdriver-manager>=4.0.0to optional selenium dependencies - JSON parser enhanced to handle camelCase and snake_case field variants
- All code changes maintain backward compatibility
[2.1.3] - 2025-06-07¶
Fixed¶
- URLError now properly raises exceptions for invalid URLs instead of returning error dictionaries
- Fixed import errors (DataExtractionError → ExtractionError)
- Fixed syntax errors in documentation examples
- Fixed broken code examples in quickstart.md and advanced.md
Changed¶
- Comprehensive documentation update to reflect actual available fields
- Updated all examples to remove references to unavailable fields (popularity, followers, genres)
- Clarified that lyrics require OAuth authentication, not just cookies
- Unified examples across README, Wiki, and MkDocs documentation
Added¶
- AVAILABLE_FIELDS.md - Complete reference of fields available via web scraping
- UNIFIED_EXAMPLES.md - Consistent examples across all documentation
- Comprehensive test suite for all documentation examples
- Clear distinction between web scraping capabilities and API-only features
Documentation¶
- Updated README with "Important Notes" section about field availability
- Fixed all code examples to use only available fields
- Added migration notes for users expecting API-like functionality
- Improved error handling documentation
[2.1.2] - 2025-06-06¶
Fixed¶
- Fixed lyrics extraction to properly handle OAuth authentication requirement
- Updated all documentation to clarify that lyrics require OAuth Bearer tokens, not cookie authentication
- Added proper warning messages when attempting to access lyrics without OAuth tokens
Added¶
- Added new
LyricsExtractorclass with proper OAuth token checking - Added comprehensive documentation about lyrics API limitations
Changed¶
- Updated
get_track_lyrics()andget_track_info_with_lyrics()to correctly return None with appropriate warnings - Modified all documentation examples to reflect that lyrics are not accessible via cookie authentication
- Updated FAQ, troubleshooting guide, and API documentation with OAuth requirements
Documentation¶
- Unified all documentation sources (README.md, GitHub Pages, ReadTheDocs) with consistent messaging about lyrics limitations
- Removed misleading examples suggesting cookie authentication works for lyrics
- Added clear explanations about Spotify's OAuth requirement for lyrics API
[2.0.22] - 2025-01-06¶
Fixed¶
- Fixed all documentation examples to use safe field access patterns with
.get()method - Fixed KeyError issues when fields are missing from API responses
- Fixed nested field access patterns (e.g.,
track['artists'][0]['name']) to handle missing data - Fixed error handling imports in documentation (
from spotify_scraper importinstead offrom spotify_scraper.exceptions import) - Updated over 40 documentation files to prevent KeyError exceptions
Added¶
- Added
docs/examples/corrected_examples.mdwith working code samples showing exactly which fields are available - Added safe patterns for accessing optional fields throughout documentation
Changed¶
- All field access now uses
.get()method with appropriate defaults: track['name']→track.get('name', 'Unknown')album['release_date']→album.get('release_date', 'N/A')artist['genres']→artist.get('genres', [])playlist['description']→playlist.get('description', '')- Complex nested access patterns now check for existence before accessing
Documentation¶
- Updated all code examples in README, Wiki, and documentation to use safe field access
- Fixed the specific example that was causing
KeyError: 'release_date'as reported by user - Ensured consistency across all documentation files
[2.0.21] - 2025-05-28¶
Fixed¶
- Fixed all documentation examples to use only available fields based on comprehensive testing
- Fixed album examples incorrectly using
album['release_date']which is not always available - Fixed album examples incorrectly using
album['label']which is not available via web scraping - Fixed artist examples incorrectly using
artist['genres'],artist['followers'], andartist['popularity'] - Fixed playlist examples incorrectly using
playlist['owner']['display_name'](should beplaylist['owner']['name']) - Fixed playlist examples using
playlist['total_tracks']instead of correctplaylist['track_count'] - Updated all documentation to handle missing fields gracefully with
.get()method
Changed¶
- Album tracks are now accessed as
album['tracks'](list) instead ofalbum['tracks']['items'] - Playlist tracks are now accessed as
playlist['tracks'](list) instead ofplaylist['tracks']['items'] - All examples now use safe access patterns for fields that may not be available
- Improved error handling in documentation examples
Documentation¶
- Comprehensively tested all extractors to identify exact available fields
- Updated README, Wiki, and all documentation files with corrected field usage
- Added notes explaining which fields are not available via web scraping
- Fixed over 10 documentation files with incorrect field references
[2.0.20] - 2025-05-28¶
Fixed¶
- Fixed documentation incorrectly listing 'popularity' as an available field for tracks
- Updated all examples to remove references to track['popularity'] field
- Clarified that popularity data is only available via Spotify's official API, not web scraping
Changed¶
- Updated README to correctly list available track fields
- Modified example code to use proper field names (is_explicit instead of explicit)
- Added notes in documentation about web scraping limitations vs official API
Documentation¶
- Corrected track metadata field list in README
- Updated Wiki examples to remove popularity field references
- Added clarification about available fields when using web scraping
[2.0.19] - 2025-05-28¶
Fixed¶
- Fixed None handling in CLI utilities for duration_ms values
- Fixed bulk operations
extract_urls_from_textto handle None input gracefully - Fixed playlist formatter to safely handle None tracks data
Changed¶
- Aligned documentation across README, GitHub Wiki, and PyPI with consistent tone and structure
- Updated all Wiki pages with unified formatting and improved examples
- Enhanced API reference documentation with comprehensive examples
- Improved FAQ section with common issues and solutions
Documentation¶
- Created unified documentation templates for better consistency
- Added more real-world examples in the Examples section
- Improved Quick Start guide with clearer instructions
- Enhanced troubleshooting information in FAQ
[2.0.18] - 2025-05-28¶
Added¶
- Added
process_urls()method toSpotifyBulkOperationsclass for processing multiple URLs - Added
export_to_json()andexport_to_csv()methods toSpotifyBulkOperations - Added
batch_download()method for efficient bulk media downloads - Added comprehensive bulk operations documentation
- Added unit tests for all new bulk operations functionality
Fixed¶
- Fixed bare except clause in
SpotifyBulkOperations(now properly catches and logs exceptions) - Fixed multiple potential None reference errors in CLI utilities
- Fixed None reference errors in JSON parser when handling missing URI fields
- Improved error handling for missing nested dictionary values
- Added proper type checking before accessing dictionary methods
Changed¶
- Improved error handling throughout the codebase with proper exception logging
- Enhanced input validation for safer dictionary access patterns
- Updated documentation with correct usage examples for bulk operations
Security¶
- Added safe handling of potentially None values to prevent crashes
- Improved URI parsing to handle edge cases safely
[2.0.7] - 2025-05-26¶
Fixed¶
- Fixed missing
albumfield inget_track_info()response - Added JSON-LD fallback extraction for album data when missing from primary track data
- Improved track data extraction to be compatible with Spotify Web API structure
[2.0.6] - 2025-05-25¶
Fixed¶
- Fixed automated PyPI deployment by using --no-isolation build to prevent cached metadata
- Added pip cache purge to ensure clean builds
- Fixed Release workflow changelog generation to handle missing previous tags
- Fixed version reference in create-github-release job
- Improved build process to clean all caches and artifacts
Changed¶
- Updated all workflows to use consistent clean build process
- Enhanced error handling in changelog generation
[2.0.5] - 2025-05-25¶
Fixed¶
- Fixed Release workflow startup failure by removing invalid secret conditionals
- Changed Test PyPI steps to use continue-on-error with runtime checks
- Ensured workflow runs successfully even when TEST_PYPI_TOKEN is not configured
[2.0.4] - 2025-05-25¶
Fixed¶
- Fixed GitHub Actions workflows to ensure clean builds
- Added build artifact cleanup step to Release workflow
- Made Test PyPI upload optional when TEST_PYPI_TOKEN is not available
- Fixed PyPI token reference from PYPI_TOKEN to PYPI_API_TOKEN in Release workflow
- Ensured all workflows use consistent build process
[2.0.3] - 2025-05-25¶
Fixed¶
- Fixed license field format in pyproject.toml to comply with PEP 621 specification
- License field now uses {text = "MIT"} format instead of plain string
- Resolved CI/CD pipeline failures on all platforms (Windows, macOS, Linux)
- Fixed "configuration error: project.license must be valid exactly by one definition" error
[2.0.2] - 2025-05-25¶
Fixed¶
- Fixed PyPI deployment metadata issues by cleaning build artifacts before packaging
- Removed deprecated
license-filefield completely from package metadata - Enhanced GitHub Actions workflow to ensure clean builds
[2.0.1] - 2025-05-25¶
Fixed¶
- Fixed KeyError when accessing 'total_tracks' in album data
- Ensured 'total_tracks' field is always present in AlbumData (defaults to 0 if tracks unavailable)
- Improved album data extraction robustness
2.0.0 - 2025-05-23¶
🎆 Complete Rewrite - Modern Architecture¶
SpotifyScraper v2.0 is a complete rewrite from the ground up, modernizing every aspect of the library. This release represents months of development effort to create a more reliable, performant, and developer-friendly tool for extracting Spotify data.
Highlights¶
- 🏗️ New Architecture: Modular design with clear separation of concerns
- 🔒 Type Safety: Full TypeScript-style type hints throughout the codebase
- ⚡ Performance: 3x faster extraction with connection pooling and caching
- 🎨 Media Support: Built-in high-quality preview and cover art downloading
- 🤖 Smart Extraction: Handles Spotify's modern React-based architecture
- 🔄 Backward Compatible: Legacy API available for smooth migration
✨ Added¶
Core Features¶
- SpotifyClient: New high-level client interface for all operations
- Extractor System: Specialized extractors for tracks, albums, artists, and playlists
- JSON Parser: Robust parser for Spotify's
__NEXT_DATA__React structure - Media Downloaders:
AudioDownloader: MP3 preview downloads with ID3 tag embeddingImageDownloader: Cover art in multiple resolutions (300x300, 640x640, original)- CLI Tool: Full-featured command-line interface for all operations
- Authentication: Support for auth tokens and cookie-based authentication
- Configuration Manager: YAML/JSON config files and environment variables
- Type System: Complete TypedDict definitions for all data structures
Browser Backends¶
- RequestsBrowser: Lightweight, fast browser using requests library
- SeleniumBrowser: Full browser automation for complex scenarios
- BrowserFactory: Automatic selection based on requirements
Developer Experience¶
- Type Hints: 100% type coverage with mypy strict mode
- Rich Exceptions: Detailed error messages with recovery suggestions
- Logging: Structured logging with configurable levels and outputs
- Documentation: Comprehensive docstrings and usage examples
- Testing: Extensive test suite with 90%+ code coverage
Advanced Features¶
- Proxy Support: HTTP/HTTPS/SOCKS proxy configuration
- Rate Limiting: Intelligent rate limit handling with backoff
- Retry Logic: Configurable retry strategies for resilience
- Cache System: Optional caching for improved performance
- Async Support: Optional async/await for concurrent operations
- Custom Headers: Support for custom HTTP headers
- Session Persistence: Save and restore authentication sessions
🔄 Changed¶
API Changes¶
- Import Structure: Main classes now in
spotify_scrapernamespace - Method Names: Consistent naming convention across all extractors
- Return Types: All methods return TypedDict structures
- Parameter Names: More descriptive parameter names throughout
- Error Handling: New exception hierarchy with specific error types
Dependency Updates¶
- lxml: 4.5.0 → 5.4.0 (Python 3.12 compatibility, security fixes)
- beautifulsoup4: 4.9.0 → 4.13.0 (performance improvements)
- requests: 2.23.0 → 2.32.3 (security patches, HTTP/2 support)
- urllib3: 1.25.9 → 2.4.0 (modern TLS, connection pooling)
- selenium: New optional dependency 4.30.0+ (WebDriver BiDi support)
- PyYAML: 5.3.1 → 6.0.1 (CVE fixes, Python 3.12 support)
- mutagen: New dependency for ID3 tag support
- Pillow: New optional dependency for image processing
⚒️ Removed¶
- Legacy Code: Removed deprecated v1.x implementation
- Old Dependencies: Removed outdated and insecure packages
- Unused Features: Removed experimental features that weren't stable
- Python 2.7 Support: Dropped support for EOL Python versions
- Python 3.6-3.7: Minimum version now Python 3.8
🔄 Migration Guide¶
Quick Migration¶
The fastest way to migrate is to update your imports:
# Old (v1.x)
from SpotifyScraper.scraper import Scraper, Request
# New (v2.0) - Compatibility mode
from spotify_scraper.compat import Scraper, Request
Recommended Migration¶
For the best experience, migrate to the new API:
# Old way (v1.x)
from SpotifyScraper.scraper import Scraper, Request
request = Request().request()
scraper = Scraper(session=request)
# Get track info
track_info = scraper.get_track_url_info(
url='https://open.spotify.com/track/6rqhFgbbKwnb9MLmUQDhG6'
)
# Download preview
scraper.download_track(track_id='6rqhFgbbKwnb9MLmUQDhG6')
# New way (v2.0)
from spotify_scraper import SpotifyClient
client = SpotifyClient()
# Get track info - cleaner API
track = client.get_track('https://open.spotify.com/track/6rqhFgbbKwnb9MLmUQDhG6')
# Download preview - more options
path = client.download_preview(
track_id='6rqhFgbbKwnb9MLmUQDhG6',
filename='my_song.mp3',
with_cover=True
)
Feature Mapping¶
| v1.x Method | v2.0 Equivalent |
|---|---|
get_track_url_info() |
get_track() |
get_track_id_info() |
get_track_by_id() |
get_album_url_info() |
get_album() |
get_album_id_info() |
get_album_by_id() |
get_artist_url_info() |
get_artist() |
get_playlist_url_info() |
get_playlist() |
download_track() |
download_preview() |
download_cover_image() |
download_cover() |
💥 Breaking Changes¶
Python Version¶
- Minimum Version: Python 3.8+ required (was 3.6+)
- Recommended: Python 3.10+ for best performance
Import Changes¶
# Old
from SpotifyScraper.scraper import Scraper
from SpotifyScraper.request import Request
# New
from spotify_scraper import SpotifyClient
# or for compatibility
from spotify_scraper.compat import Scraper, Request
API Changes¶
- Method signatures have been standardized
- All methods now return TypedDict objects instead of raw dicts
- Removed several deprecated methods
- Configuration is now handled through a dedicated Config class
Behavior Changes¶
- Downloads now include metadata by default
- File naming conventions have changed
- Error messages are more detailed
- Logging is now structured JSON by default
🐛 Fixed¶
Compatibility Fixes¶
- Python 3.12: Resolved lxml compilation errors
- Windows: Fixed path handling for Windows systems
- macOS: Fixed SSL certificate verification issues
- Linux: Improved Chrome/Chromium detection
Bug Fixes¶
- Memory Leaks: Proper cleanup of browser sessions
- Unicode: Correct handling of special characters in titles
- Rate Limiting: Exponential backoff for 429 errors
- Connection Pooling: Fixed connection exhaustion issues
- Proxy Support: Fixed SOCKS proxy authentication
- Cookie Handling: Improved cookie jar persistence
- JSON Parsing: Handle malformed JSON responses gracefully
- File Downloads: Resume partial downloads correctly
Security Fixes¶
- CVE-2023-45803: urllib3 security vulnerability
- CVE-2023-32681: Requests security vulnerability
- CVE-2022-48174: PyYAML arbitrary code execution
- Input Validation: Prevent path traversal attacks
- SSL/TLS: Enforce minimum TLS 1.2
📚 Documentation¶
- README: Complete rewrite with comprehensive examples
- API Reference: Full API documentation with type information
- Tutorials: Step-by-step guides for common use cases
- Migration Guide: Detailed instructions for upgrading from v1.x
- Contributing: Comprehensive contribution guidelines
- Architecture: Technical documentation of the system design
- Examples: 15+ example scripts for various scenarios
🎨 Developer Experience¶
- IDE Support: Full IntelliSense/autocomplete with type hints
- Error Messages: Clear, actionable error messages
- Debugging: Comprehensive logging with context
- Testing: Easy to mock and test with included fixtures
- Examples: Copy-paste ready code examples
- CLI: Intuitive command-line interface
🚀 Performance Improvements¶
- 3x Faster: Extraction speed improved through optimized parsing
- 50% Less Memory: Reduced memory usage with streaming downloads
- Connection Pooling: Reuse HTTP connections for better performance
- Parallel Processing: Support for concurrent operations
- Smart Caching: Cache frequently accessed data
- Lazy Loading: Load data only when needed
🎉 Thank You!¶
This release wouldn't have been possible without the amazing community. Special thanks to: - All contributors who submitted PRs and issues - Early adopters who tested pre-release versions - Users who provided feedback and suggestions
We're excited to see what you build with SpotifyScraper v2.0!
1.0.5 - 2021-03-15¶
Fixed¶
- Updated user agents for better compatibility
- Fixed playlist extraction for large playlists
- Improved error handling for network timeouts
Security¶
- Updated requests to 2.25.1 (security patches)
1.0.4 - 2020-11-20¶
Added¶
- Support for episode and show URLs
- Retry logic for failed requests
Fixed¶
- Unicode handling in track names
- Memory leak in long-running sessions
1.0.3 - 2020-08-15¶
Added¶
- Proxy support via environment variables
- Custom user agent configuration
Fixed¶
- Album art extraction for certain albums
- Timeout handling improvements
1.0.2 - 2020-05-10¶
Fixed¶
- Compatibility with Spotify's updated HTML structure
- Better handling of unavailable tracks
1.0.1 - 2020-02-20¶
Added¶
- Progress callbacks for downloads
- File size validation
Fixed¶
- Windows path handling issues
- Download resume functionality
1.0.0 - 2020-01-15¶
Added¶
- Initial release of SpotifyScraper
- Basic track, album, artist, and playlist extraction
- Support for downloading preview MP3s
- Simple web scraping with requests and BeautifulSoup
- Command-line interface
- Basic documentation
Upgrading¶
From 1.x to 2.0¶
Step 1: Check Python Version¶
python --version # Must be 3.8 or higher
Step 2: Update Package¶
# Uninstall old version
pip uninstall SpotifyScraper
# Install new version
pip install spotifyscraper>=2.0.0
Step 3: Update Code¶
Option A - Quick fix (use compatibility layer):
# Change this line:
from SpotifyScraper.scraper import Scraper, Request
# To this:
from spotify_scraper.compat import Scraper, Request
Option B - Full migration (recommended):
# Old
from SpotifyScraper.scraper import Scraper, Request
req = Request().request()
scraper = Scraper(session=req)
track = scraper.get_track_url_info(url="...")
# New
from spotify_scraper import SpotifyClient
client = SpotifyClient()
track = client.get_track("...")
Step 4: Test¶
# Run your tests
pytest
# Or test manually
python -c "from spotify_scraper import SpotifyClient; print('Import successful!')"