#!/usr/bin/env bash
# terminalradio - pick a station and play it with mpv.
set -euo pipefail

command -v mpv >/dev/null || { echo "terminalradio needs mpv"; exit 1; }

# Other stations: name|url
extra=(
  "101.ru Smooth Jazz|http://pub0201.101.ru:8000/stream/trust/mp3/128/31"
  "101.ru Jazz|http://pub0201.101.ru:8000/stream/trust/mp3/128/264"
  "FIP Jazz|https://icecast.radiofrance.fr/fipjazz-midfi.mp3"
  "Jazz Radio WR04|https://jazz-wr04.ice.infomaniak.ch/jazz-wr04-128.mp3"
  "Sepia Jazz|http://stream.sepia.sk/jazz128.mp3"
  "FluxFM Electronic Chillout|https://channels.fluxfm.de/electronic-chillout/externalembedflxhp/stream.mp3"
  "FluxFM Chillout Radio|https://channels.fluxfm.de/chillout-radio/externalembedflxhp/stream.mp3"
  "Hirschmilch Chillout|http://xfer.hirschmilch.de:8000/chillout.mp3"
  "Ambient Sleeping Pill 256|http://radio.stereoscenic.com/asp-h"
  "Stereoscenic AMA 256|http://radio.stereoscenic.com/ama-h"
  "Ambient Modern 256|http://radio.stereoscenic.com/mod-h"
  "Cryosleep|http://streams.echoesofbluemars.org:8000/cryosleep"
  "Dinamo Sleep|http://channels.dinamo.fm/sleep-mp3"
  "Radio Art - Ambient Piano|http://air.radioart.com/fAmbient_piano.mp3"
  "Costa del Mar - Zen|http://stream.cdm-zen.com:8004/stream-mp3-Zen"
  "Nightride FM - Chillsynth|https://stream.nightride.fm/chillsynth.mp3"
  "Total Instrumental|http://stream.laut.fm/total-instrumental"
  "Beautiful Instrumentals|http://s3.voscast.com:10038/"
  "RMNinstrumental|http://stream.instrumentalhits.de:8060/"
  "Radio Art - Piano & Guitar|http://air-tunein.radioart.com/fPiano_and_guitar.mp3"
  "Clam Radio - Piano & Guitar|http://streams.calmradio.com:30228/"
  "Chillout Piano|https://stream.epic-piano.com/chillout-piano?ref=terminalradio"
  "Romantic Piano|https://stream.epic-piano.com/romantic-piano?ref=terminalradio"
  "Chopin|https://stream.epic-piano.com/chopin?ref=terminalradio"
  "Classical Pan Flute|https://stream.epic-classical.com/classical-pan-flute?ref=terminalradio"
  "Your Classical - Relax|http://relax.stream.publicradio.org/relax.mp3"
  "Instrumentals Forever|http://quincy.torontocast.com:1910/stream"
  "1000 Melodien|http://stream.laut.fm/1000melodien"
)

