らじるを聴取・録音（mpv/ffmpeg コマンド利用）

こんにちは。
NHK ラジオ番組の聴取・録音を行うシェルスクリプトを作りました。```mpv```コマンド（聴取）・```ffmpeg``` コマンド（録音）を用いることで簡素化しています。
  * これは「[らじるを録音（シェルスクリプト）](https://qiita.com/kkdd/items/7a28c23c620c18848310)」の続編です。

```console
$ ./radiru.sh --channel FM
$ ./radiru.sh --channel R1 --duration 60 --output out.mp3
```

```radiru.sh
#!/bin/sh

# default values and constants
channel="R1"
station="Tokyo"
duration=60
PROGNAME=$(basename "$0")
LF=$(printf '\n_');LF=${LF%_}
SHIFT_INCR_ERR=2
SEP_SPLIT=','
REQUIRED_COMMNNDS="mpv ffmpeg"

# functions
url_f() {
  ch="$(echo "$1" | tr '[:upper:]' '[:lower:]')"
  station="$(echo "$station" | tr '[:upper:]' '[:lower:]')"
  case "$ch" in 
    r2) c=a; id=2023501;;
    r1|fm) case "$station" in sapporo) c=i;; sendai) c=h;; tokyo) c=a;; nagoya) c=c;; osaka) c=b;;
                              hiroshima) c=f;; matsuyama) c=z;; fukuoka) c=l;; *) return 1;; esac;;
    *) return 1;;
  esac
  case "$station" in
    sapporo)   case "$ch" in r1) id=2023545;; fm) id=2023546;; esac;;
    sendai)    case "$ch" in r1) id=2023543;; fm) id=2023544;; esac;;
    tokyo)     case "$ch" in r1) id=2023229;; fm) id=2023507;; esac;;
    nagoya)    case "$ch" in r1) id=2023510;; fm) id=2023511;; esac;;
    osaka)     case "$ch" in r1) id=2023508;; fm) id=2023509;; esac;;
    hiroshima) case "$ch" in r1) id=2023512;; fm) id=2023513;; esac;;
    matsuyama) case "$ch" in r1) id=2023547;; fm) id=2023548;; esac;;
    fukuoka)   case "$ch" in r1) id=2023541;; fm) id=2023542;; esac;;
  esac
  echo "https://radio-stream.nhk.jp/hls/live/${id}/nhkradiru${c}k${ch}/master48k.m3u8"
}
# derived from https://www.nhk.or.jp/radio/config/config_web.xml

exit_f() {
  printf "%s\n" "$1"
  exit
}

split_f() { echo "$1" | tr $SEP_SPLIT ' '; }

param_shift_f() {
  shift_incr=0  # default
  arg_param="$2"
  for flag in $(split_f "$1 ="); do arg_param=${arg_param#"$flag"}; done
  if [ -z "$arg_param" ]; then
    arg_param="$3"; shift_incr=1
    case "$arg_param" in -*|"") shift_incr=$SHIFT_INCR_ERR ;; esac  # failed
  fi
  split_f "$arg_param"
  return $shift_incr  # exit status
}


# messages
WARNING="Warning: Type \"$PROGNAME -h|--help\" for usage instructions."

USAGE=$LF$(cat <<- EOS
  Name: $PROGNAME$LF
  Description: play radio lively (or record if an output file specified)$LF
  Usage: $PROGNAME [options]$LF
  Options:
    -c|--channel R1|R2|FM   (default $channel)
    -s|--station Sapporo|Sendai|Tokyo|Nagoya|Osaka|Hiroshima|Matsuyama|Fukuoka  (default $station)
    -o|--output  __file__.mp3
    -d|--duration __period__    (default $duration)
    -h|--help $LF
  Required: $REQUIRED_COMMNNDS
	EOS
)$LF

# parsing optional arguments
while [ $# -gt 0 ]; do
  case "$1" in
    -c*|--channel*)  channel=$(param_shift_f -c,--channel "$@") ;;
    -s*|--station*)  station=$(param_shift_f -s,--station "$@") ;;
    -o*|--output*)   output_file=$(param_shift_f -o,--output "$@") ;;
    -d*|--duration*) duration=$(param_shift_f -d,--duration "$@") ;;
    -h|--help )  exit_f "$USAGE";;
    -* ) exit_f "$WARNING" ;;
    * )  break ;;
  esac
  shift_incr=$?; [ $shift_incr -lt $SHIFT_INCR_ERR ] || exit_f "$WARNING"
  shift $((shift_incr+1))
done

# main
url="$(url_f "$channel")" || exit_f "$WARNING"
if [ -z "$output_file" ]; then
  mpv --really-quiet "$url" || echo "error in mpv" 1>&2
else
  ffmpeg -y -v 0 -i "$url" -t "$duration" "$output_file" || echo "error in ffmpeg" 1>&2
fi
```