Created
June 11, 2025 09:42
-
-
Save nmasse-itix/aeb5671f02ad3ba54885fa8f95ca3df8 to your computer and use it in GitHub Desktop.
Download a Music Playlist from YouTube
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -Eeuo pipefail | |
if [ $# -ne 1 ]; then | |
echo "Usage: $0 https://youtube.com/playlist?list=..." | |
exit 1 | |
fi | |
PLAYLIST_URL="$1" | |
declare -a YTDLP_PARAMS=( | |
# Select the MP4 Audio format (m4a) to prevent re-encoding | |
-f m4a/bestaudio | |
# Extract audio track | |
-x | |
# Embed metadata and thumbnail | |
--embed-thumbnail | |
--embed-metadata | |
# The YouTube chain becomes the artist name | |
--parse-metadata "%(uploader|)s:%(artist)s" | |
# If the artist name is in the title extract only the song name | |
--parse-metadata "title:([^-–.,::]+ ?[-–.,::] )?(?P<title>.*)" | |
# Cleanup title | |
--replace-in-metadata "title" "( -)? ?[([](([Tt]he )?[Oo]fficial.*|OFFICIAL.*|([Cc]lip )?[Oo]fficiel.*|Remastered|[Vv]ideo)[)\]]" "" | |
--replace-in-metadata "title" " ?[-|] ?(Officiel|Warner Vault)$" "" | |
--replace-in-metadata "title" " ?[([]HD[)\]] ?" "" | |
# Remove common prefixes in artist name | |
--replace-in-metadata "artist" "^([Oo]fficial) ?" "" | |
# Cleanup artist | |
--replace-in-metadata "artist" " ?[(]?[Oo]fficial.*[)]?" "" | |
# Remove common suffixes in artist name | |
--replace-in-metadata "artist" "(officialVEVO|VEVO| ?- Topic|Music|TV| ?Channel)$" "" | |
# Add spaces in a CamelCase word (ie. CamelCase => Camel Case) | |
--replace-in-metadata "artist" "KoRn" "Korn" # Exception | |
--replace-in-metadata "artist" "P!NK" "Pink" # Exception | |
--replace-in-metadata "artist" "([a-z])([A-Z]+[a-z])" "\\1 \\2" | |
# Sanitize the title and artist name (remove path component separators) | |
--replace-in-metadata "title,artist" "[/\\\\]" "-" | |
# Output file name | |
--output "%(artist)s - %(title)s.%(ext)s" | |
# Throttling parameters | |
--sleep-requests 1 | |
--min-sleep-interval 2 | |
--max-sleep-interval 5 | |
# Partial download | |
#--playlist-start 1 | |
#--playlist-end 10 | |
) | |
# Download the complete playlist | |
yt-dlp "${YTDLP_PARAMS[@]}" --yes-playlist "$PLAYLIST_URL" | |
PLAYLIST_FILE="playlist.m3u" | |
PLAYLIST_NAME="YouTube Playlist" | |
# M3U Header | |
cat > "$PLAYLIST_FILE" <<EOF | |
#EXTM3U | |
#EXTENC:UTF-8 | |
#PLAYLIST:$PLAYLIST_NAME | |
EOF | |
# Generate M3U file content | |
for file in *.m4a; do | |
duration="$(mp4info "$file" |sed -r 's/^.* ([0-9]+).[0-9]+ secs.*/\1/;t;d')" | |
basename="$(basename "$file" .m4a)" | |
cat >> "$PLAYLIST_FILE" <<EOF | |
#EXTINF:$duration,$basename | |
$file | |
EOF | |
done | |
# Convert M3U to CRLF line ends to have a wider compatibility | |
todos "$PLAYLIST_FILE" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment