Spotify track and playlist metadata library
Project description
๐ Syncify
Syncify is a Python library + CLI that fetches Spotify track, playlist, and liked-song metadata directly from open.spotify.com pages โ great for quick metadata lookups, playlist introspection, and tooling where you don't want to wire up OAuth.
Heads up: Syncify scrapes Spotify's web UI (via Selenium). Selectors can break if Spotify updates their site.
โจ Features
- Track metadata: title, artist, cover image URL, and track ID from a track URL
- Playlist metadata: playlist title, cover image URL, playlist ID, and all track URLs
- Liked Songs: scrape your full Spotify liked-songs library โ opens a real browser window so you can log in, then collects every track URL automatically
- CLI-first: run
syncify <url>,syncify --likes, orpython -m syncify ... - Auto-detect URLs: mix track + playlist URLs in one command
- No OAuth setup: does not require Spotify API keys/tokens
๐ง How It Works
- Input: Spotify track/playlist URLs or
--likesflag - URL detection: a lightweight regex-based detector determines whether each URL is a Track or Playlist
- Extraction:
- Tracks: Selenium loads the page and extracts title/artist/image from page elements
- Playlists: Selenium loads the page in headless mode, scrolls through the virtualised track list, and collects every track link
- Liked Songs: Selenium opens a visible browser window, navigates to the Spotify login page, and polls the DOM for track elements โ proceeding the instant your liked songs are rendered (no fixed waits)
- Output:
- Library: returns dataclasses (
TrackDetails,PlaylistDetails,LikesDetails) - CLI: prints a readable summary plus track URLs
- Library: returns dataclasses (
๐ Tech Stack
- Language: Python
- Automation/scraping: Selenium (headless Chrome for tracks/playlists, visible Chrome for liked songs)
- Driver management:
webdriver-manager(fallback if Selenium driver resolution fails) - HTML parsing (small helper): BeautifulSoup4
- HTTP:
requests
๐ฆ Installation
Prerequisites
- Python: 3.9+ recommended (packaging allows older, but tested targets are 3.9โ3.12)
- Google Chrome installed (used by Selenium)
Install from PyPI (recommended)
pip install syncify-py
Then use:
- CLI:
syncify ... - Python import:
from syncify import ...
Install from GitHub
pip install "git+https://github.com/adelelawady/Syncify.git"
Install locally (for development)
git clone https://github.com/adelelawady/Syncify.git
cd Syncify
pip install -e ".[dev]"
Install from source tree (non-editable)
pip install .
โ๏ธ Configuration
Syncify has no required environment variables.
Runtime requirements
- Chrome available on PATH / installed normally
- Chromedriver is handled automatically via Selenium's driver resolution, with a fallback to
webdriver-manager.
Troubleshooting
- If Selenium can't start Chrome:
- Ensure Chrome is installed and up to date.
- Try upgrading Selenium and webdriver-manager:
pip install -U selenium webdriver-manager
-
If playlist results are incomplete:
- Spotify's UI loads tracks lazily; the scraper scrolls, but very large playlists may take longer.
-
If liked songs time out:
- Increase
--login-timeout(default is 120 seconds). - Make sure you complete the login โ including any Spotify challenge/captcha pages โ before the timeout expires.
- Increase
๐ Usage
As a library
from syncify import get_track, get_playlist, get_likes
# Track
track = get_track("https://open.spotify.com/track/5nJ4Zzqc2UjwSaIcv7bGjx")
print(track.track_title, "-", track.artist_title)
print(track.track_image_url)
# Playlist
playlist = get_playlist("https://open.spotify.com/playlist/5YOevUTnavVClJ0hAslu0N")
print(playlist.title)
print("Tracks:", len(playlist.track_urls))
print(playlist.track_urls[:5])
# Liked Songs โ opens a browser window for you to log in
likes = get_likes()
print(likes.total_tracks)
for url in likes.track_urls:
print(url)
# Give yourself more time to log in
likes = get_likes(login_timeout=180)
get_likes() parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
login_timeout |
int |
120 |
Seconds to wait for login + page render. Proceeds immediately once ready. |
page_load_timeout |
int |
30 |
Selenium page-load timeout in seconds. |
scroll_pause |
float |
2.0 |
Pause between scroll steps in seconds. |
As a CLI
After installation, you can use either:
syncify ...(console script), orpython -m syncify ...(module execution)
# Auto-detect URL type (track or playlist)
syncify https://open.spotify.com/track/5nJ4Zzqc2UjwSaIcv7bGjx
syncify https://open.spotify.com/playlist/5YOevUTnavVClJ0hAslu0N
# Explicit type
syncify --track https://open.spotify.com/track/...
syncify --playlist https://open.spotify.com/playlist/...
# Fetch your liked songs (opens a browser window for login)
syncify --likes
# Give yourself more time to log in
syncify --likes --login-timeout 180
# Multiple URLs (mixed types supported)
syncify <url1> <url2> <url3>
CLI flags
syncify --track <URL> # fetch a single track
syncify --playlist <URL> # fetch a playlist
syncify --likes # fetch your liked songs
syncify --likes --login-timeout <SECONDS> # custom login timeout (default 120)
syncify <URL> [URL ...] # auto-detect, multiple URLs
๐ก API Reference
get_track(url: str) -> TrackDetails
Fetch metadata for a Spotify track URL.
| Field | Type | Description |
|---|---|---|
spotify_url |
str |
Original Spotify URL |
track_id |
str |
Spotify track ID |
track_title |
str |
Song title |
artist_title |
str |
Artist name |
track_image_url |
str |
Cover image URL |
get_playlist(url: str) -> PlaylistDetails
Fetch metadata for a Spotify playlist URL.
| Field | Type | Description |
|---|---|---|
playlist_url |
str |
Original Spotify URL |
playlist_id |
str |
Spotify playlist ID |
title |
str |
Playlist title |
playlist_image_url |
str |
Cover image URL |
track_urls |
list[str] |
All track URLs in the playlist |
get_likes(login_timeout, page_load_timeout, scroll_pause) -> LikesDetails
Fetch all tracks from your Spotify Liked Songs library. Opens a visible browser window for authentication.
| Field | Type | Description |
|---|---|---|
track_urls |
list[str] |
All liked track URLs |
total_tracks |
int |
Total number of liked tracks (property) |
from syncify.spotify.Spotify_likes_info import LikesDetails, get_likes
# Basic usage โ opens browser, waits for login
details = get_likes()
# Give yourself more time to log in
details = get_likes(login_timeout=180)
print(details.total_tracks)
for url in details.track_urls:
print(url)
Note:
get_likes()opens a real (non-headless) Chrome window and navigates to the Spotify login page. It polls the DOM every second and proceeds the instant your liked songs are rendered โ you are never made to wait longer than necessary.
๐ Project Structure
Syncify/
โโ syncify/
โ โโ __init__.py # Public API exports
โ โโ __main__.py # CLI: `python -m syncify` / `syncify`
โ โโ spotify/
โ โโ Spotify_track_info.py
โ โโ Spotify_playlist_info.py
โ โโ Spotify_likes_info.py # โ Liked Songs scraper
โ โโ utils.py
โ โโ __init__.py
โโ main.py # Convenience script wrapper
โโ pyproject.toml # Modern packaging + dependencies
โโ setup.py # Legacy packaging (mirrors pyproject)
โโ requirements.txt # Dev-friendly requirements list
โโ README.md
๐งช Development
git clone https://github.com/adelelawady/Syncify.git
cd Syncify
python -m venv .venv
# Windows PowerShell
.venv\Scripts\Activate.ps1
pip install -e ".[dev]"
# Run the CLI against a URL
python -m syncify https://open.spotify.com/track/<id>
# Fetch liked songs
python -m syncify --likes --login-timeout 180
Suggested checks:
python -c "from syncify import get_track; print(get_track('https://open.spotify.com/track/<id>').track_title)"
python -c "from syncify import get_likes; d = get_likes(); print(d.total_tracks)"
๐ค Contributing
Contributions are welcome!
- Bugs/requests: open an issue with a minimal repro (URL + expected vs actual output)
- PRs:
- Keep changes focused and include a clear description
- Prefer small, well-scoped improvements to selectors and parsing logic
- Avoid committing local artifacts (
.venv/,build/,syncify.egg-info/)
If you're adding new scraping logic, please include:
- A sample Spotify URL (track/playlist) that the change targets
- A note about which DOM selectors were relied on and why
๐ License
MIT (as declared in package metadata).
Tip: consider adding a top-level
LICENSEfile so GitHub can display the license automatically.
โญ Support
If you find Syncify useful, please star the repo โ it helps others discover the project and motivates continued maintenance.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file syncify_py-2.2.0.tar.gz.
File metadata
- Download URL: syncify_py-2.2.0.tar.gz
- Upload date:
- Size: 19.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f74a35db452497b8a0b7ef8b5dae527c0aef0bd394899f7f5cdaae6972501109
|
|
| MD5 |
d015d5175e76d0caa6126117d4bb76d6
|
|
| BLAKE2b-256 |
331f42552aaef3822f2520a38e6efb62e4b804719437cb6123b7e293be558b4d
|
File details
Details for the file syncify_py-2.2.0-py3-none-any.whl.
File metadata
- Download URL: syncify_py-2.2.0-py3-none-any.whl
- Upload date:
- Size: 18.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
33a7bc18bf294e8835813a955e0a336506699d1f0d974d0b827dbc4468e8c96a
|
|
| MD5 |
ea6875c86b7f958d44157be5195f818c
|
|
| BLAKE2b-256 |
5ab0b999c233783e32f6023374a0a37b18fe51ca53dcd3e74a4aa185ee3800d8
|