Beebotron music player/recorder - openbox pipe menu
Posted: Sat Aug 31, 2013 6:56 am
This is the lastest version of a script I published on CrunchBang to access the excellent Beebotron site, get a list of all the bbc "listen again" music programmes available, filter out the stuff you don't want and make an openbox pipe menu to play your choice in radiotray (or other) or record it with ffmpeg. Comments in the file hopefully make it all clear, but feel free to ask here if something doesn't seem to make sense.
Don't forget to change the regular expression filters to match your taste in music, unless it's identical to mine...
Filters are applied to both entry names and descriptions, but only names are displayed.
Basic expression: '(string1|string2|etc)'
(watch out for long lines which might get folded here)
EDIT 130905 Added some sanity checks, thanks to Dr xaos.
Don't forget to change the regular expression filters to match your taste in music, unless it's identical to mine...
Filters are applied to both entry names and descriptions, but only names are displayed.
Basic expression: '(string1|string2|etc)'
(watch out for long lines which might get folded here)
Code: Select all
#!/bin/bash
# beebotron.sh - a script to download a list of
# recent bbc radio programmes from beebotron.org
# and generate an openbox pipe menu
# version 12/04/11 added optional top menu items
# version 13/08/31 added recording option
# version 13/09/05 added some error checks
# requires curl, awk and ffmpeg (for recording)
# Usage: add this entry:
# <menu id="beebotron" label="BBC Music Programmes" execute="/path/to/beebotron.sh" />
# to your .config/openbox/menu.xml
# The first time it is run that day the cache file will be downloaded,
# which will make the menu slow to pop out. You can avoid that by adding:
# /path/to/beebotron.sh --refresh &
# to your openbox autostart(.sh) file.
# choose player for radio (radiotray will load new urls via dbus)
player=radiotray
# choose beebotron url to use
url=http://beebotron.org/public3/genremusic.html
# Other genres are: genrechildrens, genrecomedy, genredrama, genrefactual,
# genrelearning, genrenews, genrereligethics, genresport, genreweather
# - substitute for genremusic above.
# If you live in the UK you can use the high quality links,
# which end with "hq" eg:
# url=http://beebotron.org/public3/genremusichq.html
cache_file=$HOME/.cache/beebotron_music # path to cache file
# (change name to match genre)
# RECORDING (needs ffmpeg to be installed)
recording='true' # 'true' to enable, any other value to disable recording
download_folder="$HOME/downloads/bbc" # store downloaded files here
# optional terminal to run ffmpeg in (see line 100)
terminal=urxvt # should support the -e option
#######################################
## FILTERS using regular expressions ##
# If you don't filter the list the menu will be very long.
# Entry descriptions are in the html file, but not displayed in the menu.
# Any entries (including descriptions) matching the expression
# will be put at the top of the menu and further filters will be ignored.
#top='(^My Favourite Prog Title|^This Too)'
top='(^World on 3|^World Routes|^Cerys on 6|^Don Letts|womad|WOMAD)'
# Any entries (including descriptions) matching the expression
# will be skipped.
#skip='([Bb]ach|[Bb]eethoven)'
#skip='a^' # nothing matches this
skip='(^Ace|^Beverley.*s World of Music|^Breakfast|^C2|^Chatback|^Chris Hawkins|^Composer of the Week|^Damien St|^Dress Circle|^Drivetime|^Graham Torrington|^Mornings |^Phil White|^Pipeline|^Rob da Bank|^Scott Mills |^Shaun Keaveny|^Simon Mayo |^Sue Davies|^The Early Show |^The Evening Show|^Through the Night|^Toddla T|^Tommy Sandhu)'
# Any entries (including descriptions) NOT matching the expression
# will be skipped.
keep='([Jj]azz|[Ww]orld|[Gg]lobal|[Aa]sia|[Aa]frica|[Rr]eggae|[Bb]hangra|[Bb]lues|r&b|R&B|[Rr]oots|[Ll]atin|India|Pakistan|Thai|Lao|Indonesia|Nathan Fake|Late Junction)'
##########################################################################
error_exit() {
echo "$0 error: $1" >&2
exit 1
}
[[ -t 0 ]] && {
[[ $1 = '--debug' ]] && shift || {
echo "This script is not intended to be called from a terminal.
Use the --debug option to overrule this behaviour.
Otherwise, see the comments in $0 for usage information"
exit
}
}
if [[ $recording = true ]]
then
needed_apps='curl awk ffmpeg'
else
needed_apps='curl awk'
fi
missing_apps=
for i in curl $needed_apps
do
hash $i || missing_apps+=" $i"
done
[[ $missing_apps ]] && error_exit "Some necessary packages missing: $missing_apps"
[[ $1 = "--refresh" || ! -f $cache_file || $(( $(date +%s) - $(stat -c %Z "$cache_file") )) -gt 86400 ]] && {
curl -so "$cache_file" "$url" || error_exit "failed to download list from beebotron"
}
[[ $1 = "--refresh" ]] && exit
[[ $1 = "--record" ]] && {
[[ $2 && $3 ]] || error_exit "not enough arguments for --record option"
[[ $2 =~ ^http://(www|open\.live)\.bbc\.co\.uk(/[[:alnum:]_]+)+$ ]] || error_exit "url is not valid"
prog_name="$3-$( date +%y%m%d )"
mkdir -p "$download_folder" || error_exit "unable to make $download_folder"
dl_file="$download_folder/$prog_name".wma
stream_url=$( tr [[:upper:]] [[:lower:]] <<< $( curl -s $2 || error_exit "curl failed to fetch $2" ) | awk 'BEGIN{RS="<ref href=\"";FS="\"";}NR!=2{next}{sub(/^mms/,"mmsh",$1);print $1;}' )
# remove '$terminal -e' from next line to run ffmpeg in background
$terminal -e ffmpeg -i "$stream_url" -vn -acodec copy "$dl_file"
exit
}
awk -v TOP="$top" -v SKIP="$skip" -v KEEP="$keep" -v PLAYER="$player" -v RECORDER="$0 --record" -v RECORDING="$recording" '
function submenu(name,url) {
return "\
\n <menu id=\"" name "\" label=\"" name "\">\
\n <item label=\"PLAY\">\
\n <action name=\"Execute\"><command>" PLAYER " \"" url "\"</command></action>\
\n </item>\
\n <item label=\"RECORD\">\
\n <action name=\"Execute\"><command>" RECORDER " \"" url "\" \"" name "\"</command></action>\
\n </item>\
\n </menu>"
}
function item(name,url) {
return "\
\n <item label=\"" name "\">\
\n <action name=\"Execute\"><command>" PLAYER " \"" url "\"</command></action>\
\n </item>"
}
BEGIN {
MENU=TOPMENU=""
RS="<a href=\""
FS="\">"
}
/DOCTYPE/ {next}
/http:\/\/beebotron.org/ {exit}
# $1 is the url, $2 the name+description
$2 ~ TOP {
sub(/<\/a>.*$/,"",$2)
if (RECORDING == "true") {
TOPMENU = TOPMENU submenu($2, $1)
}
else {
TOPMENU = TOPMENU item($2, $1)
}
next
}
$2 ~ SKIP {next}
$2 !~ KEEP {next}
{
sub(/<\/a>.*$/,"",$2)
if (RECORDING == "true") {
MENU = MENU submenu($2, $1)
}
else {
MENU = MENU item($2, $1)
}
}
END {print ("<openbox_pipe_menu>" TOPMENU "\n <separator/>" MENU "\n</openbox_pipe_menu>")}
' "$cache_file"
exit