🚀 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.
Metadata
Release files for syncify-py 2.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| syncify_py-2.3.0.tar.gz | 17.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| syncify_py-2.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 34.9 kB
Release files / syncify_py-2.3.0.tar.gz
| Download URL | syncify_py-2.3.0.tar.gz |
|---|---|
| Size | 17.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c5915456df3f72af1221a11a76c2a4cbfd5216b27d76e4a20b62aac9c72a4825
|
|
BLAKE2b-256 checksum How to use checksums |
f3739ab2d7a00ec215859bb12a4ebed9586afb714e658521ece3b96457736cdd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.0
|
Release files / syncify_py-2.3.0-py3-none-any.whl
| Download URL | syncify_py-2.3.0-py3-none-any.whl |
|---|---|
| Size | 17.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
623e84f78846ae246a9c59426489c33b230447f20aafda7a42761f9337cf9632
|
|
BLAKE2b-256 checksum How to use checksums |
d3b17c430d18d16aa48c95f293091ba461d6a9e56e88cf927e83ee4c9b18bb59
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.0
|