# SomaFM stations: "title|id|url|format|url|format|..."
# Snapshot of https://somafm.com/channels.json, sorted by title.
soma=(
  "Beat Blender|beatblender|https://api.somafm.com/beatblender.pls|mp3|https://api.somafm.com/beatblender130.pls|aac|https://api.somafm.com/beatblender64.pls|aacp|https://api.somafm.com/beatblender32.pls|aacp"
  "Black Rock FM|brfm|https://api.somafm.com/brfm.pls|mp3|https://api.somafm.com/brfm130.pls|aac|https://api.somafm.com/brfm64.pls|aacp|https://api.somafm.com/brfm32.pls|aacp"
  "Boot Liquor|bootliquor|https://api.somafm.com/bootliquor320.pls|mp3|https://api.somafm.com/bootliquor130.pls|aac|https://api.somafm.com/bootliquor64.pls|aacp|https://api.somafm.com/bootliquor32.pls|aacp"
  "Bossa Beyond|bossa|https://api.somafm.com/bossa256.pls|mp3|https://api.somafm.com/bossa130.pls|aac|https://api.somafm.com/bossa64.pls|aacp|https://api.somafm.com/bossa32.pls|aacp"
  "Chillits Radio|chillits|https://api.somafm.com/chillits256.pls|mp3|https://api.somafm.com/chillits130.pls|aac|https://api.somafm.com/chillits64.pls|aacp|https://api.somafm.com/chillits32.pls|aacp"
  "Christmas Lounge|christmas|https://api.somafm.com/christmas256.pls|mp3|https://api.somafm.com/christmas130.pls|aac|https://api.somafm.com/christmas64.pls|aacp|https://api.somafm.com/christmas32.pls|aacp"
  "Christmas Rocks!|xmasrocks|https://api.somafm.com/xmasrocks.pls|mp3|https://api.somafm.com/xmasrocks130.pls|aac|https://api.somafm.com/xmasrocks64.pls|aacp|https://api.somafm.com/xmasrocks32.pls|aacp"
  "cliqhop idm|cliqhop|https://api.somafm.com/cliqhop256.pls|mp3|https://api.somafm.com/cliqhop130.pls|aac|https://api.somafm.com/cliqhop64.pls|aacp|https://api.somafm.com/cliqhop32.pls|aacp"
  "Covers|covers|https://api.somafm.com/covers.pls|mp3|https://api.somafm.com/covers130.pls|aac|https://api.somafm.com/covers64.pls|aacp|https://api.somafm.com/covers32.pls|aacp"
  "Deep Space One|deepspaceone|https://api.somafm.com/deepspaceone.pls|mp3|https://api.somafm.com/deepspaceone130.pls|aac|https://api.somafm.com/deepspaceone64.pls|aacp|https://api.somafm.com/deepspaceone32.pls|aacp"
  "DEF CON Radio|defcon|https://api.somafm.com/defcon256.pls|mp3|https://api.somafm.com/defcon130.pls|aac|https://api.somafm.com/defcon64.pls|aacp|https://api.somafm.com/defcon32.pls|aacp"
  "Department Store Christmas|deptstore|https://api.somafm.com/deptstore256.pls|mp3|https://api.somafm.com/deptstore130.pls|aac|https://api.somafm.com/deptstore64.pls|aacp|https://api.somafm.com/deptstore32.pls|aacp"
  "Digitalis|digitalis|https://api.somafm.com/digitalis256.pls|mp3|https://api.somafm.com/digitalis130.pls|aac|https://api.somafm.com/digitalis64.pls|aacp|https://api.somafm.com/digitalis32.pls|aacp"
  "Doomed|doomed|https://api.somafm.com/doomed256.pls|mp3|https://api.somafm.com/doomed130.pls|aac|https://api.somafm.com/doomed64.pls|aacp|https://api.somafm.com/doomed32.pls|aacp"
  "Drone Zone|dronezone|https://api.somafm.com/dronezone256.pls|mp3|https://api.somafm.com/dronezone130.pls|aac|https://api.somafm.com/dronezone64.pls|aacp|https://api.somafm.com/dronezone32.pls|aacp"
  "Drone Zone 2|dz2|https://api.somafm.com/dz2.pls|mp3|https://api.somafm.com/dz2130.pls|aac|https://api.somafm.com/dz264.pls|aacp|https://api.somafm.com/dz232.pls|aacp"
  "Dub Step Beyond|dubstep|https://api.somafm.com/dubstep256.pls|mp3|https://api.somafm.com/dubstep130.pls|aac|https://api.somafm.com/dubstep64.pls|aacp|https://api.somafm.com/dubstep32.pls|aacp"
  "Fluid|fluid|https://api.somafm.com/fluid.pls|mp3|https://api.somafm.com/fluid130.pls|aac|https://api.somafm.com/fluid64.pls|aacp|https://api.somafm.com/fluid32.pls|aacp"
  "Folk Forward|folkfwd|https://api.somafm.com/folkfwd.pls|mp3|https://api.somafm.com/folkfwd130.pls|aac|https://api.somafm.com/folkfwd64.pls|aacp|https://api.somafm.com/folkfwd32.pls|aacp"
  "Groove Salad|groovesalad|https://api.somafm.com/groovesalad256.pls|mp3|https://api.somafm.com/groovesalad130.pls|aac|https://api.somafm.com/groovesalad64.pls|aacp|https://api.somafm.com/groovesalad32.pls|aacp"
  "Groove Salad 2|groovesalad2|https://api.somafm.com/groovesalad2256.pls|mp3|https://api.somafm.com/groovesalad2130.pls|aac|https://api.somafm.com/groovesalad264.pls|aacp|https://api.somafm.com/groovesalad232.pls|aacp"
  "Groove Salad Classic|gsclassic|https://api.somafm.com/gsclassic.pls|mp3|https://api.somafm.com/gsclassic130.pls|aac|https://api.somafm.com/gsclassic64.pls|aacp|https://api.somafm.com/gsclassic32.pls|aacp"
  "Heavyweight Reggae|reggae|https://api.somafm.com/reggae256.pls|mp3|https://api.somafm.com/reggae130.pls|aac|https://api.somafm.com/reggae80.pls|aacp|https://api.somafm.com/reggae32.pls|aacp"
  "Illinois Street Lounge|illstreet|https://api.somafm.com/illstreet.pls|mp3|https://api.somafm.com/illstreet130.pls|aac|https://api.somafm.com/illstreet64.pls|aacp|https://api.somafm.com/illstreet32.pls|aacp"
  "Indie Pop Rocks!|indiepop|https://api.somafm.com/indiepop.pls|mp3|https://api.somafm.com/indiepop130.pls|aac|https://api.somafm.com/indiepop64.pls|aacp|https://api.somafm.com/indiepop32.pls|aacp"
  "Jolly Ol' Soul|jollysoul|https://api.somafm.com/jollysoul.pls|mp3|https://api.somafm.com/jollysoul130.pls|aac|https://api.somafm.com/jollysoul64.pls|aacp|https://api.somafm.com/jollysoul32.pls|aacp"
  "Left Coast 70s|seventies|https://api.somafm.com/seventies320.pls|mp3|https://api.somafm.com/seventies130.pls|aac|https://api.somafm.com/seventies64.pls|aacp|https://api.somafm.com/seventies32.pls|aacp"
  "Lush|lush|https://api.somafm.com/lush.pls|mp3|https://api.somafm.com/lush130.pls|aac|https://api.somafm.com/lush64.pls|aacp|https://api.somafm.com/lush32.pls|aacp"
  "Metal Detector|metal|https://api.somafm.com/metal.pls|mp3|https://api.somafm.com/metal130.pls|aac|https://api.somafm.com/metal64.pls|aacp|https://api.somafm.com/metal32.pls|aacp"
  "Mission Control|missioncontrol|https://api.somafm.com/missioncontrol.pls|mp3|https://api.somafm.com/missioncontrol130.pls|aac|https://api.somafm.com/missioncontrol64.pls|aacp|https://api.somafm.com/missioncontrol32.pls|aacp"
  "n5MD Radio|n5md|https://api.somafm.com/n5md.pls|mp3|https://api.somafm.com/n5md130.pls|aac|https://api.somafm.com/n5md64.pls|aacp|https://api.somafm.com/n5md32.pls|aacp"
  "PopTron|poptron|https://api.somafm.com/poptron.pls|mp3|https://api.somafm.com/poptron130.pls|aac|https://api.somafm.com/poptron64.pls|aacp|https://api.somafm.com/poptron32.pls|aacp"
  "Secret Agent|secretagent|https://api.somafm.com/secretagent.pls|mp3|https://api.somafm.com/secretagent130.pls|aac|https://api.somafm.com/secretagent64.pls|aacp|https://api.somafm.com/secretagent32.pls|aacp"
  "Seven Inch Soul|7soul|https://api.somafm.com/7soul.pls|mp3|https://api.somafm.com/7soul130.pls|aac|https://api.somafm.com/7soul64.pls|aacp|https://api.somafm.com/7soul32.pls|aacp"
  "SF 10-33|sf1033|https://api.somafm.com/sf1033.pls|mp3|https://api.somafm.com/sf1033130.pls|aac|https://api.somafm.com/sf103364.pls|aacp|https://api.somafm.com/sf103332.pls|aacp"
  "SF in SF|sfinsf|https://api.somafm.com/sfinsf.pls|mp3|https://api.somafm.com/sfinsf130.pls|aac|https://api.somafm.com/sfinsf64.pls|aacp|https://api.somafm.com/sfinsf32.pls|aacp"
  "SF Police Scanner|scanner|https://api.somafm.com/scanner.pls|mp3|https://api.somafm.com/scanner130.pls|aac|https://api.somafm.com/scanner64.pls|aacp|https://api.somafm.com/scanner32.pls|aacp"
  "SomaFM Live|live|https://api.somafm.com/live.pls|mp3|https://api.somafm.com/live130.pls|aac|https://api.somafm.com/live64.pls|aacp|https://api.somafm.com/live32.pls|aacp"
  "SomaFM Specials|specials|https://api.somafm.com/specials.pls|mp3|https://api.somafm.com/specials130.pls|aac|https://api.somafm.com/specials64.pls|aacp|https://api.somafm.com/specials32.pls|aacp"
  "Sonic Universe|sonicuniverse|https://api.somafm.com/sonicuniverse256.pls|mp3|https://api.somafm.com/sonicuniverse130.pls|aac|https://api.somafm.com/sonicuniverse64.pls|aacp|https://api.somafm.com/sonicuniverse32.pls|aacp"
  "Space Station Soma|spacestation|https://api.somafm.com/spacestation320.pls|mp3|https://api.somafm.com/spacestation130.pls|aac|https://api.somafm.com/spacestation64.pls|aacp|https://api.somafm.com/spacestation32.pls|aacp"
  "Suburbs of Goa|suburbsofgoa|https://api.somafm.com/suburbsofgoa.pls|mp3|https://api.somafm.com/suburbsofgoa130.pls|aac|https://api.somafm.com/suburbsofgoa64.pls|aacp|https://api.somafm.com/suburbsofgoa32.pls|aacp"
  "Synphaera Radio|synphaera|https://api.somafm.com/synphaera256.pls|mp3|https://api.somafm.com/synphaera130.pls|aac|https://api.somafm.com/synphaera64.pls|aacp|https://api.somafm.com/synphaera32.pls|aacp"
  "The Dark Zone|darkzone|https://api.somafm.com/darkzone256.pls|mp3|https://api.somafm.com/darkzone130.pls|aac|https://api.somafm.com/darkzone64.pls|aacp|https://api.somafm.com/darkzone32.pls|aacp"
  "The In-Sound|insound|https://api.somafm.com/insound256.pls|mp3|https://api.somafm.com/insound130.pls|aac|https://api.somafm.com/insound64.pls|aacp|https://api.somafm.com/insound32.pls|aacp"
  "The Trip|thetrip|https://api.somafm.com/thetrip.pls|mp3|https://api.somafm.com/thetrip130.pls|aac|https://api.somafm.com/thetrip64.pls|aacp|https://api.somafm.com/thetrip32.pls|aacp"
  "ThistleRadio|thistle|https://api.somafm.com/thistle.pls|mp3|https://api.somafm.com/thistle130.pls|aac|https://api.somafm.com/thistle64.pls|aacp|https://api.somafm.com/thistle32.pls|aacp"
  "Tiki Time|tikitime|https://api.somafm.com/tikitime256.pls|mp3|https://api.somafm.com/tikitime130.pls|aac|https://api.somafm.com/tikitime64.pls|aacp|https://api.somafm.com/tikitime32.pls|aacp"
  "Underground 80s|u80s|https://api.somafm.com/u80s256.pls|mp3|https://api.somafm.com/u80s130.pls|aac|https://api.somafm.com/u80s64.pls|aacp|https://api.somafm.com/u80s32.pls|aacp"
  "Vaporwaves|vaporwaves|https://api.somafm.com/vaporwaves.pls|mp3|https://api.somafm.com/vaporwaves130.pls|aac|https://api.somafm.com/vaporwaves64.pls|aacp|https://api.somafm.com/vaporwaves32.pls|aacp"
  "Xmas in Frisko|xmasinfrisko|https://api.somafm.com/xmasinfrisko.pls|mp3|https://api.somafm.com/xmasinfrisko130.pls|aac|https://api.somafm.com/xmasinfrisko64.pls|aacp|https://api.somafm.com/xmasinfrisko32.pls|aacp"
)

