You are not logged in.

#1 2015-10-29 07:25:52

johnraff
nullglob
From: Nagoya, Japan
Registered: 2015-09-09
Posts: 5,472
Website

Shoutcast and Radionomy tuner for mplayer, mpg123 or radiotray

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(/^.*&quot;mp3&quot;: &quot;/,"",url)
        sub(/&quot;.*$/,"",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

John
--------------------
( a boring Japan blog , Japan Links, idle twitterings  and GitStuff )
In case you forget, the rules.

Offline

#2 2016-06-25 16:40:22

ohnonot
...again
Registered: 2015-09-29
Posts: 3,773
Website

Re: Shoutcast and Radionomy tuner for mplayer, mpg123 or radiotray

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 '&ampXXX;' 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(/^.*&quot;mp3&quot;: &quot;/,"",url)
        sub(/&quot;.*$/,"",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

#3 2016-06-27 09:43:59

johnraff
nullglob
From: Nagoya, Japan
Registered: 2015-09-09
Posts: 5,472
Website

Re: Shoutcast and Radionomy tuner for mplayer, mpg123 or radiotray

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.  cool


John
--------------------
( a boring Japan blog , Japan Links, idle twitterings  and GitStuff )
In case you forget, the rules.

Offline

#4 2016-06-30 05:25:16

ohnonot
...again
Registered: 2015-09-29
Posts: 3,773
Website

Re: Shoutcast and Radionomy tuner for mplayer, mpg123 or radiotray

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

Board footer

Powered by FluxBB