Skip to content

Instantly share code, notes, and snippets.

@febuiles
Last active July 1, 2022 03:45
Show Gist options
  • Star 52 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save febuiles/1549991 to your computer and use it in GitHub Desktop.
Save febuiles/1549991 to your computer and use it in GitHub Desktop.
Fetching lyrics in Unix

Fetching lyrics in the command line

Objective: Print the lyrics for the current playing song.

How: We'll create a small bash script to do the fetching for us (using curl) and then we'll display it either in the terminal or in our $EDITOR

Get the current song

First we'll need to get the name of the current song and its artist:

Mac

iTunes (Mountain Lion+):

osascript -e'tell application "iTunes"' -e'get artist of current track' -e'end tell'
osascript -e'tell application "iTunes"' -e'get name of current track' -e'end tell'

iTunes (Lion and older):

arch -i386 osascript -e'tell application "iTunes"' -e'get artist of current track' -e'end tell'
arch -i386 osascript -e'tell application "iTunes"' -e'get name of current track' -e'end tell'

GNU/Linux and others

Rythmbox:

rhythmbox-client --print-playing-format %ta
rhythmbox-client --print-playing-format %tt

MPD:

mpc -f %artist% | head -n 1
mpc -f %title% | head -n 1

Banshee:

# you can find a full Banshee script in the comments section.
banshee --query-artist
banshee --query-title

Spotify:

# you can find a full Spotify script for GNU/Linux in the comments section

In Amarok you might be able to do something like this:

qdbus org.mpris.amarok /Player GetMetadata
# match the artist and title lines

Get the lyrics

Change depending on your editor:

#!/bin/bash
artist=`osascript -e'tell application "iTunes"' -e'get artist of current track' -e'end tell'`
title=`osascript -e'tell application "iTunes"' -e'get name of current track' -e'end tell'`

curl does the fetching for us:

curl -s --get "https://makeitpersonal.co/lyrics" --data-urlencode "artist=$artist" --data-urlencode "title=$title"

Sample script

I use something like this on macOS:

#!/bin/bash
artist=`osascript -e'tell application "iTunes"' -e'get artist of current track' -e'end tell'`
title=`osascript -e'tell application "iTunes"' -e'get name of current track' -e'end tell'`
song=`curl -s --get "https://makeitpersonal.co/lyrics" --data-urlencode "artist=$artist" --data-urlencode "title=$title"`

echo -e "$artist - $title\n$song"

To try it just save, chmod it and make sure something's playing to try it out:

chmod +x lyrics
./lyrics

If all goes well you should see the lyrics on your screen after a second or two.

Formatting

If you want a cleaner output for the lyrics you can pass the song results to less and print it with a bit of formatting (please try it!):

echo -e "$artist_name - $song_title\n$song" | less -FX

Here we are adding an "Artist - Song" header and displaying the results as they were meant to be seen!

Emacs

