You are not logged in.
I'm starting migrate some of my stuff over from #!, and recommend others to do the same, just in case...
Anyway, this was written in 2011 but it still works (needed some tweaking as web interfaces changed). It's a cli interactive script that sends queries to the shoutcast and radionomy directories and makes a list for you to choose a station, which is then played in mplayer, mpg123 or radiotray. radiotray is the easiest and most likely to play the stream, mpg123 is the fastest, but I often use mplayer too...
I'm thinking of adding a live365 module some time.
Just tested on Jessie, I found mplayer uncooperative but substituting mplayer2 fixed things. It's fine on Wheezy but I haven't yet looked in to what's wrong with 3:1.1.1+20150226+svn37375-dmo4 from deb-multimedia. I think you'd better go with mplayer2. (or radiotray or mpg123 of course)
Another, I failed (on Jessie) to get either terminator or xfce4-terminal to send a SIGQUIT with Ctrl+\ but urxvt was OK. On Wheezy xfce4-terminal was OK, but lxterminal was not. Again urxvt (which I generally use) was OK. It's not a big deal, but these signals let you control the script a little bit directly from the keyboard. If anyone can shed any light on different terminals' handling of signals, please do so!
Anyway, from --help:
"This is an interactive script to query the Shoutcast and Radionomy listings,
put the results in a menu,
and load the chosen radio station in radiotray, mpg123 or mplayer.
There is also an option to record with streamripper.
If you exit the script and leave mpg123 or mplayer running,
you can close either of them with the command:
echo quit >/tmp/radio_pipe
KEYBOARD SHORTCUTS:
Ctrl+C to exit normally
Ctrl+\ to terminate and close player (handles SIGQUIT)
Ctrl+Z to start recording current station (handles SIGTSTP)"
The chosen player runs completely independently in the background, not occupying a terminal or (if mplayer or mpg123) a systray icon - it is controlled via a pipe, and can continue playing after the script has closed. The script was developed over a period of time so it's a bit gnarly looking, but generally works quite well.
#!/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
#
# version 3.3
#
# Needs curl, [radiotray, dbus | mpg123 | mplayer], [streamripper], [xsel], [perl]
# If streamripper is omitted recording will not work.
#
# xsel enables pasting from the X selection (to a config file etc.)
# Comment out line 294 "printf '%s'..." if you don't use it.
#
# perl is used to urlencode the query.
# Comment out line 252 and uncomment line 251 to escape spaces only
# if your system doesn't have perl.
#
# KEYBOARD SHORTCUTS:
# Ctrl+C to exit normally
# Ctrl+\ to terminate and close player (may not work on all terminals)
# Ctrl+Z to start recording current station (handles SIGTSTP)
##### choose from radiotray, mpg123 or mplayer #####
#player=radiotray
#player=mpg123
player=mplayer
# 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
HELP="This is an interactive script to query the Shoutcast and Radionomy listings,
put the results in a menu,
and load the chosen radio station in radiotray, mpg123 or mplayer.
There is also an option to record with streamripper.
If you exit the script and leave mpg123 or mplayer running,
you can close either of them with the command:
echo quit >$rpipe
KEYBOARD SHORTCUTS:
Ctrl+C to exit normally
Ctrl+\ to terminate and close player (handles SIGQUIT)
Ctrl+Z to start recording current station (handles SIGTSTP)"
##########################################################################
case $1 in
--help|-h)
echo "$HELP"
exit
;;
esac
case $player in
##### RADIOTRAY SETTINGS #####
radiotray)
required_commands='curl radiotray'
start_player() {
if pgrep radiotray >/dev/null
then
echo "$player is already running"
else
( setsid 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."
sleep 4
}
;;
##### END RADIOTRAY #####
##### MPLAYER SETTINGS #####
mplayer)
required_commands='curl 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 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 24 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."
query_shoutcast() {
curl -s --data "query=$1" "http://www.shoutcast.com/Search/UpdateSearch" | awk '
BEGIN {
RS="},{"
}
{
url = name = $0
if($0=="[]") {exit}
sub(/^.*\"ID\":/,"",url)
sub(/,.*$/,"",url)
url = "http://yp.shoutcast.com/sbin/tunein-station.pls?id=" url
sub(/^.*\"Name\":\"/,"",name)
sub(/\".*$/,"",name)
print url,name
}
'
}
query_radionomy() {
curl -sL "http://www.radionomy.com/en/search/index?query=$1" |awk '
BEGIN {
RS="class=\"browseRadioWrap\">"
FS="<div class=\"radioPlay\">"
}
NR < 2 {next}
{
name = $1
sub(/^.*class=\"radioName\">/,"",name)
sub(/<\/p>.*$/,"",name)
url = $2
sub(/^.*"mp3": "/,"",url)
sub(/".*$/,"",url)
print url,name
}
'
}
start_player
unset playing_name playing_url
while true
do
echo "Please enter keyword(s)"
read keyword
#keyword_esc="${keyword// /%20}" # escape spaces for url
keyword_esc=$(perl -MURI::Escape -e 'print uri_escape($ARGV[0]);' "$keyword")
results_sh=$( query_shoutcast "$keyword_esc" )
results_ra=$( query_radionomy "$keyword_esc" )
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 ]] && hash streamripper >/dev/null 2>&1 && 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
exit
...elevator in the Brain Hotel, broken down but just as well...
( a boring Japan blog (currently paused), now on Bluesky, there's also some GitStuff )
Offline
thanks again for this!
i just spent a little time searching for existing radio utilities, but they all seem to come with a predefined list of stations, so they don't search for stations. which is pretty much useless imho.
the more happy to have this one still working.
i added support for mocp, and an option to append the currently playing url to a list of favorites.
i also added 2 clear screen commands, because it makes it easier to keep an eye on the sometimes rather long menu; it's a matter of taste i guess. they're in the last few lines of the script.
i also added a little extra to update the terminal title with the name of the currently playing station, and another little extra to convert some stray '&XXX;' entities to normal ascii, with recode. it checks if recode is in $PATH, so nothing will break if it isn't.
i'd be happy if you want to incorporate some of that.
#!/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
#
# version 3.3
#
# Needs curl, [radiotray, dbus | mpg123 | mplayer], [streamripper], [xsel], [perl]
# If streamripper is omitted recording will not work.
#
# xsel enables pasting from the X selection (to a config file etc.)
# Comment out line 294 "printf '%s'..." if you don't use it.
#
# perl is used to urlencode the query.
# Comment out line 252 and uncomment line 251 to escape spaces only
# if your system doesn't have perl.
#
# KEYBOARD SHORTCUTS:
# Ctrl+C to exit normally
# Ctrl+\ to terminate and close player (may not work on all terminals)
# Ctrl+Z to start recording current station (handles SIGTSTP)
favorites="$HOME/music/playlists/shoutcastmplay-favorites.m3u"
##### choose from radiotray, mpg123, mocp or mplayer #####
#player=radiotray
#player=mpg123
player=mocp
#player=mplayer
# 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=false
##### 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
HELP="This is an interactive script to query the Shoutcast and Radionomy listings,
put the results in a menu,
and load the chosen radio station in radiotray, mpg123 or mplayer.
There is also an option to record with streamripper.
If you exit the script and leave mpg123 or mplayer running,
you can close either of them with the command:
echo quit >$rpipe
KEYBOARD SHORTCUTS:
Ctrl+C to exit normally
Ctrl+\ to terminate and close player (handles SIGQUIT)
Ctrl+Z to start recording current station (handles SIGTSTP)"
##########################################################################
case $1 in
--help|-h)
echo "$HELP"
exit
;;
esac
# shoutcast seems to return playlists, not playable urls.
# in some cases we need to extract a playable url from that.
url_not_list() {
if [[ "$1" == *shoutcast*'.pls?id='* ]] ; then
x="$(wget --quiet -O - "$1" | grep 'File1=')"
echo "${x##*=}"
else
echo "$1"
fi
}
case $player in
##### RADIOTRAY SETTINGS #####
mocp)
radioplay() {
mocp -s; mocp -c; mocp -q "$(url_not_list "$1")"; mocp -p
}
cleanup() {
[[ $player_ok = true ]] && [[ $keep_player = true ]] && return
mocp -x
}
start_player() {
pidof mocp >/dev/null 2>&1 || mocp -S >/dev/null 2>&1
}
;;
radiotray)
required_commands='curl radiotray'
start_player() {
if pgrep radiotray >/dev/null
then
echo "$player is already running"
else
( setsid 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."
sleep 4
}
;;
##### END RADIOTRAY #####
##### MPLAYER SETTINGS #####
mplayer)
required_commands='curl 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 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 24 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."
query_shoutcast() {
curl -s --data "query=$1" "http://www.shoutcast.com/Search/UpdateSearch" | awk '
BEGIN {
RS="},{"
}
{
url = name = $0
if($0=="[]") {exit}
sub(/^.*\"ID\":/,"",url)
sub(/,.*$/,"",url)
url = "http://yp.shoutcast.com/sbin/tunein-station.pls?id=" url
sub(/^.*\"Name\":\"/,"",name)
sub(/\".*$/,"",name)
print url,name
}
'
}
query_radionomy() {
curl -sL "http://www.radionomy.com/en/search/index?query=$1" |awk '
BEGIN {
RS="class=\"browseRadioWrap\">"
FS="<div class=\"radioPlay\">"
}
NR < 2 {next}
{
name = $1
sub(/^.*class=\"radioName\">/,"",name)
sub(/<\/p>.*$/,"",name)
url = $2
sub(/^.*"mp3": "/,"",url)
sub(/".*$/,"",url)
print url,name
}
'
}
start_player
unset playing_name playing_url
while true
do
echo "Please enter keyword(s)"
read keyword
#keyword_esc="${keyword// /%20}" # escape spaces for url
keyword_esc=$(perl -MURI::Escape -e 'print uri_escape($ARGV[0]);' "$keyword")
results_sh=$( query_shoutcast "$keyword_esc" )
results_ra=$( query_radionomy "$keyword_esc" )
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
which recode >/dev/null 2>&1 && name="$(recode html..ascii <<<"$name")"
list["$name"]="$url"
done <<< "$results"
PS3='Please enter the number of your choice > '
while true
do
menu=("${!list[@]}")
[[ $playing_name && $playing_url ]] && hash streamripper >/dev/null 2>&1 && menu+=("RECORD \"$playing_name\"" "ADD \"$playing_name\" TO $favorites")
select station in "${menu[@]}" 'SEARCH AGAIN' QUIT
do
[[ $station = "RECORD \"$playing_name\"" ]] && {
recorder "${playing_url%.m3u}" # streamripper won't take m3u urls
break
}
[[ $station = "ADD \"$playing_name\" TO $favorites" ]] && {
x="$(url_not_list "$playing_url")"
grep "$x" "$favorites" || echo "$x" >> "$favorites"
unset x
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
clear
echo -e "Station last chosen was \"$playing_name\" ( $playing_url )\033]2;$playing_name\007\n"
done
clear
done
exit
Offline
Hi ohnonot many thanks for your contribution. Those ideas all look good, and I'll try them out and probably add them to the script.
...elevator in the Brain Hotel, broken down but just as well...
( a boring Japan blog (currently paused), now on Bluesky, there's also some GitStuff )
Offline
I think the "Add current station to playlist" functionality still needs some work.
a) a better mechanism to distinguish whether the link is an url or a playlist
b) adding the name of the station, not just the url
i'll look into it eventually, but not soon (family holiday trip coming up).
but so far the script has been working well for me, i've been using it daily to discover good stations (and all the crap that is floating around the 'net).
Offline