What we’re building

We’ll create a fully automated script that’ll pull all of the content from the streaming site(s) of your choice and feed them seamlessly into your offline music library.

Exclaimer

What we’re doing here might (or might not) violate against existing copyright/piracy laws in your country. In legal terms, you will be downloading a copy of a piece that could be protected by copyright. Here’s the austrian take on copyright.

The mere downloading of music or videos (which are copyrighted works) from the internet (i.e. without wanting to re-offer the piece of music or video itself) onto a data carrier (e.g. hard disk, DVD, CD) for private use is generally permitted. However, this presupposes that the downloaded piece of music or video, which was saved on one’s own computer, for example, is not subsequently used for commercial purposes. For example, the sale of copied or downloaded pieces of music or videos is prohibited, as this would no longer constitute private use. It is also not permitted to allow other persons to access the downloaded music or videos on the internet (e.g. via file-sharing networks).

No private copies of computer programmes may be made. However, backup copies shall be excepted insofar as this is necessary for the use of the computer programme.

Source: Austrian ministry for Education and Digital Media

To summarize this: as long as you don’t distribute the copy and only store it for private purposes (without commercial interest) you are not violating against the law! While it seems that most of european countries share the same interpetation of copyright, please verify this first (or take pre-cautions like VPNs and Proxies before you continue).

Ethical

Please also take into consideration that artists get paid a small portion per stream on most streaming sites. Especially for less-known artists, this might be the primary source of income. If you really enjoy the track please always consider supporting the artist first. Making music is lots of work and requires lots of know-how and effort and thus needs to be valued. If you are downloading the music with no intention of supporting the artists then, stop continue reading NOW and leave this page! I mean it.

Convenience of Streaming Sites

Personally, I prefer to organize my tracks in playlists. I usually sort them by Genre or by artist. So I do have quite a lot playlists on Soundcloud. And I really love SoundCloud especially for that. It allows to find new artists and songs with ease, and categorize them into Playlists and likes. That’s really something I wouldn’t like to miss out anymore. Even though I valued the old go-to-shop-and-buy-a-random-cd-approach, I prefer the streaming-site approach much more, as it is just easier to find tracks that match your favorite style.

youtube-dl

youtube-dl is a CLI application written in Python, specializing on downloading videos from the Web. youtube-dl is open source and actively developed on ytdl-org Github. While the name suggests that it’ll download from YouTube only, it really supports pretty much every site existing (including Spotify and Soundcloud. You can find a list of all supported sites here).

Installing youtube-dl

If you are on Linux distribution, Python (and pip) are most likely already installed, thus the only thing you’d need to do is install youtube-dl with pip.

# if your distribution still ships with Python 2.x make sure to use pip3 instead of pip
pip3 install youtube-dl

Downloading your first Video

Once installed on your machine it is time to test downloading your first video. The commandline interface of youtube-dl is quite straight-forward. If you just want to download the video, just invoke youtube-dl with the URL to the resource that you want to download. Here’s an example URL from YouTube.

youtube-dl https://www.youtube.com/watch?v=dQw4w9WgXcQ

This will download the video into the Current Working Directory.

Conversion to Audio

Since we are interested in music primarily we’d need to extract the Audio from the video. Luckily youtube-dl ships with support for ffmpeg out of the box. And ffmpeg will take care of extracting the music from the video. Make sure that you have installed ffmpeg on your box as well.

# On Fedora/CentOS and RHEL-based distributions
sudo dnf install ffmpeg -y
# On Ubuntu and Debian-based distributions
sudo apt install ffmpeg -y

Additionally to ffmpeg you’ll need to install lame in case you want to export your audio to the mp3 format. I’m not going to show you how to install lame as this is very distribution-dependent and mp3 is a non-free format. As soon as ffmpeg is installed we can invoke youtube-dl once again, but this time we’ll add additional triggers to the command that tell youtube-dl to extract the audio.

# Download the video with the highest-quality audio
# After download (of video) succeeded, call ffmpeg to extract audio
# Convert extracted audio to flac as output format
# Delete the downloaded video file
youtube-dl --extract-audio --format 'bestaudio' --audio-format 'flac' https://www.youtube.com/watch?v=dQw4w9WgXcQ

# Download the video with the highest-quality audio
# After download (of video) succeeded, call ffmpeg to extract audio
# Convert extracted audio to flac as output format
# Keep the downloaded video file
youtube-dl --keep-video --extract-audio --format 'bestaudio' --audio-format 'ogg' https://www.youtube.com/watch?v=dQw4w9WgXcQ
  • –extract-audio tells youtube-dl to invoke ffmpeg to extract the audio from the video it downloaded.
  • –format ‘bestaudio’ tells youtube-dl to find the video-stream (and output format) with the best audio-quality

Working with Playlists

The intention of this post, was to show you how to download playlists (or in more general terms: lists of media-resources). Luckily youtube-dl has support for this out-of-the-box. Downloading a playlist works exactly like downloading a single media element from a website. You just have additional controls.

