Replacing YouTube as a Music Player
2020-11-10
I listen to a lot of music and most of the time I'm not playing whole albums, but chain songs that fit my current mood. I started out creating those chains by clicking through suggestions on YouTube, but I disliked that mostly because the suggestions didn't always fit my expectations, I don't want Google to analyze my listening patterns and I want full access to my suggestions data. Thus I created some tools and scripts which alleviate those problems and enable me to manage my music completely from the terminal as a bonus.
A Quick Overview of My Setup
Nowadays I'm just typing sng
into my terminal to get
suggestions for songs to listen to and select one via fzf
.
It then gets downloaded from YouTube, if necessary, and starts playing
in mpd
.
If the song played for 20 seconds, it is automatically registered that I
listened to it using songmem
.
After listening to some songs, songmem
will have learned
which songs I often listen to consecutively and sng
will be
able to make better suggestions.
With this setup, YouTube will only see me listening to the song the
first time.
After that the song is stored on my computer, automatically tagged and
added to my mpd
music library.
This not only keeps Google from seeing my listening patterns, but also
saves network bandwidth, decreases latency, let's me listen to the
songs offline and gives me the possibility to add those songs to my
mpd
queue.
Prerequisites
The following tools will be used in the sections below. Check out these links, if you are unfamiliar with them:
- youtube-dl: Tool for downloading videos from YouTube.
- fzf: A UNIX filter used to select one song out of many suggestions. You could also use dmenu instead.
- ffmpeg: A video and audio conversion tool used for tagging.
- ytools: Tools I wrote to interact with YouTube in scipts.
- songmem: Tool I wrote to analyze listening patterns.
- mpd and an mpd client. I use mpq.
Searching and Downloading Songs from YouTube
I search YouTube from the command line with ytools
and
download songs with youtube-dl
.
After downloading I tag the songs with their artist and title using
ffmpeg
.
I use this script for searching, downloading and tagging a song all in
one; let's call it yt-audio-backup
:
#!/usr/bin/env sh # Use like: yt-audio-backup 'Daft Punk - Face to Face' set -e cd ~/Music/youtube-backups song=$@ song_slug=$(printf '%s\n' "$song" | sed 's|[ /]|_|g') artist=$(printf '%s' "$song" | awk -F ' - ' '{print $1}') title=$(printf '%s' "$song" | awk '{i=index($0, " - "); print substr($0, i+3)}') ytools-search "$song" && \ echo -n 'Selection [1]: ' read selection test -z "$selection" && selection=1 youtube-dl \ -f "bestaudio/best" \ -x \ -o "${song_slug}_%(id)s.%(ext)s" \ "$(ytools-pick "$selection")" file=$(find . -name "${song_slug}*" | head -n1) ffmpeg -i "$file" \ -acodec copy \ -metadata artist="$artist" \ -metadata title="$title" \ "tmp_youtube-dl_output.${file##*.}" mv "tmp_youtube-dl_output.${file##*.}" "$file"
Now you could run mpc --wait rescan
and use the newly
downloaded song from your mpq client.
Automatically Recording Listening Patterns
Now that songs can easily be backed up from YouTube and added to the
mpd
music library, I can use songmem
to
automatically register every song I listen to in mpd
.
Simply run this script after you logged into your computer and
mpd
is started:
#!/usr/bin/env sh while song=$(mpc -f '%artist% - %title%' current --wait) do # Kill background processes from previous loops: pkill -P "$$" # Register a hearing of the started song, # if it is still playing after 20s: sleep 20 \ && mpc status | grep -q 'playing' \ && songmem --register "$song" & done
Introducing sng
Now that I can easily download songs and record my listening patterns,
I want to have an easy way to find suggestions for songs to listen to,
download them automatically if necessary and start playing them in
mpq
. To do this I use a script I call "sng
":
#!/usr/bin/env sh set -e alias fzf='fzf --no-sort --prompt "Search on YouTube: "' last_song=$(songmem | head -n1) selection=$(songmem --suggestions "$last_song" | fzf) artist=$(printf '%s' "$selection" | awk -F ' - ' '{print $1}') title=$(printf '%s' "$selection" | awk '{i=index($0, " - "); print substr($0, i+3)}') file=$(mpc search artist "$artist" title "$title") if [ -z "$file" ] then printf 'Need to download from YouTube first:\n' yt-audio-backup "$selection" mpc --wait rescan file=$(mpc search artist "$artist" title "$title") fi mpc clear mpc add "$file" mpc play
You could add other features to this script, like registering you just
heard a song without playing it, listing most heard songs instead
of suggestions or searching for recommendations on YouTube using
ytools-recommend
.
Exploring New Music
When I just listened to a new song, I can add it to my collection
by executing something like songmem -r 'Röyksopp - Keyboard
Milk'
.
The next time I play this song through sng
it will be
downloaded and added to my music library.