Shell script for internet radio

2020-03-25

I’ve been feeling nostalgic for a holiday I took last year to New Mexico in the USA. We spent a lot of time listening to country radio stations and driving through the beautiful scenery. While I am confined to home I thought it would be nice to listen to those radio stations again, but I was finding it laborious to listen to the radio through my web browser.

Most internet radio streams have a URL, which can be scraped usually by looking at the HTML of the webpage, or rarely if the radio provider is feeling public spirited, in plain text on the streaming page. These URLs are mostly readable by VLC if they are .mp3, .ogg, m3u, .pls and probably many more. The backend of VLC’s streaming capabilities is an in-built plugin called Icecast, previously Shoutcast. I made a simple text file of these URLs along with the names of the stations:

https://radiostationusa.fm/apii.php?url=https://stream.revma.ihrhls.com/zc1385,Big I 107.9 Albuquerque New Country 
http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio1_mf_p,BBC Radio 1
http://a.files.bbci.co.uk/media/live/manifesto/audio/simulcast/hls/nonuk/sbr_vlow/llnw/bbc_radio_fourlw.m3u8,BBC Radio 4 LW

Then I wrote a shell script which uses fzf to neatly display the radio station names, then uses sed and grep to send the URL to the ncurses version of VLC, which on macOS at least is stored in /Applications/VLC.app/Contents/MacOS/VLC -I ncurses when VLC is installed using Homebrew.

#!/bin/sh

stations="$HOME/.radio.txt"

sel=$(sed 's/^.*,//' ${stations} | fzf)

url=$(grep "${sel}" ${stations} | sed 's/,.*$//')

vlc "${url}"

Update 2021-04-18

The BBC changed their radio streaming URLs which prompted me to also change how this script worked a bit. The radio streaming URLs are now stored in a .pls file, which makes it more compatible with other music players. I’ve included the full .pls file here because these URLs are hard to come by online:

playlist
NumberOfEntries=10

Title1=BBC Radio 4 FM
File1=http://stream.live.vc.bbcmedia.co.uk/bbc_radio_fourfm 

Title2=BBC Radio 4 LW - non UK
File2=http://stream.live.vc.bbcmedia.co.uk/bbc_radio_fourlw_online_nonuk 

Title3=BBC Radio 6
File3=http://stream.live.vc.bbcmedia.co.uk/bbc_6music 

Title4=BBC Radio London
File4=http://stream.live.vc.bbcmedia.co.uk/bbc_london  

Title5=BBC World Service
File5=http://stream.live.vc.bbcmedia.co.uk/bbc_world_service 

Title6=WQXR 
File6=http://stream.wqxr.org/wqxr 

Title7=LBC
File7=http://media-ice.musicradio.com:80/LBCNewsUK 

Title9=BBC Radio Scotland
File9=http://stream.live.vc.bbcmedia.co.uk/bbc_radio_scotland_fm 

Title10=NTS
File10=http://stream-relay-geo.ntslive.net/stream 

The script looks like this:

#!/usr/bin/env sh 

rfile=~/.radio.pls

station=$(grep '^Title' ${rfile} | sed 's/^Title\([0-9]\+\)=\(.*\)/\1 - \2/' | fzf | sed 's/\(^[0-9]\+\).*/\1/')

url=$(grep "File${station}=" $rfile | sed 's/.*=//')

/Applications/VLC.app/Contents/MacOS/VLC -I rc --no-color $url

Update 2021-06-03

I was getting annoyed having to quit out of FZF and relaunch the script every time I wanted to change the radio station, so I re-wrote it to use mpv, using the --bind flag in fzf to run a never-ending loop. I tried to do similar using VLC, but it kept quitting back to FZF immediately, rather than keeping VLC open until I wanted to quit.

#!/usr/bin/env sh

rfile=~/.radio.pls

grep '^Title' ${rfile} |\
	sed 's/^Title\([0-9]\+\)=\(.*\)/\1 - \2/' |\
	fzf --bind="enter:execute;echo {} | sed 's/\(^[0-9]\+\).*/\1/' | 
	sed 's/\(.*\)/File\1=/' |
	grep -f - ${rfile} |
	sed 's/.*=//' |
	mpv --playlist=- ;"

Update 2024-06-26

I’ve further simplified the FZF radio script. It now uses a file like this:

http://as-hls-ww-live.akamaized.net/pool_904/live/ww/bbc_radio_fourfm/bbc_radio_fourfm.isml/bbc_radio_fourfm-audio=128000.m3u8 BBC Radio 4 FM  
http://stream.wqxr.org/wqxr WQXR 
http://media-ice.musicradio.com:80/LBCNewsUK LBC
http://as-hls-ww-live.akamaized.net/pool_904/live/ww/bbc_radio_scotland_fm/bbc_radio_scotland_fm.isml/bbc_radio_scotland_fm-audio=128000.m3u8 BBC Radio Scotland
http://ice2.somafm.com/defcon-128-aac Soma FM DEF CON Radio

Where the streaming URL comes first, then everything after the first whitespace is the title of the stream.

The script looks like this:

#!/usr/bin/env sh

rfile=~/.radio.txt

sed 's/[^ ]* //' ${rfile} | 
	sort -f |
	fzf --bind="enter:execute;echo {} | 
		grep -f - ${rfile} |
		sed 's/\s.*//' |
		mpv --playlist=- ;"