Android: Internet Radio App: Transistor

I’m not the one to promote android apps usually, but…
I know there’s a few fans of internet radio out here.

what works nicely on all my linux machines: * get a playlist or create a playlist from one or two streaming links * save it to some folder on your machine * open it with your favorite lightweight audio player (MOC here)

…has always been a bit of a problem on my phone:
Standard media players won’t open remote streams. Why, is beyond me. Some android/java quirk, who knows what’s going on under the hood…
Many Radio/streaming apps exist, but they all seem to insist on finding my radio stations for me, and usually default to 128kbps mp3 streams. Why, when i can get 64kbps AAC which gives equal quality with half the bandwidth? Maybe android can’t stream AAC?
This results in * buffering problems * phone going to sleep during playback * dropouts (probably intiated server-side)

Maybe this is why:
I’m using mobile broadband exclusively, because it’s a flatrate. unfortunately my phone does not have 4G, only 3G, and the throughput can be patchy. i use it while cycling, so moving from cell to cell constantly.
But it seems many apps assume that you don’t use mobile broadband, instead constantly surf wifi networks, because everybody has a mobile data plan that is already used up for this month?
…really i just don’t know. Android will never have the sort of transparency for me that gnu/linux has.

Enter Transistor:

Transistor is a bare bones app for listening to radio programs over the internet. The app stores stations as files on your device’s external storage. It currently understands streams encoded in MP3, AAC and Ogg/Opus(*).
Important note: This is an app of type BYOS (“bring your own station”). It does not feature any kind of built-in search option. You will have to manually add radio stations.
(…)
During Playback Transistor acquires a so called partial wake lock. That prevents the Android system to stop playback for power saving reasons.

what? AAC streaming? my eyes are about to pop out, my mouth is watering. why didn’t I see this earlier? It’s been around for a while. and it sounds like it’s born from a unix philosophy: plain text files and folders, not intents and databases!

Long story short, it works! Been using it for a few days with somafm’s 64kbps streams, and it’s definitely much better. no more going to sleep, almost no dropouts, and very reasonable sound quality.
Yay!

The UI is simple, usable. Just a list of stations, and once you click on one, a play/stop button. if the station supports it, it also shows currently playing song.

Small caveat: it wants .M3U playlists.

So, here’s a gratuitous little conversion script that will convert a PLS playlist to m3u and push the result to an android device of your choice:

#!/bin/bash  

# convert (somafm's) pls playlists to m3u playlists.  
# a list of files as arguments.  
# output stored in temp folder in current dir.  

me="${0##*/}"  
folder="$me$(date +%s)"  
if ! mkdir -p "$folder"; then   
    echo "Could not create output folder"  
    exit 1  
fi  
trap "rmdir $folder 2>/dev/null 1>&2" EXIT  

grep="$(which grep 2>/dev/null)"  
[[ "$grep" == "" ]] && echo "grep not found in PATH. Can't continue." && exit 1  

# for pushing .m3us to android device with adb  
# if you don't want to use this, better comment it out completely  
# because adb takes a while to fire up.  
device="XXXXXXXXXXX" # find out your device number with 'adb devices'  
pushpath="/mnt/sdcard/Android/data/org.y20k.transistor/files/Collection/"  
adb="$(which adb 2>/dev/null)"  
if [[ "$adb" == "" ]]; then  
    echo "adb not found in PATH."  
else  
    if ! $adb devices | $grep "$device"; then  
        adb=""  
        echo "adb: device $device not found."  
    fi  
fi  

for input in $@; do  
    if [ -r "$input" ] && [[ "${input,,}" = *.pls ]]; then  
        oldifs="$IFS"  
        IFS=$'\n'  
        file=( $($grep -E "File.?=" "$input") )  
        title=( $($grep -E "Title.?=" "$input") )  
        length=( $($grep -E "Length.?=" "$input") )  
        IFS="$oldifs"  

        output="$folder/${input%.*}.m3u"  
        echo "Converting $input to $output"  
        echo -e "#EXTM3U" > "$output"  
        for (( i=0 ; i<${#file[@]}; i++ )); do  
            file*="${file*#*=}"  
            # the file (url) is the most important bit - if that's missing, skip to the next array member  
            if [[ "${file*}" != "" ]]; then  
                title*="${title*#*: }"  
                title*="${title*/ (*)/}"  
                # if title is empty after cutting out some stuff, replace it with the file name (url)  
                [[ "${title*}" == "" ]] && title*="${file*#http*://}"  
                length*="${length*#*=}" # if length is empty, make it -1  
                [[ "${length*}" == "" ]] && length*="-1"  
                echo -e "#EXTINF:${length*},${title*}\n${file*}" >> "$output"  
            fi  
        done  
        [[ "$adb" != "" ]] && $adb push "$output" "$pushpath"  
    else  
        echo "File $input does not end in .pls or is not readable - skipping."  
    fi  
done  

exit 0

save to ~/bin, make executable.
if you want adb push functionality, replace the device=“XXXXXXXX” string with your device number (get it with ‘adb devices’).

Let’s say you have all somafm stations in one folder - and you want 64kbps stations only on your phone, like me - then connect your phone, and run the script like this:

pls2m3u *64.pls

let me know how it goes, i have only one phone for testing.


Sep 7th, 2017