Imagine the following playlist:

1) Abba - Dancing Quuen
2) The Prodigy - Invaders Must Die
3) Lady Gaga - Pokerface
4) Amy Winehouse - Back in Black
5) Scooter - Nessaja

with these (self-explanatory) triggres you can easily select which elements of the playlist you want to download.

  • --playlist-start (e.g. playlist-start 2 to skip Abba)
  • --playlist-end (e.g. playlist-end 4 to skip Scooter)
  • note that those commandline-triggers can be set at the same time.
  • --playlist-items (e.g. playlist-items 1,2,5 will download Abba, The Prodigyy, Scooter)
  • note that playlist-items cannot be added if either --playlist-start or --playlist-end is present

And finally, since playlists tend to grow over time, we want to youtube-dl to keep track of what it has downloaded already, and what not. With the trigger --download-archive you can specify a file that youtube-dl utilizes as database of what has already
been downloaded and can be skipped for future downloads of this playlist.

Authentication against Soundcloud

sometimes, playlists are private, or Songs are not publicly available and are behind a paywall that require you to be logged in (like a payed Soundcloud Go-subscription). Then you need to tell youtube-dl to authenticate against the Soundcloud Streaming-Servers before downloading anything.

First you need to log-in to Soundcloud, then identify the Authentication-Token that your browser sends to authenticate against the Soundcloud-Servers. On Firefox press F12 (Developer Conosole), find the Network-Tab in the Console and then refresh the site. Don’t be overwhelmed for the huge amount of requests that are made.
Firefox Developer Console, Network Inspector, Soundcloud Authentication Token

One of the responses of the server that contains the authentication-token is the me-request. The first element in the JSON-response is the authentication-token that you need.

with the trigger --add-header you can pass additional HTTP-headers to the requests to the server that youtube-dlis downloading the media from. To authenticate add the following header: --add-header 'Authorization':'OAuth <your Soundcloud Authentication Token>'.

Let’s put it all together

#!/usr/bin/env bash

TARGET_DIRECTORY='./Sync'
TARGET_FORMAT='mp3'

# Update youtube-dl everytime we start the script (recommended)
pip3 install --upgrade youtube-dl &> /dev/null

# Declare a Dictionary of Directories (where the files are downloaded to) and the upstream playlist-source
declare -A playlists=( 
    ["Austropop"]="https://soundcloud.com/djraremusic/sets/austropop"
    ["Hands Up"]="https://soundcloud.com/djraremusic/sets/haends-up"
    ["Acoustic"]="https://soundcloud.com/djraremusic/sets/acoustic"
    ["Oldskool & Classics"]="https://soundcloud.com/djraremusic/sets/nostalgisch-wie-fick"
    ["Neuro Funk"]="https://soundcloud.com/djraremusic/sets/zabrochene-schlaeg"
    ["Hardstyle"]="https://soundcloud.com/djraremusic/sets/reverse-bass-cyka"
    ["Psytrance"]="https://soundcloud.com/djraremusic/sets/psychadelic-mindfuk"
    ["Rock & Metal"]="https://soundcloud.com/djraremusic/sets/rock-metal-sammelbecken"
    ["Hardcore"]="https://soundcloud.com/djraremusic/sets/3x-normalpuls"
    ["House & Electro"]="https://soundcloud.com/djraremusic/sets/future-zeigs"
    ["House & Electro"]="https://soundcloud.com/djraremusic/sets/hoartes-house"
    ["House & Electro"]="https://soundcloud.com/djraremusic/sets/producing-schmankerl"
    ["Drum & Bass"]="https://soundcloud.com/djraremusic/sets/fluessigs-dnb"
    ["Mainstream"]="https://soundcloud.com/djraremusic/sets/mood-chill"
    ["Likes & Favs"]="https://soundcloud.com/djraremusic/likes"
)

for name in "${!playlists[@]}"; 
do 
    url=${playlists[$name]}
    mkdir -p "$TARGET_DIRECTORY/$name"
    echo "$datetime: Synchronizing $name ($url)"

    youtube-dl \
        --ignore-errors \
        --yes-playlist \
        --continue \
        --no-overwrites \
        --extract-audio \
        --audio-format "$TARGET_FORMAT" \
        --prefer-ffmpeg \
        --sleep-interval 10 \
        -f 'bestaudio' \
        --download-archive "$TARGET_DIRECTORY/$name/.downloadarchive.txt" \
        --user-agent 'Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0' \
        --add-header 'Authorization':'OAuth xxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \
        --output "$TARGET_DIRECTORY/$name/%(title)s.%(ext)s" \
        $url
done

Thank you for reading ❤

I hope you enjoyed reading this article. Maybe it was helpful, maybe it was not? Maybe you learned something new? I'd be really glad to hear your opinions. Your feedback is much appreciated, please just send a mail to bloginput@rtrace.io