total=$(( ${#soma[@]} + ${#extra[@]} ))

echo
echo "SomaFM"
for i in "${!soma[@]}"; do
  printf '%3d  %s\n' "$((i + 1))" "${soma[$i]%%|*}"
done

echo
echo "Other stations"
for i in "${!extra[@]}"; do
  printf '%3d  %s\n' "$(( ${#soma[@]} + i + 1 ))" "${extra[$i]%%|*}"
done

echo
read -rp "Station [1-$total, q]: " pick || exit 0
[[ $pick == q ]] && exit 0
[[ $pick =~ ^[0-9]+$ ]] || { echo "Enter a number." >&2; exit 1; }
pick=$((10#$pick))
(( pick >= 1 && pick <= total )) || { echo "Out of range." >&2; exit 1; }

if (( pick > ${#soma[@]} )); then
  entry=${extra[$((pick - ${#soma[@]} - 1))]}
  name=${entry%%|*}
  url=${entry#*|}
  echo "Playing: $name"
  exec mpv --no-video \
    --audio-buffer=8 \
    --pipewire-buffer=2000 \
    --pulse-buffer=2000 \
    --cache=yes \
    "$url"
fi

entry=${soma[$((pick - 1))]}
title=${entry%%|*}
rest=${entry#*|}
IFS='|' read -ra fields <<< "$rest"
id=${fields[0]}
streams=$(( (${#fields[@]} - 1) / 2 ))
(( streams )) || { echo "No streams for $title." >&2; exit 1; }

echo
echo "$title"
for (( i = 1; i < ${#fields[@]}; i += 2 )); do
  url=${fields[$i]}
  fmt=${fields[$((i + 1))]}
  label=${url##*/}
  label=${label%.pls}
  label=${label#"$id"}
  label=${label:-128}
  if (( label == 130 )); then
    label=128
  fi
  if [[ $label =~ ^[0-9]+$ ]]; then
    label="$label kbps"
  fi
  printf '%3d  %s (%s)\n' "$(((i + 1) / 2))" "$label" "$fmt"
done

read -rp "Quality [1-$streams, q]: " q || exit 0
[[ $q == q ]] && exit 0
[[ $q =~ ^[0-9]+$ ]] || { echo "Enter a number." >&2; exit 1; }
q=$((10#$q))
(( q >= 1 && q <= streams )) || { echo "Out of range." >&2; exit 1; }

url=${fields[$((1 + (q - 1) * 2))]}
fmt=${fields[$((2 + (q - 1) * 2))]}
echo "Playing: $title"
exec mpv --no-video \
  --audio-buffer=8 \
  --pipewire-buffer=2000 \
  --pulse-buffer=2000 \
  --cache=yes \
  "$url"
