From the Mind of Bob

What I think, what I hear, what I see

Capture Track Info

2022-02-22 Code Bob Ossler

SUCCESS!!! In a prior post I talked about re-discovering Internet streaming radio. I am enjoying listening to TheEL.US and I love their variety of Rock, Blues, and Metal. Their library spans decades and they play stuff you’d never hear on a corporate station.

What does this have to do with code & scripting?

Well, I use the mpv CLI tool to stream the station from a terminal. Each time the song (track) changes I get a message with the artist / title. I decided I wanted to start capturing the song info, as it’s played, to review later and get ideas for music to purchase.

I could have done a clunky, but workable, bash shell script capturing output from redirection off the command line. However, I would have to do a lot of parsing and formatting. I knew there were better, more efficient ways…

mpv has a built-in API that works with C, Lua and other languages. What I wanted was just a simple capture of tags (also called properties). I decided a full C program was overkill and too much overhead since I wasn’t doing anything other than capturing an artist name and song title. mpv also has a simple mechanism to load and run scripts while it is running. This is where Lua comes in.

I have no experience with Lua other than seeing it used as a configuration language for some other Linux/Unix tools. The syntax is similar to many other languages, so I figured I could hack something out. I started with an example script I found on GitHub.

function on_pause_change(name, value)
    if value == true then
        file = io.open("/directory/to/store/titles.txt", "a")
        file:write(mp.get_property("media-title"),"\n")
        file:close()
    end
end
mp.observe_property("pause", "bool", on_pause_change)
 
--local msg = require 'mp.msg'
--local utils = require 'mp.utils'
function dump_info()
file = io.open("/directory/to/store/titles.txt", "a")
file:write(mp.get_property("media-title"), "\n")
file:close()
end
mp.add_key_binding("n", "dump_2_txt", dump_info)
--key binding letter n on keyboard

This code will write the media-title property to a file of your choosing, anytime the mpv stream is paused or when the user presses the ’n’ key.

That’s a great start, and works well. However, it requires manual intervention for every song you wish to capture. I wanted something that would capture everything while the stream is paying. This way, if I needed to walk away from the computer or was busy with another task, the info would be captured without having to press a key. So I started trying to write my own little script that would do what I needed, and would be automatic.

It took me longer than it should have, but without a clear understanding of Lua or the mpv API, I was sort of flying blind. After several mistakes and trying to decipher error messages I was unfamiliar with, I studied a little more of the Lua basics and was able to debug and troubleshoot my code. I came up with a workable solution in a handful of lines of code. I should go back and add some comments, especially around why I chose the if/then logic I did. There are more efficient ways to write this, but it will do for now.

function on_track_change(name, value)
    local startmsg
    if value ~= nil then
        if value == "a71722" then
            startmsg = "Start of stream for "..value.." "os.date("%x")
            print("value of startmsg", startmsg)
        else
            file = io.open("/directory/to/store/tracks.txt", "a")
            file:write(value,"\n")
            file:close()
        end
    end
--    file = io.open("/directory/to/store/tracks.txt", "a")
--    file:write(value,"\n")
--    file:close()
end
mp.observe_property("media-title", "string", on_track_change)

Basically, when I start the mpv stream, the first two instances of the property are a nil value as it starts, and then the stream identifier for TheEL.US (a71722). After that, each value will be a track title of the format:

Seether - Fine Again

The mp.observe_property does all the hard work of identifying when the track changes, and then calls the on_track_change function. The function just validates the value of the string, and if valid writes it to the file. I can then use the file for any purpose I need.

It’s been a fun (sometimes frustrating) learning process, and I enjoy combining various tools to solve little problems or tasks I need done.

Caveat :: This is not a full tutorial as I have left out various details and descriptions of mpv, Lua, etc. I will add that if writing a script for mpv, it should be stored in the user’s home folder under the .config/mpv/scripts directory.