Enjoying YMDE? Please consider starring the project on GitHub! Your support helps the project grow.
YMDE is a simple tool for downloading your music from YouTube and organizing it into a clean, tagged library suitable for media servers like Jellyfin or Plex.
It scans your Google Takeout playlists (both JSON and CSV), downloads the audio for each track, and saves it into a structured folder format.
Disclaimer: This tool is for personal, archival purposes only. Ensure your use complies with YouTube's Terms of Service and all applicable laws in your country.
- Process Google Takeout: Directly handles
JSONandCSVplaylists from your YouTube Music export. - Optimized for Media Servers: Creates a clean library structure compatible with Jellyfin, Plex, and others.
- Parallel Downloads: Uses
yt-dlpwith multiple concurrent downloads for speed. - Embedded Metadata & Thumbnails: Automatically tags audio files with track info and cover art.
- Automatic Playlist Generation: Creates
.m3u8playlist files for easy importing. - Smart Deduplication: Avoids re-downloading tracks that already exist anywhere in your library.
- Automatic Title Cleaning: Removes clutter like
(Official Video)from track titles. - Optional Non-Music Trimming (SponsorBlock): Remove intros/outros/sponsor/selfpromo/misc segments using community data (enabled by default).
- Automatic Replacement Search: If a track fails with a "video unavailable" error, YMDE can automatically search YouTube for a likely replacement and download it instead (enabled by default).
Prerequisites: You need Docker and Docker Compose installed.
Create data and library folders in the same directory as the compose.yml file.
mkdir -p data libraryQuick Steps:
- Go to Google Takeout.
- Uncheck all categories except "YouTube and YouTube Music".
- Click "Multiple formats" and set History to JSON or CSV.
- Click "Next step" and request your data.
- When your archive is ready, download and extract it.
- Copy all
.csvand.jsonfiles from
Takeout/YouTube and YouTube Music/playlists/
into your local./data/folder.
Copy the example below and save it as compose.yml.
services:
ymde:
image: ghcr.io/warreth/ymde:latest
container_name: ymde
volumes:
- ./data:/data
- ./library:/library
environment:
# --- Basic Configuration ---
- AUDIO_FORMAT=m4a # one of [flac, alac, wav, aiff, opus, vorbis, aac, m4a, mp3, ac4, eac3, ac3, dts]
- QUALITY=0 # For MP3, VBR quality (0=best, 9=worst)
- CONCURRENCY=4 # Number of parallel downloads
- WRITE_M3U=1 # 1=Create M3U8 playlists, 0=disable
- REMOVE_VIDEOS_SUFFIX=1 # 1=Remove "-videos" from playlist names, 0=disable
- PREFER_YOUTUBE_MUSIC=1 # 1=Rewrite URLs to music.youtube.com for better metadata
- TRIM_NON_MUSIC=1 # 1=Trim non-music segments via SponsorBlock
- RETRY_SEARCH_IF_UNAVAILABLE=1 # 1=Search for replacement if original video is unavailable
# --- Advanced Configuration ---
# - RATE_LIMIT=1M # Limit download speed (e.g., 500K, 1M).
# - SLEEP="2,8" # Sleep for a random 2-8 seconds between downloads.
# - DRY_RUN=1 # 1=Simulate without downloading, 0=disable
# - COOKIES=/data/cookies.txt # Path to cookies file for private/gated content.
# - SPONSORBLOCK_CATEGORIES="sponsor,intro,outro" # Example overriding categoriesExecute the downloader using Docker Compose. It will pull the image (if not local), run the process, and then exit.
docker compose run --rm ymdeYour music will appear in the ./library directory, organized by playlist.
At the end of the process, you will see a summary of how many tracks were downloaded, skipped, or failed.
All settings are managed through environment variables in your compose.yml file.
| Variable | Description | Default |
|---|---|---|
AUDIO_FORMAT |
Output audio format. | m4a |
QUALITY |
For mp3, VBR quality (0=best, 9=worst). |
0 |
CONCURRENCY |
Number of downloads to run in parallel. | 4 |
WRITE_M3U |
1 to create .m3u8 playlists in a _playlists folder. |
1 |
REMOVE_VIDEOS_SUFFIX |
1 to change My Playlist-videos to My Playlist. |
1 |
PREFER_YOUTUBE_MUSIC |
1 to rewrite URLs to music.youtube.com for better metadata. |
1 |
TRIM_NON_MUSIC |
1 to trim non-music segments (SponsorBlock). |
1 |
RETRY_SEARCH_IF_UNAVAILABLE |
1 to auto-search & retry when a video is unavailable. |
1 |
FALLBACK_MAX_RESULTS |
Max search results considered for a replacement when unavailable. | 6 |
SPONSORBLOCK_CATEGORIES |
Override categories (comma list). Default when enabled: sponsor,intro,outro,selfpromo,music_offtopic |
|
RATE_LIMIT |
Download speed limit (e.g., 1M). Automatically set to 500K if no cookies are used. |
|
SLEEP |
Delay between downloads. Fixed (5) or random range (2,8). |
|
DRY_RUN |
1 to simulate the process without downloading files. |
0 |
COOKIES |
Path to a cookies.txt file (Netscape format) for accessing private or age-gated content. |
|
There are two easy ways to get your downloaded music into Jellyfin:
- Run the downloader as described in the Quick Start.
- Once finished, copy all the contents from the local
./libraryfolder into your Jellyfin music library directory. - In Jellyfin, go to Dashboard -> Libraries, click the three dots on your music library, and select Scan Library.
Jellyfin will import the music and automatically detect the .m3u8 playlists.
For a seamless experience, you can map the output directory directly to your Jellyfin music library. This way, music and playlists appear in Jellyfin automatically after the downloader runs.
-
Find the absolute path to your Jellyfin music library on your host machine (e.g.,
/storage/musicor/home/user/jellyfin/music). -
Update the
volumessection in yourcompose.ymlto point to that path:services: ymde: # ... other settings volumes: - ./data:/data - /path/to/your/jellyfin/music:/library # <-- Change this line # ... other settings
-
Run the downloader:
docker compose run --rm ymde. -
Scan your library in Jellyfin. New content will be added automatically.
This avoids any manual copying and keeps your library perfectly in sync.
This often happens when YouTube requires you to be logged in to view certain content (e.g., age-gated videos) or when a video is private or unavailable in your region.
Solution: Use a cookies.txt file. By providing cookies from your logged-in YouTube session, YMDE can access these videos just like your browser.
-
Export your cookies from your browser into a
cookies.txtfile. For detailed instructions, see the guide on how to use cookies. -
Place the
cookies.txtfile in your./data/folder. -
Uncomment and set the
COOKIESenvironment variable in yourcompose.yml:environment: # ... - COOKIES=/data/cookies.txt
You can run YMDE periodically to download new songs from your playlists. The tool automatically skips any tracks that are already in your library (even in different playlists), so it only downloads what's new.
This is a great way to maintain a long-term archive of your music. Just re-run the same command whenever you want to sync:
docker compose run --rm ymdeIf you prefer to build the Docker image locally instead of using a pre-built one from a registry:
-
Clone the repository:
git clone https://github.com/WarreTh/ymde.git cd ymdeError Checking: If you already have the repo, skip this step. If you get an error, check your internet connection or repository URL.
-
Build the image:
docker compose build
Error Checking: If you get a build error, ensure Docker is running and you are in the correct directory.
-
Run the container:
docker compose run --rm ymde
Error Checking: If you get a runtime error, check your Docker Compose file and environment variables.
This project is licensed under the AGPL-3.0 License. See the LICENSE file for details.