Sync music between local MP3 files and Spotify / Youtube playlists. Supports two-way synchronization: upload local MP3 metadata to Spotify, or download Spotify playlist tracks as MP3s via YouTube.
- Sync Local to Spotify (
sync-to-spotify): Scan a local directory of MP3 files, find matching tracks on Spotify, and add them to a specified Spotify playlist. - Sync Spotify to Local (
sync-from-spotify): Fetch tracks from a Spotify playlist, search for corresponding audio on YouTube, download them as MP3 files, and apply metadata (title, artist, album, cover art). - Download YouTube Playlist (
from-youtube): Download audio from a YouTube playlist directly as MP3s. - Uses
.envfile, environment variables, or command-line arguments for Spotify API configuration. - Parallel downloads for faster Spotify-to-Local syncing.
-
Sync Local MP3s to Spotify (
sync-to-spotify):- Scans the specified directory for
.mp3files. - Attempts to read metadata (artist, title, album) from each MP3 file using
eyed3. - If metadata is missing, it tries to parse this information from the filename (assuming formats like
Artist - Album - Title.mp3). - Constructs a search query for each valid track.
- Uses the Spotify API (
spotipy) to search for matching tracks. - If a match is found, its Spotify track URL is recorded.
- Checks if the target Spotify playlist exists by name. If not, creates it.
- Adds all found Spotify track URLs to the target playlist in chunks.
- Scans the specified directory for
-
Sync Spotify Playlist to Local MP3s (
sync-from-spotify):- Fetches all track details (ID, name, artist, album, art URL) from the specified Spotify playlist ID using
spotipy. - For each track, constructs a search query (e.g., "Artist Title Album audio").
- Uses
youtubesearchpythonto search YouTube for the best matching video. - If a YouTube video is found, its URL is recorded.
- Uses
yt-dlp(which requires FFmpeg) to download the audio stream from the YouTube URL. yt-dlpconverts the audio to MP3 format and attempts to embed metadata (title, artist, album) and the video thumbnail as cover art directly during the download/conversion process.- Saves the resulting MP3 file to the specified output directory with a sanitized filename (e.g.,
Artist - Title.mp3). - Limitation: This process relies entirely on finding a suitable match on YouTube. If a track from the Spotify playlist isn't available on YouTube or the search doesn't find the correct match, that track cannot be downloaded.
- Fetches all track details (ID, name, artist, album, art URL) from the specified Spotify playlist ID using
-
Download YouTube Playlist (
from-youtube):- Takes a YouTube playlist URL as input.
- Uses
yt-dlp(which requires FFmpeg) to iterate through the playlist videos. - For each video, downloads the best audio stream.
- Converts the audio to MP3 format.
- Attempts to embed metadata extracted from YouTube (title, uploader, etc.) and the video thumbnail as cover art during the download/conversion process.
- Saves the resulting MP3 file to the specified output directory using a sanitized filename format like
Index - Title.mp3. - Limitation: Metadata quality depends entirely on what's available on YouTube for each video. Artist/Album information might be inaccurate or missing compared to Spotify.
- Python >= 3.8
uv(Recommended, for environment/package management)- Spotify Account & API Credentials (see Spotify API Setup)
- FFmpeg: Required by
yt-dlpfor audio conversion. Install via your system's package manager:- Ubuntu/Debian:
sudo apt update && sudo apt install ffmpeg - macOS:
brew install ffmpeg - Windows: Download from ffmpeg.org or use
choco install ffmpeg. Ensureffmpeg.exeis in your system's PATH.
- Ubuntu/Debian:
- Create a Spotify Developer Account:
- Go to the Spotify Developer Dashboard
- Log in with your Spotify account or create one if needed
- Create a New Application:
- Click "Create App"
- Fill in the application details:
- App name:
mp3ify(or any name you prefer) - App description: A brief description of what the app does
- Redirect URI:
http://127.0.0.1:8888(must match the URI you use with the app) - Accept the terms and conditions
- Click "Create"
- App name:
- Get Your API Credentials:
- On your app's dashboard, you'll see:
- Client ID: Copy this value
- Client Secret: Click "Show Client Secret" and copy this value
- Configure mp3ify:
- You can provide your API credentials in three ways:
a) Command line arguments (as shown in the Usage example):
python mp3ify.py --oauthclientid <client-id> --oauthclientsecret <client-secret> --oauthredirecturi http://localhost:8080b) Environment variables:
# Linux/macOS
export SPOTIPY_CLIENT_ID=<client-id>
export SPOTIPY_CLIENT_SECRET=<client-secret>
export SPOTIPY_REDIRECT_URI=http://localhost:8080
# Windows (Command Prompt)
set SPOTIPY_CLIENT_ID=<client-id>
set SPOTIPY_CLIENT_SECRET=<client-secret>
set SPOTIPY_REDIRECT_URI=http://localhost:8080
# Windows (PowerShell)
$env:SPOTIPY_CLIENT_ID="<client-id>"
$env:SPOTIPY_CLIENT_SECRET="<client-secret>"
$env:SPOTIPY_REDIRECT_URI="http://localhost:8080"c) Create a .env file (recommended for repeated use):
# Create a .env file in the project directory
echo "SPOTIPY_CLIENT_ID=<client-id>" > .env
echo "SPOTIPY_CLIENT_SECRET=<client-secret>" >> .env
echo "SPOTIPY_REDIRECT_URI=http://127.0.0.1:8888" >> .envmp3ify will automatically load these variables from a .env file in the current directory, or you can specify a different file:
python mp3ify.py --env-file /path/to/your/.envNote: Make sure .env is listed in your .gitignore to avoid accidentally committing your credentials.
- Authentication Flow:
- When you first run
mp3ifyusing a command that requires user authorization (liketo-spotify), it initiates the Spotify OAuth2 flow. - A browser window will likely open asking you to log in to your Spotify account and grant permissions to the application.
- After you approve, Spotify redirects your browser back to the Redirect URI you configured in the Spotify Developer Dashboard and in your
mp3ifysettings (e.g.,http://127.0.0.1:8888). - Important Note on Local Port: To receive this redirect,
mp3ify(specifically, thespotipylibrary) starts a temporary local web server listening on the host and port specified in your Redirect URI (e.g.,127.0.0.1and port8888). - If another application on your computer is already using this specific port, you will encounter an
[Errno 98] Address already in useerror, and the authentication cannot complete. To fix this:- Stop the other application using the port, OR
- Choose a different, unused port (e.g., 9090, 5001, etc.). Update the Redirect URI in both your Spotify Developer Dashboard application settings and your
mp3ifyconfiguration (.envfile, environment variables, or command-line arguments).
- Once the temporary server receives the redirect from Spotify, it extracts an authorization
codefrom the URL. - The browser page itself might show a "Connection Refused" or similar error after the redirect; this is usually normal because the temporary server shuts down immediately after grabbing the code.
spotipythen exchanges this code for access tokens behind the scenes.- If you are running in a terminal environment where a browser cannot be automatically opened, you might see a message asking you to manually open a URL, authorize, and then paste the full final URL (the one you were redirected to, containing the
code=...part) back into the terminal.
-
Clone the repository:
git clone https://github.com/alienmind/mp3ify.git cd mp3ify -
Install
uv: Follow the official instructions at astral.sh/uv or use one of the common methods:# macOS / Linux curl -LsSf https://astral.sh/uv/install.sh | sh # Windows (Powershell) powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
Verify the installation:
uv --version
-
Create and activate virtual environment:
# Create the virtual environment (creates a .venv directory) uv venv # Activate the environment # Linux / macOS source .venv/bin/activate # Windows (cmd.exe) # .venv\Scripts\activate.bat # Windows (Powershell) # .venv\Scripts\Activate.ps1
You should see
(.venv)prepended to your shell prompt. -
Install dependencies:
# Install runtime and development dependencies uv pip install -e ".[dev,test]"
mp3ify now uses subcommands to determine the sync direction.
Note: Examples show direct script execution. If you installed the package using pip install . or uv pip install ., you might be able to run mp3ify <command> ... directly without python mp3ify.py.
python mp3ify.py to-spotify [OPTIONS]Options:
-d,--directory DIRECTORY: Directory containing MP3 files (default:mp3/).--playlist PLAYLIST_NAME: Name of the Spotify playlist to create/update (default:MP3ify).- Authentication options (
--oauthclientid, etc.) if not using environment variables or.env.
Example:
# Scan ./my_music and sync to a playlist named "My Local Gems"
python mp3ify.py to-spotify -d ./my_music --playlist "My Local Gems"python mp3ify.py from-spotify --playlist-id <SPOTIFY_PLAYLIST_ID> [OPTIONS]Required:
--playlist-id PLAYLIST_ID: The ID of the Spotify playlist to download. Find this in the playlist's URL (e.g.,https://open.spotify.com/playlist/YOUR_PLAYLIST_ID).
Options:
-d,--directory DIRECTORY: Directory to save downloaded MP3 files (default:spotify_downloads/).- Authentication options (
--oauthclientid, etc.) if not using environment variables or.env.
Example:
# Download tracks from a specific playlist to the default ./spotify_downloads folder
python mp3ify.py from-spotify --playlist-id 37i9dQZF1DXcBWIGoYBM5M
# Download tracks to a custom folder using -d
python mp3ify.py from-spotify --playlist-id 37i9dQZF1DXcBWIGoYBM5M -d ./downloaded_musicpython mp3ify.py from-youtube --playlist-url <YOUTUBE_PLAYLIST_URL> [OPTIONS]Required:
--playlist-url URL: The full URL of the YouTube playlist to download.
Options:
-d,--directory DIRECTORY: Directory to save downloaded MP3 files (default:youtube_downloads/).--keep-intermediate-files: If set, keeps all files downloaded byyt-dlp(original audio/video format, thumbnails like.webp/.png, etc.) instead of just the final.mp3. Defaults to deleting intermediate files. Controlled byMP3IFY_KEEP_INTERMEDIATEenv var if flag not used.
Example:
# Download audio from a YouTube playlist to the default ./youtube_downloads folder
python mp3ify.py from-youtube --playlist-url "https://www.youtube.com/playlist?list=PLxxxxxxxxxxxxxxx"
# Download to a custom folder
python mp3ify.py from-youtube --playlist-url "https://www.youtube.com/playlist?list=PLxxxxxxxxxxxxxxx" -d ./my_youtube_musicTo test downloading tracks from a specific sample playlist into the tests/mp3 directory, first ensure the directory exists (mkdir -p tests/mp3) and then run:
# Use -d for the output directory
python mp3ify.py from-spotify --playlist-id 54mvdz04MpqdRjRVrEbWYM -d tests/mp3This command will fetch tracks from the specified playlist, search for them on YouTube, and download the MP3s with metadata into the tests/mp3 folder.
--env-file FILE_PATH: Specify a custom path for the.envfile.--num-cores N: Set the maximum number of parallel worker threads for download operations (from-spotify). Set to0to use the maximum available cores. Defaults to 5, or the value of theNUMCORESenvironment variable if set. (Note: This currently only affects thefrom-spotifycommand's parallel search/download;from-youtuberelies onyt-dlp's internal handling).- Authentication flags (
--oauthclientid, etc.) can be used withto-spotifyandfrom-spotify.
SPOTIPY_CLIENT_ID: Your Spotify application Client ID.SPOTIPY_CLIENT_SECRET: Your Spotify application Client Secret.SPOTIPY_REDIRECT_URI: Your Spotify application Redirect URI (e.g.,http://127.0.0.1:8888).NUMCORES: Overrides the default number of parallel workers (5) forfrom-spotify. Command-line argument--num-corestakes precedence. Set to0for maximum available cores.MP3IFY_KEEP_INTERMEDIATE: Set totrue,1, oryesto keep all intermediate files (original format, thumbnails) when using thefrom-youtubecommand. Defaults tofalse. The--keep-intermediate-filescommand-line flag takes precedence.
Here's a sequence demonstrating how you might use mp3ify to download a YouTube playlist, upload its contents to Spotify, and then re-download that Spotify playlist:
-
Download YouTube Playlist to Local Folder: Download the audio tracks from the specified YouTube playlist into a local directory named
mp3.python mp3ify.py from-youtube --playlist-url https://www.youtube.com/playlist?list=PLidIjcybOMhyQDmIGJglNjAQFR0BLFZ_m -d mp3(This will create sanitized MP3 files like
01 - Title One.mp3,02 - Title Two.mp3, etc., in the./mp3directory) -
Sync Local Folder to New Spotify Playlist: Scan the
./mp3directory created in the previous step, search for matches on Spotify, and create/update a Spotify playlist named "Jinjer" with the found tracks.python mp3ify.py to-spotify -d mp3 --playlist "Jinjer"(This requires Spotify authentication and will create a private playlist named "Jinjer" on your Spotify account if it doesn't exist.)
-
Sync New Spotify Playlist Back to a Different Local Folder: Download the tracks from the "Jinjer" playlist (created in step 2) to a new local directory named
mp3_from_spotify. Note: You first need to find the Playlist ID for your "Jinjer" playlist (e.g., by finding the playlist in Spotify, clicking "Share", and copying the Playlist Link - the ID is the string of characters afterplaylist/and before?).# Replace <JINJER_PLAYLIST_ID> with the actual ID found on Spotify python mp3ify.py from-spotify --playlist-id <JINJER_PLAYLIST_ID> -d mp3_from_spotify
(This will search YouTube for each track in the "Jinjer" playlist and download the best match into the
./mp3_from_spotifydirectory, attempting to embed metadata from Spotify.)