[![This banner could use some help...](https://stallman.org/graphics/saint-button.png)](https://stallman.org/saint.html)

If you want the output in a *Lyrics* buffer you can add a small function to your Emacs config:

(defun lyrics()
  "Prints the lyrics for the current song"
  (interactive)
  ;; replace path below with your own.
  (let ((song (shell-command-to-string "/usr/local/bin/lyrics"))) 
  (if (equal song "")
    (message "No lyrics - Opening browser.")
  (switch-to-buffer (create-file-buffer "Lyrics"))
  (insert song)
  (goto-line 0))))

M-x lyrics and you're done.

Credits

  • @taborj: MPD instructions and less -FX.
  • @arsinux: Banshee script.
  • @Glutanimate: --data-urlencode for curl and Spotify for GNU/Linux script.
@moonwave99
Copy link

Well done mate, nice to have.

@taborj
Copy link

taborj commented Feb 1, 2013

Thanks for this, it's perfect!

I did a slight modification or two, though. I'm using MPD, so I first pulled the artist and title using the following (which I put into some variables, $artist and $title):

mpc -f %artist% | head -n 1
mpc -f %title% | head -n 1

The other issue I ran into was curl on OpenBSD did not translate spaces in the artist or title into %20, so my URL didn't work. Solution? Use wget:

wget -qO- "http://makeitpersonal.co/lyrics?artist=$artist&title=$title"

@taborj
Copy link

taborj commented Feb 1, 2013

Also, one other thing to note. If you use the -FX flag on less, the output is much friendlier. The -F flag will terminate less if the output fits on one page (saving you from having to exit out of less), and the -X flag will stop less from sending the termcap initialization and deinitialization strings, which can cause things like clearing the screen when less is exited.

@febuiles
Copy link
Author

@taborj: thanks for the less trick and the MPD instructions. I hope you don't mind me adding them to the gist.

@arsinux
Copy link

arsinux commented Dec 8, 2014

Script for Banshee music player
function lyrics {
artist=$(banshee --query-artist)
artist=${artist:8}
title=$(banshee --query-title)
title=${title:7}
artist=$(perl -MURI::Escape -e 'print uri_escape($ARGV[0]);' "$artist")
title=$(perl -MURI::Escape -e 'print uri_escape($ARGV[0]);' "$title")
curl -s "http://makeitpersonal.co/lyrics?artist=$artist&title=$title"
}

@glutanimate
Copy link

Thanks for posting this tutorial! It has been very useful.

A couple of remarks:

  • curl actually has URL encoding built in. You just have to do a GET request and supply the artist and title fields with the --data-urlencode option, e.g.:

    LyricsAPI="http://makeitpersonal.co/lyrics/"
    curl -s --get "$LyricsAPI" --data-urlencode "artist=${TrackArtist}" --data-urlencode "title=${TrackTitle}"  
  • Here's a an implementation of the script for Spotify on Linux:

    #!/bin/bash
    
    SP_DEST="org.mpris.MediaPlayer2.spotify"
    SP_PATH="/org/mpris/MediaPlayer2"
    SP_MEMB="org.mpris.MediaPlayer2.Player"
    
    LyricsAPI="http://makeitpersonal.co/lyrics/"
    
    SPOTIFY_METADATA="$(dbus-send                                                 \
        --print-reply                                  `# We need the reply.`       \
        --dest=$SP_DEST                                                             \
        $SP_PATH                                                                    \
        org.freedesktop.DBus.Properties.Get                                         \
        string:"$SP_MEMB" string:'Metadata'                                         \
        | grep -Ev "^method"                           `# Ignore the first line.`   \
        | grep -Eo '("(.*)")|(\b[0-9][a-zA-Z0-9.]*\b)' `# Filter interesting fiels.`\
        | sed -E '2~2 a|'                              `# Mark odd fields.`         \
        | tr -d '\n'                                   `# Remove all newlines.`     \
        | sed -E 's/\|/\n/g'                           `# Restore newlines.`        \
        | sed -E 's/(xesam:)|(mpris:)//'               `# Remove ns prefixes.`      \
        | sed -E 's/^"//'                              `# Strip leading...`         \
        | sed -E 's/"$//'                              `# ...and trailing quotes.`  \
        | sed -E 's/\"+/|/'                             `# Regard "" as seperator.`  \
        | sed -E 's/ +/ /g'                            `# Merge consecutive spaces.`\
      )"
    
    TrackArtist=$(echo "$SPOTIFY_METADATA" | sed -n 's/artist|//p')
    TrackTitle=$(echo "$SPOTIFY_METADATA" | sed -n 's/title|//p')
    
    curl -s --get "$LyricsAPI" --data-urlencode "artist=${TrackArtist}" --data-urlencode "title=${TrackTitle}"

@arnellebalane
Copy link

@glutanimate that is exactly what I needed! that is so awesome thank you so much! 💯

@nick-parry
Copy link

I whipped up this to grab the currently playing song and fetch the lyrics.
https://github.com/nick-parry/songLyrics

This way I can be lazy and just run: songLyrics spotify to get the lyrics. It will try 3 different sites before giving up. Just some random hacker ware, but I like it. :)

@calbertts
Copy link

Awesome!

@glensc
Copy link

glensc commented Jan 21, 2018

i got inspired from this script and wrote my own that does:

  1. use id3 lyrics tag if available
  2. fetch from net, update id3 tag if was missing

https://github.com/glensc/mpd-lyrics

@victorbnl
Copy link

Instead of all those different commands for each player, why not just use playerctl metadata title and playerctl metadata artist?

@apprehensions
Copy link

i believe @glutanimate made it without knowing that playerctl was a thing, it would be much much much MUCH MUCH MUUUCH smaller if it to be using playerctl.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment