EDIT 140911 Please see V3.0 here:
http://linuxbbq.org/bbs/viewtopic.php?f ... 725#p30725 which deals with the new Shoutcast interface, and has a couple of other minor tweaks.
Ah... it took a bit longer than a day or two.
In the process of setting up remote control of mpg123 and mplayer I was obliged to dig down into processes, forking, pipes, signals...
OK the new version is amazingly bloated (don't look Rho The Bloathound) because it has code for radiotray, mpg123 and mplayer built in, selected by changing a config variable at the top. This makes the file longer, but not really slower because most of the code gets ignored. A lot of checking is done to try and make sure it's not too easy to break, but please report back if you hit a problem. In particular, I haven't run this on Sid so as usual ymmv. (I don't know if some of the code might be re-usable in a general purpose bbq radio app.)
It should be easy enough to add code for mpd or moc since they seem to support remote access too, but I'll leave that as a task for those who want to use those players.
Replace the top section of the script down to line 145 with your plugin, making sure you supply the
required_commands variable and
start_player,
radioplay and
cleanup functions. Look at what's there now to get the idea.
Anyway default
player is mpg123 - nice and fast - and default behaviour is
keep_player=true so you can close the script and terminal and the music will continue. Rerun the script if you want to change the station or shut down the player. Record the stream with streamripper if you want.
KEYBOARD SHORTCUTS:
Ctrl+C to exit normally
Ctrl+\ to terminate and close player
Ctrl+Z to start recording current station (usurps SIGTSTP)
Anyway, try it out if you have a free moment, anyone. Hope you like it :)
Code: Select all
#!/bin/bash
# shoutcast_radionomy_search.sh
# search shoutcast and radionomy,
# send url to radiotray, mpg123, mplayer or another player
# send url to streamripper to record
#
# needs curl, [radiotray, dbus | mpg123 | mplayer], streamripper, [xsel]
# xsel enables pasting from the X selection (to a config file etc.)
# Comment out line 246 "printf '%s'..." if you don't use it.
#
# KEYBOARD SHORTCUTS:
# Ctrl+C to exit normally
# Ctrl+\ to terminate and close player
# Ctrl+Z to start recording current station (handles SIGTSTP)
##### choose from radiotray, mpg123 or mplayer #####
player=mpg123
# Set this to something other than 'true'
# to have audio player exit with script.
# Otherwise player will continue till closed separately.
# Even with 'keep_player=true', if script is stopped with Ctrl+\
# then player will exit too.
keep_player=true
##### code to record a radio stream (url is $1) in a new terminal #####
# Add your own options to streamripper's command line,
# edit ~/.config/streamripper/streamripper.ini,
# change urxvt to another terminal
# or use a different command altogether.
recorder() {
( setsid urxvt -e streamripper "$1" >/dev/null 2>&1 & )
}
# where to put player control fifo
# (radiotray doesn't use this)
rpipe=/tmp/radio_pipe
##########################################################################
case $player in
##### RADIOTRAY SETTINGS #####
radiotray)
required_commands='curl streamripper radiotray'
start_player() {
if pgrep radiotray >/dev/null
then
echo "$player is already running"
else
( radiotray >/dev/null 2>&1 & )
fi
}
radioplay() {
radiotray $1
}
cleanup() { # run just before exit
[[ $player_ok = true ]] && [[ $keep_player = true ]] && {
echo "$player will continue to play.
You can control it from the system tray icon
or run the script again to choose another station."
sleep 4
return
}
pkill radiotray && echo "Closed radiotray."
}
;;
##### END RADIOTRAY #####
##### MPLAYER SETTINGS #####
mplayer)
required_commands='curl streamripper mplayer'
player_regex="^mplayer .*-input file=$rpipe"
launch_player() {
[[ -p $rpipe ]] || { mkfifo "$rpipe" || error_exit "cannot make fifo $rpipe"; }
( setsid sh -c "mplayer -really-quiet -idle -slave -input file=$rpipe; rm -f $rpipe;" >/dev/null 2>&1 & )
sleep 4 & launching_player=$!
}
load_url() {
echo "loadlist $1" >"$rpipe"
}
;;&
##### END MPLAYER #####
##### MPG123 SETTINGS #####
mpg123)
required_commands='curl streamripper mpg123'
player_regex="^mpg123 .*--fifo $rpipe"
launch_player() { # mpg123 will make fifo if necessary
( setsid sh -c "mpg123 --remote --fifo $rpipe; rm -f $rpipe;" >/dev/null 2>&1 & )
(sleep 2; echo 'silence' >"$rpipe") & launching_player=$!
}
load_url() {
echo "loadlist 1 $1" >"$rpipe"
}
;;&
##### END MPG123 #####
##### COMMON TO MPLAYER AND MPG123 #####
mplayer|mpg123)
start_player() {
if pgrep -f "$player_regex" >/dev/null
then
echo "$player is already running"
[[ -p $rpipe ]] || error_exit "fifo missing $rpipe"
(:>"$rpipe") & test_pipe=$!
(sleep 2; kill $test_pipe 2>/dev/null && kill -s SIGPIPE $selfpid) &
else
launch_player
fi
}
radioplay() {
wait $launching_player
[[ -p $rpipe ]] || error_exit "fifo missing $rpipe"
pgrep -f "$player_regex" >/dev/null || error_exit "$player not running"
load_url "$1"
}
cleanup() { # run just before exit
[[ -p $rpipe ]] || { player_ok=false; echo "Script error: fifo $rpipe does not exist." >&2 ;}
pgrep -f "$player_regex" >/dev/null || { player_ok=false; echo "Script error: $player not running" >&2 ;}
[[ $player_ok = true ]] && {
[[ $keep_player = true ]] && {
echo "$player will continue to play.
You can stop it with the command:
echo quit >$rpipe
or run the script again to choose another station."
sleep 4
return
}
echo "closing $player..."
echo 'quit' >"$rpipe" # try to close player nicely
sleep 2 # time for player to quit
}
pkill -f "$player_regex" && echo "$player close forced."
echo "removing $rpipe"
rm -f "$rpipe" # in case it has become a normal file
}
;;
##### END COMMON TO MPLAYER AND MPG123 #####
*)
echo "$0: chosen player $player has not been configured.
Please check line 17 of the script" >&2
exit 1
;;
esac
##########################################################################
selfpid=$$
player_ok=true
error_exit() {
echo "Script error: $1" >&2
player_ok=false
exit 1
}
trap 'cleanup' EXIT
trap 'echo " Exit script
Goodbye..."; exit' SIGHUP SIGINT
trap 'echo " Exit script
($player will be shut down)
Goodbye..."; keep_player=false; exit' SIGQUIT
trap 'error_exit "script terminated"' SIGTERM
trap 'error_exit "broken pipe"' SIGPIPE
trap 'recorder "${playing_url%.m3u}"' SIGTSTP
missing_commands=
for i in $required_commands
do
hash $i || missing_commands+=" $i"
done
[[ $missing_commands ]] && error_exit "This script requires the following commands: $missing_commands
Please install the packages containing the missing commands
and rerun the script."
start_player
unset playing_name playing_url
while true
do
echo "Please enter keyword(s)"
read keyword
keyword="${keyword// /%20}" # escape spaces for url
results_sh=$( curl -s "http://www.shoutcast.com/Internet-Radio/$keyword" |awk '
BEGIN {
RS="<div class=\"dirlist\">"
FS=">"
}
NR < 2 {next}
{url = name = $2
sub(/^.*title=\"/,"",name)
sub(/\".*$/,"",name)
sub(/^.*href=\"/,"",url)
sub(/\".*$/,"",url)
print url,name }
' )
results_ra=$( curl -s "http://www.radionomy.com/en/search?q=$keyword" |awk '
BEGIN {
RS="<h2 class=\"radio-title-list\"><a href=\"/en/radio/"
FS="</a></h2>"
}
NR < 2 {next}
{url = name = $1
sub(/^.*>/,"",name)
sub(/\/index\".*$/,"",url)
url="http://listen.radionomy.com/" url ".m3u"
print url,name }
' )
if [[ $results_sh ]] && [[ $results_ra ]]
then
results="$results_sh"$'\n'"$results_ra"
elif [[ $results_sh ]]
then
echo "No results for $keyword on radionomy"
results="$results_sh"
elif [[ $results_ra ]]
then
echo "No results for $keyword on shoutcast"
results="$results_ra"
else
echo "Sorry, no results for $keyword"
continue
fi
unset list
declare -A list # make associative array
while read -r url name # read in awk's output
do
list["$name"]="$url"
done <<< "$results"
PS3='Please enter the number of your choice > '
while true
do
menu=("${!list[@]}")
[[ $playing_name && $playing_url ]] && menu+=("RECORD \"$playing_name\"")
select station in "${menu[@]}" 'SEARCH AGAIN' QUIT
do
[[ $station = "RECORD \"$playing_name\"" ]] && {
recorder "${playing_url%.m3u}" # streamripper won't take m3u urls
break
}
[[ $station = 'SEARCH AGAIN' ]] && break 2
[[ $station = QUIT ]] && { echo 'Goodbye...'; exit; }
[[ $station ]] && {
# comment out next line if you don't use xsel
printf '%s' "${list[$station]}" | xsel --input #--clipboard # can paste url
radioplay "${list[$station]}"
playing_name=$station
playing_url=${list[$station]}
break
}
done
echo "
Station last chosen was \"$playing_name\" ( $playing_url )
"
done
done # closes loop started at line 178
exit
EDIT Added setsid to launch command for mpg123. At first I thought it wasn't necessary, but it seems for some versions at least, like mplayer, it needs that extra layer of insulation from the launching shell's signals. setsid makes a very forked off process - it even continues after you log out!
EDIT 121015 Couple of minor tweaks to UI and comments.
All code is one.