πΆ HARMONI
A modular, Python-based command-line tool for downloading music from Spotify & Youtube using yt-dlp.
Features interactive menus, system checks, download management, metadata embedding, robust logging, and Spotify Web API (OAuth PKCE) playlist/liked-song loading.
Screenshots
π Features
NEW: Spotify Web API (OAuth PKCE) β authenticate and download directly from your Spotify playlists and Liked Songs
- Enhanced Interactive CLI menus for downloads, management, and automation
- Batch and single downloads pick and choose what you prefer
- Playlist file download: using the playlist file.
- Download from Exportify CSVs that you can get from Exportify
- Download From Youtube paste the link and download playlist or video as audio file.
- Flexible playlist downloads: whole playlists at once or individual ones.
- System resource checks (CPU, RAM, storage)
- Track management via JSON files (pending, failed, history)
- Download by artist and song name
- Configurable settings in
config.json - metadata embedding for downloaded music
- Retry failed downloads
- Duplicate detection and file organization
- Colorful terminal logs (via
colorama) - Persistent logging to
app.log - Modular, maintainable codebase
- Export library data as JSON with detailed track and album info.
- Clean up music library by removing broken, or unreadable tracks.
- Choosing audio format and target bitrate w/ quality and size impacts.
π§ Spotify Web API (NEW) β Setup + Authentication (Recommended)
HARMONI can now load tracks directly from your Spotify account (playlists + liked songs) via the Spotify Web API.
What you need
- A Spotify account
- (Recommended) a Spotify Developer app Client ID
- A Redirect URI (default:
http://127.0.0.1:8888/callback)
This project uses Authorization Code + PKCE, so no client secret is required.
1) Create a Spotify app (recommended)
- Go to https://developer.spotify.com/dashboard
- Create an app (or select an existing app)
- In the app settings, add this Redirect URI exactly (must match byte-for-byte):
http://127.0.0.1:8888/callback
- Copy your Client ID
- Paste it into your config:
spotify_client_idinspotify-yt-dlp-downloader/config.json
2) Configure Spotify API settings in config.json
These are the key settings used by the Spotify Web API workflow:
{
"spotify_client_id": "",
"spotify_redirect_uri": "http://127.0.0.1:8888/callback",
"spotify_scopes": [
"playlist-read-private",
"playlist-read-collaborative",
"user-library-read"
],
"spotify_cache_tokens": true,
"spotify_auto_refresh": true
}Notes:
spotify_scopescontrols what Spotify permissions you request.- The defaults support reading your playlists and your liked songs.
- Token caching is stored at
data/spotify_tokens.jsonwhen enabled. - Spotify no longer allows
localhostas a redirect URI; use a loopback IP like127.0.0.1.
3) Authenticate (OAuth PKCE) in the app
- Run the app
- Go to: Downloads Menu β Spotify Web API (OAuth) β Playlists / Liked Songs
- Choose: Authenticate with Spotify (OAuth PKCE)
- The app will show an authorize URL and offer to open it in your browser
- After you approve, Spotify redirects to your
spotify_redirect_uri - HARMONI starts a tiny local callback server and should auto-capture the redirect.
- If the callback server cannot start (port in use / restricted environment), it will fall back to asking you to paste the full redirect URL.
After authentication, HARMONI caches the token (if enabled) and will reuse/refresh it automatically.
4) Download from playlists or liked songs
From the same Spotify menu:
- Download from my playlists
- Download from liked songs
Youβll be prompted to:
- pick playlists (checkbox UI)
- optionally cap the maximum tracks loaded (for large libraries)
- choose tracks to download using the per-playlist song selection UI
π Spotify Export downloads (Legacy inputs)
If you are using the Spotify Web API workflow above, you can skip this section.
If you prefer file-based workflows (CSV/JSON), HARMONI still supports Spotify exports via either Exportify or Spotifyβs official data export.
NOTE: You have two options for getting Spotify data into the application:
- Official Spotify Data Export (detailed below)
- Exportify (recommended alternative - no waiting for email)
Option 1: Official Spotify Data Export
Before using HARMONI for spotify downloads, you can request your personal Spotify data from Spotify's Privacy page. Spotify will provide you with a ZIP file containing several JSON files, including one named YourLibrary.json.
This YourLibrary.json file contains your saved tracks, albums, and playlists metadata, which HARMONI can use to generate the track list and manage downloads.
How to get your Spotify data:
Go to Spotify's Privacy Request page.
Request your personal data export.
Spotify will email you a ZIP file when ready.
Extract the ZIP and locate YourLibrary.json.
Use or convert this JSON file as the basis for your data/tracks.json to run HARMONI.
Option 2: Exportify (Recommended Alternative)
Exportify is a simpler, faster way to get your Spotify playlists without waiting for Spotify's email response.
How to use Exportify:
Go to https://exportify.net/
Click "Login with Spotify" and authorize the application
Click "Export" next to your chosen playlist
Save the CSV file to the data/exportify/ folder in your project
Exportify downloads are immediately available and don't require the waiting period associated with official Spotify data exports.
This step is essential to generate the input data HARMONI needs for downloading your favorite music.
π Project Structure
spotify-ytdlp/
β
βββ main.py # Entry point, interactive menus
βββ config.py # Loads config from config.json
βββ config.json # User-configurable settings
βββ requirements.txt # Dependencies
βββ changelog.md # change log
βββ app.log # Log file
βββ todo.md # Development notes
βββ constants.py # constants
β
βββ history/
β βββ prototype.py # First version of this entire app
βββ data/
β βββ exportify # Directory where you should place your exportify csv files
β βββ tracks.json # Track list (with artist, album, track, uri)
β βββ playlists.json # (Optional/legacy) playlists export format
β βββ failed_downloads.json # Tracks that failed to download
β βββ download_history.json # Downloaded tracks history
β βββ spotify_tokens.json # (Optional) cached Spotify OAuth token (Spotify Web API)
βββ export/
β βββ potyy_export_(MDY).json # export of tracks in music folder
β βββ playlist_tracklist.json # playlist in tracks format
βββ downloader/
β βββ base_downloader.py # Download logic (single, batch)
β βββ playlist_download.py # Download playlists
β βββ metadata.py # Embed metadata
β βββ retry_manager.py # Retry failed downloads
β βββ youtube_link_downloader.py # Download Directly from youtube link
β βββ __init__.pyβ
βββ menus/ # Interactive menu modules
β βββ automation_menu.py # Menu for automation section
β βββ downloads_menu.py # Menu for downloads section
β βββ main_menu.py # Menu for main section
β βββ management_menu.py # Menu for management section
β βββ tools_menu.py # Menu for tools section
β βββ __init__.py
+
+βββ spotify_api/ # Spotify Web API (stdlib-only) OAuth PKCE + client + loaders
βββ tools/
β βββ choose_audio_format.py # pick global format for download
β βββ compress_music.py # compress songs to a certain format
β βββ dependency_check.py # check if your dependencies are installed
β βββ library_cleanup.py # deletes broken track files
β βββ library_export_json.py # all tracks in music folder as json
β βββ open_log.py # opens app.log
β βββ playlist_to_tracklist.py # playlist turned into tracklist format
β βββ __init__.py
βββ managers/
β βββ file_manager.py # Duplicate detection, file organization
β βββ resume_manager.py # Resume batch downloads
β βββ schedule_manager.py # Scheduled downloads
β βββ __init__.py
βββ utils/
β βββ logger.py # Logging utilities
β βββ loaders.py # Loading utilities
β βββ system.py # System resource checks
β βββ track_checker.py # Check downloaded files
β βββ __init__.py
βββ music/ # Downloaded music files
β Prerequisites
- Python 3.9+
- ffmpeg available on your system PATH (required for
yt-dlpaudio extraction/post-processing) - Internet connection (YouTube)
Spotify input options (choose one)
- Spotify Web API (recommended):
- a Spotify account
- your own Spotify Developer app Client ID
- a Redirect URI (default:
http://127.0.0.1:8888/callback)
- Legacy file-based inputs: Exportify CSVs and/or Spotify official export JSON
Prefer not installing system dependencies? Use the Docker deployment below.
βοΈ Installation (Python version 3.9)
-
Clone the repository:
git clone https://github.com/Ssenseii/spotify-yt-dlp-downloader.git cd spotify-ytdlp -
Create and activate virtual environment:
python3 -m venv .venv source .venv/bin/activate # On Windows: .venv\Scripts\activate
-
Install dependencies:
python3 -m pip install -r requirements.txt
(if you use system check it'll say yt-dlp is not installed even if it is so don't worry about that until I fix that check).
-
Ensure
yt-dlpis installed:python3 -m pip install yt-dlp
π Quick Start with start.sh
For an effortless setup and launch experience, use the provided start.sh script:
This script automatically handles:
- Virtual Environment Creation: If
.venvdoesn't exist, it creates one for you - Dependency Installation: Automatically installs all required packages from
requirements.txtwhen creating a new virtual environment - Application Launch: Activates the virtual environment and starts the application
No manual setup required! The script will guide you through the process with clear status messages.
π³ Docker Deployment
If you'd rather not install Python/ffmpeg locally, you can run HARMONI fully inside Docker. The provided Docker setup includes system dependencies like ffmpeg and runs the same interactive questionary menus.
Prerequisites
- Docker
- Docker Compose (recommended)
Option A: Docker Compose (recommended)
From the spotify-yt-dlp-downloader/ folder:
docker compose build docker compose run --rm --service-ports spotify-yt-dlp-downloader
If you have an older Docker setup,
docker-composemay be the correct command.
Option B: Docker only
docker build -t spotify-yt-dlp-downloader . docker run --rm -it \ -v "$(pwd)/data:/app/data" \ -v "$(pwd)/music:/app/music" \ -v "$(pwd)/export:/app/export" \ -v "$(pwd)/config.json:/app/config.json" \ -e TERM=xterm-256color \ spotify-yt-dlp-downloader
Persistent data (volume mounts)
The examples above mount local folders/files into the container so your library survives container restarts:
./dataβ/app/data(tracks/playlists/history/failed +data/exportify/*.csv)./musicβ/app/music(downloaded audio)./exportβ/app/export(JSON exports, etc.)./config.jsonβ/app/config.json(your settings)
Common commands
# Rebuild after code/dependency changes docker compose build --no-cache # Run again (interactive menu) docker compose run --rm spotify-yt-dlp-downloader # Open a shell inside the container (for debugging) docker compose run --rm --entrypoint /bin/sh spotify-yt-dlp-downloader
Notes (interactive mode)
- This is an interactive CLI app, so you need a TTY:
- Compose already sets
stdin_open: trueandtty: true - With plain Docker, always use
-it
- Compose already sets
- If the checkbox menus donβt respond, try a real terminal (not a basic IDE console) and ensure
TERMis set (see examples above).
βοΈ Upgrade guide
If the system fails to donwload your music too frequently, make sure to run this command
```bash
python3 -m pip install --upgrade yt-dlp
```
π Configuration
Edit config.json to set your preferences:
{
"tracks_file": "data/tracks.json",
"playlists_file": "data/playlists.json",
"output_dir": "music",
"audio_format": "mp3",
"sleep_between": 5,
"average_download_time": 20,
"spotify_client_id": "",
"spotify_redirect_uri": "http://127.0.0.1:8888/callback",
"spotify_scopes": [
"playlist-read-private",
"playlist-read-collaborative",
"user-library-read"
],
"spotify_cache_tokens": true,
"spotify_auto_refresh": true
}π΅ Track List Format
data/tracks.json should contain:
{
"tracks": [
{
"artist": "Artist Name",
"album": "Album Name",
"track": "Song Title",
"uri": "spotify:track:xxxx"
}
]
}π΅ Playlist Format
data/playlists.json should contain:
{
"playlists": [
{
"name": "Simon vol.94",
"lastModifiedDate": "2025-05-03",
"items": [
{
"track": {
"trackName": "Time of Our Lives",
"artistName": "Pitbull",
"albumName": "Globalization",
"trackUri": "spotify:track:2bJvI42r8EF3wxjOuDav4r"
},
"episode": null,
"audiobook": null,
"localTrack": null,
"addedDate": "2025-05-03"
},
]
}]
}βΆοΈ Usage
Run the program:
# First activate the virtual environment source .venv/bin/activate # On Windows: .venv\Scripts\activate # Then run the program python3 main.py
or
# Just do everything for me...
./start.shYou will see a menu with options for downloading, checking files, importing playlists, retrying failed downloads, and more.
Here's the updated Dependencies section including mutagen and schedule:
π Dependencies
- yt-dlp - YouTube downloader
- psutil - System resource monitoring
- colorama - Colored terminal output
- mutagen - Audio metadata tagging and manipulation
- schedule - Job scheduling for periodic tasks
- Questionar - for the interactive menu
- Shutil - for systems stuff
Install all:
python3 -m pip install -r requirements.txt
or
π Logging
- Terminal output is colored for readability
app.logstores a full log history of actions, warnings, and errors
β οΈ Disclaimer
This tool is for personal use only.
Ensure you respect copyright laws and YouTube's terms.
License
This project is licensed under the MIT License β see the LICENSE file for details.

