#!/usr/bin/env bash
#
# roon - frontend script to issue commands to Roon via the Python Roon API
#
#  Copyright 2021-2024, Ronald Joe Record
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
#
# shellcheck disable=SC1090,SC2001,SC2002,SC2016,SC2006,SC2086,SC2181,SC2129,SC2059,SC2076,SC2029,SC2207
#
# Edit these two settings if necessary
#
#   Both of these should have been set correctly during
#   installation of the RoonCommandLine package. Manual
#   setting of these variables is uncommon and only necessary
#   if the Python Roon API is installed on another system
#
#   The IP address of the system on which the Python Roon API is installed
#
server="XX.X.X.XXX"
#
#   The username with public key authorized SSH access to the system on
#   which the Python Roon API is installed
#
user="SSH_USERNAME"

# Set defaults
album= artist= composer= comm= albumlist= artistlist= artalbumlist=
albtracklist= arttracklist= composerlist= comalbumlist= dest_zone= from_zone=
exalbum= exartist= genrelist= genartistlist= genalbumlist= playlistlist=
radiolist= taglist= playlist= radio= relative= search= setdefs= noexit=
showusage=1 showexamples=1 tag= track= volume= zone= zonegroup= zonelist=
# Check for installed tools
have_brew=$(type -p brew)
have_fzf=$(type -p fzf)
have_jq=$(type -p jq)
have_rich=$(type -p rich)
have_tui=$(type -p roon-tui)
have_flat=$(type -p flatpak)

# Download URLs
fzf_url="https://raw.githubusercontent.com/junegunn/fzf/master/install"
rcl_url="https://raw.githubusercontent.com/doctorfree/RoonCommandLine"

usage() {
  [ "${showusage}" ] && {
    if [ "${have_rich}" ]; then
      rich "[bold]Usage:[/] [bold italic green]roon[/] [cyan]-A[/] [yellow]album[/] [cyan]-a[/] [yellow]artist[/] [cyan]-bB -C[/] [yellow]composer[/] [cyan]-D[/] [yellow]destination zone[/] [cyan]-m -n -N -O[/]" --print
      rich "    [cyan]-F[/] [yellow]\[from zone][/] [cyan]-f[/] [yellow]\[on|onlog|off|status][/] [cyan]-g[/] [yellow]genre[/] [cyan]-G[/] [yellow]zone_group[/] [cyan]-i[/]" --print
      rich "    [cyan]-I -l[/] [yellow]\[albums|artists|artalbums|albtracks|arttracks|composers|comalbums|[/]" --print
      rich "        [yellow]genres|genalbums|genartists|playlists|playtracks|tags|zones][/]" --print
      rich "    [cyan]-c[/] [yellow]\[discover|group|ungroup|play|play_all|pause|pause_all|stop|stop_all|[/]" --print
      rich "        [yellow]next|previous|shuffle|unshuffle|repeat|unrepeat|mute|mute_all][/]" --print
      rich "    [cyan]-s[/] [yellow]search[/] [cyan]-p[/] [yellow]playlist[/] [cyan]-T[/] [yellow]track[/] [cyan]-t[/] [yellow]tag[/] [cyan]-z[/] [yellow]zone[/] [cyan]-L[/] [cyan]-S[/] [cyan]-r[/] [yellow]radio[/]" --print
      rich "    [cyan]-X[/] [yellow]ex_album[/] [cyan]-x[/] [yellow]ex_artist[/] [cyan]\[-EuU][/]" --print
      rich "[bold]Where:[/]" --print
      rich "    [cyan]-A[/] [yellow]album[/] selects an album to play" --print
      rich "    [cyan]-a[/] [yellow]artist[/] selects an artist to list/play" --print
      rich "    [cyan]-B[/] installs the Roon Community GUI" --print
      rich "    [cyan]-b[/] opens the Roon Community GUI" --print
      rich "    [cyan]-C[/] [yellow]composer[/] selects a composer to play" --print
      rich "    [cyan]-D[/] [yellow]destination zone[/] specifies the zone to transfer current queue to" --print
      rich "    [cyan]-F[/] [yellow]from zone[/] specifies the zone to transfer from (default: last played)" --print
      rich "    [cyan]-g[/] [yellow]genre[/] selects a genre to list/play" --print
      rich "    [cyan]-i[/] displays zone information (combine with '[cyan]-z[/] [yellow]zone[/]' for extended" --print
      rich "        info on a specified zone, otherwise display info on all zones)" --print
      rich "    [cyan]-I[/] installs the [green]Roon TUI[/] terminal user interface for Roon and exits" --print
      rich "    [cyan]-f[/] [yellow]\[on|onlog|off|status][/] enables/disables fading/logging in specified zone" --print
      rich "        '[yellow]on[/]' enables fading, '[yellow]onlog[/]' fading and logging, '[yellow]off[/]' disables fading" --print
      rich "        (combine with '[cyan]-z[/] [yellow]zone[/]' for 'fading' in that zone)" --print
      rich "    [cyan]-m[/] indicates show the RoonCommandLine menu" --print
      rich "    [cyan]-n[/] displays 'now playing' information for zones actively playing" --print
      rich "    [cyan]-N[/] displays 'now playing' information for all zones" --print
      rich "        (combine with '[cyan]-z[/] [yellow]zone[/]' for 'now playing' in only that zone)" --print
      rich "    [cyan]-O[/] opens [green]Roon TUI[/] terminal user interface for Roon if available" --print
      rich "    [cyan]-p[/] [yellow]playlist[/] selects a playlist to play" --print
      rich "    [cyan]-G[/] [yellow]zone_group[/] specifies a zone grouping specified in roon_api.ini" --print
      rich "    [cyan]-L[/] setup roon to execute local commands rather than remote via SSH" --print
      rich "    [cyan]-S[/] Set Roon defaults in roon_api.ini" --print
      rich "    [cyan]-l[/] [yellow]\[albums|artists|artalbums|albtracks|arttracks|composers|comalbums|[/]" --print
      rich "        [yellow]genres|genalbums|genartists|playlists|playtracks|tags|zones][/]" --print
      rich "            indicates list [italic]albums, artists, albums by artist,[/]" --print
      rich "            [italic]composers, albums by composers, genres, albums in genre,[/]" --print
      rich "            [italic]artists in genre, playlists, tags,[/] or Roon [italic]zones[/]" --print
      rich "    [cyan]-r[/] [yellow]radio[/] selects a live radio stream to play" --print
      rich "    [cyan]-s[/] [yellow]search[/] specifies a term to search for in the lists retrieved with [cyan]-l[/]" --print
      rich "    [cyan]-T[/] [yellow]track[/] specifies a track to play" --print
      rich "    [cyan]-t[/] [yellow]tag[/] selects an tag to play" --print
      rich "    [cyan]-z[/] [yellow]zone[/] selects the Roon Zone in which to play" --print
      rich "    [cyan]-c[/] [yellow]\[discover|group|ungroup|play|play_all|pause|pause_all|playpause|stop|stop_all|[/]" --print
      rich "        [yellow]next|previous|shuffle|unshuffle|repeat|unrepeat|mute|mute_all][/]" --print
      rich "            issues the command in the selected zone" --print
      rich "            '[italic green]roon -c mute[/]' toggles the zone's muted or unmuted state" --print
      rich "            '[italic green]roon -c mute_all[/]' toggles all zones' muted or unmuted state" --print
      rich "            '[italic green]roon -c pause_all[/]' pauses playback in all zones" --print
      rich "            '[italic green]roon -c play_all[/]' begins playback in all zones" --print
      rich "            '[italic green]roon -c stop_all[/]' stops playback in all zones and releases devices" --print
      rich "            '[italic green]roon -c shuffle[/]' enables the zone's shuffled setting" --print
      rich "            '[italic green]roon -c unshuffle[/]' disables the zone's shuffled setting" --print
      rich "            '[italic green]roon -c repeat[/]' enables the zone's looping setting" --print
      rich "            '[italic green]roon -c unrepeat[/]' disables the zone's looping setting" --print
      rich "    [cyan]-v[/] [yellow]volume[/] sets the volume level in the selected zone" --print
      rich "        The volume argument has the format [yellow]\[g:]\[r:]\[s:]num[/]" --print
      rich "        Where '[yellow]g[/]' indicates set volume for all zones in the group" --print
      rich "        '[yellow]r[/]' specifies use relative method volume setting" --print
      rich "        '[yellow]s[/]' specifies use relative_step method volume setting" --print
      rich "        '[yellow]num[/]' can be absolute, relative, and negative or positive" --print
      rich "    [cyan]-X[/] [yellow]ex_album[/] specifies a string to exclude from album/genre names" --print
      rich "    [cyan]-x[/] [yellow]ex_artist[/] specifies a string to exclude from artist/composer/playlist names" --print
      rich "    [cyan]-u[/] displays a full usage message with examples" --print
      rich "    [cyan]-U[/] displays a usage message without examples" --print
      rich "    [cyan]-E[/] displays examples with no usage message" --print
      rich "Combine '[cyan]-a[/] [yellow]artist[/]' and '[cyan]-A[/] [yellow]album[/]' to play an album by a specified artist" --print
      rich "Combine '[cyan]-a[/] [yellow]artist[/]' and '[cyan]-T[/] [yellow]track[/]' to play a track by a specified artist" --print
      rich "Combine '[cyan]-a[/] [yellow]artist[/]' or '[cyan]-A[/] [yellow]album[/]' with '[cyan]-g[/] [yellow]genre[/]' to play an artist or album in a specified genre" --print
      printf "\n"
      rich "Special search term [bold italic magenta]__all__[/] matches all entries" --print
      rich "Special name [bold italic green]default[/] plays the default setting in roon_api.ini" --print
    else
      printf "\nUsage: roon -A album -a artist -C composer -D destination zone -m -n -N -O"
      printf "\n\t-F [from zone] -f [on|onlog|off|status] -g genre -G zone_group -i"
      printf "\n\t-I -l [albums|artists|artalbums|albtracks|arttracks|composers|comalbums|"
      printf "\n\t    genres|genalbums|genartists|playlists|playtracks|tags|zones]"
      printf "\n\t-c [discover|group|ungroup|play|play_all|pause|pause_all|stop|stop_all|"
      printf "\n\t    next|previous|shuffle|unshuffle|repeat|unrepeat|mute|mute_all]"
      printf "\n\t-s search -p playlist -T track -t tag -z zone -L -S -r radio"
      printf "\n\t-X ex_album -x ex_artist [-EuU]"
      printf "\nWhere:\n\t-A album selects an album to play"
      printf "\n\t-a artist selects an artist to list/play"
      printf "\n\t-B installs the Roon Community GUI"
      printf "\n\t-b opens the Roon Community GUI"
      printf "\n\t-C composer selects a composer to play"
      printf "\n\t-D 'destination zone' specifies the zone to transfer current queue to"
      printf "\n\t-F 'from zone' specifies the zone to transfer from (default: last played)"
      printf "\n\t-g genre selects a genre to list/play"
      printf "\n\t-i displays zone information (combine with '-z zone' for extended"
      printf "\n\t\tinfo on a specified zone, otherwise display info on all zones)"
      printf "\n\t-I installs the Roon TUI terminal user interface for Roon and exits"
      printf "\n\t-f [on|onlog|off|status] enables/disables fading/logging in specified zone"
      printf "\n\t\t'on' enables fading, 'onlog' fading and logging, 'off' disables fading"
      printf "\n\t\t(combine with '-z zone' for 'fading' in that zone)"
      printf "\n\t-m indicates show the RoonCommandLine menu"
      printf "\n\t-n displays 'now playing' information for zones actively playing"
      printf "\n\t-N displays 'now playing' information for all zones"
      printf "\n\t\t(combine with '-z zone' for 'now playing' in only that zone)"
      printf "\n\t-O opens 'Roon TUI' terminal user interface for Roon if available"
      printf "\n\t-p playlist selects a playlist to play"
      printf "\n\t-G zone_group specifies a zone grouping specified in roon_api.ini"
      printf "\n\t-L setup roon to execute local commands rather than remote via SSH"
      printf "\n\t-S Set Roon defaults in roon_api.ini"
      printf "\n\t-l [albums|artists|artalbums|albtracks|arttracks|composers|comalbums|"
      printf "\n\t    genres|genalbums|genartists|playlists|playtracks|tags|zones]"
      printf "\n\t        indicates list albums, artists, albums by artist,"
      printf "\n\t        composers, albums by composers, genres, albums in genre,"
      printf "\n\t        artists in genre, playlists, tags, or Roon zones"
      printf "\n\t-r radio selects a live radio stream to play"
      printf "\n\t-s search specifies a term to search for in the lists retrieved with -l"
      printf "\n\t-T track specifies a track to play"
      printf "\n\t-t tag selects an tag to play"
      printf "\n\t-z zone selects the Roon Zone in which to play"
      printf "\n\t-c [discover|group|ungroup|play|play_all|pause|pause_all|playpause|stop|stop_all|"
      printf "\n\t    next|previous|shuffle|unshuffle|repeat|unrepeat|mute|mute_all]"
      printf "\n\t        issues the command in the selected zone"
      printf "\n\t        'mute' toggles the zone's muted or unmuted state"
      printf "\n\t        'mute_all' toggles all zones' muted or unmuted state"
      printf "\n\t        'pause_all' pauses playback in all zones"
      printf "\n\t        'play_all' begins playback in all zones"
      printf "\n\t        'stop_all' stops playback in all zones and releases devices"
      printf "\n\t        'shuffle' enables the zone's shuffled setting"
      printf "\n\t        'unshuffle' disables the zone's shuffled setting"
      printf "\n\t        'repeat' enables the zone's looping setting"
      printf "\n\t        'repeat' disables the zone's looping setting"
      printf "\n\t-v volume sets the volume level in the selected zone"
      printf "\n\t\tThe volume argument has the format [g:][r:][s:]num"
      printf "\n\t\tWhere 'g' indicates set volume for all zones in the group"
      printf "\n\t\t'r' specifies use relative method volume setting"
      printf "\n\t\t's' specifies use relative_step method volume setting"
      printf "\n\t\t'num' can be absolute, relative, and negative or positive"
      printf "\n\t-X ex_album specifies a string to exclude from album/genre names"
      printf "\n\t-x ex_artist specifies a string to exclude from artist/composer/playlist names"
      printf "\n\t-u displays a full usage message with examples"
      printf "\n\t-U displays a usage message without examples"
      printf "\n\t-E displays examples with no usage message"
      printf "\nCombine '-a artist' and '-A album' to play an album by a specified artist"
      printf "\nCombine '-a artist' and '-T track' to play a track by a specified artist"
      printf "\nCombine '-a artist' or '-A album' with '-g genre' to play an artist or album in a specified genre\n"
      printf "\nSpecial search term '__all__' matches all entries"
      printf "\nSpecial name 'default' plays the default setting in roon_api.ini\n"
    fi
  }
  [ "${showexamples}" ] && {
    if [ "${have_rich}" ]; then
      rich "[bold]Example invocations[/]" --print
      rich "    [magenta]Play artist:[/]" --print
      rich "        [bold italic green]roon -a \"Deep Purple\"[/]" --print
      rich "    [magenta]Play album by artist:[/]" --print
      rich "        [bold italic green]roon -a \"Deep Purple\" -A Burn[/]" --print
      rich "    [magenta]Play track by artist:[/]" --print
      rich "        [bold italic green]roon -a \"Aretha Franklin\" -T Think[/]" --print
      rich "    [magenta]Play artist in specified zone:[/]" --print
      rich "        [bold italic green]roon -a \"Jethro Tull\" -z \"Mac Pro DAC\"[/]" --print
      rich "    [magenta]Play genre:[/]" --print
      rich "        [bold italic green]roon -g Classical[/]" --print
      rich "    [magenta]Play default live radio:[/]" --print
      rich "        [bold italic green]roon -r default[/]" --print
      rich "    [magenta]Play playlist:[/]" --print
      rich "        [bold italic green]roon -p \"Bowie Favs\"[/]" --print
      rich "    [magenta]Play next track:[/]" --print
      rich "        [bold italic green]roon -c next[/]" --print
      rich "    [magenta]Stop play in specified zone:[/]" --print
      rich "        [bold italic green]roon -c stop -z Kitchen[/]" --print
      rich "    [magenta]Mute/Unmute a specified zone:[/]" --print
      rich "        [bold italic green]roon -c mute -z \"Mac Pro DAC\"[/]" --print
      rich "    [magenta]Mute/Unmute all zones:[/]" --print
      rich "        [bold italic green]roon -c mute_all[/]" --print
      rich "    [magenta]List all playlists containing the string 'Best':[/]" --print
      rich "        [bold italic green]roon -l playlists -s Best[/]" --print
      rich "    [magenta]List albums by artist:[/]" --print
      rich "        [bold italic green]roon -l artalbums -a \"Deep Purple\"[/]" --print
      rich "    [magenta]List artists containing the string 'Will' in the 'Country' genre:[/]" --print
      rich "        [bold italic green]roon -l genartists -a Will -g Country[/]" --print
      rich "    [magenta]List albums containing the string 'Magic' in the 'Rock' genre:[/]" --print
      rich "        [bold italic green]roon -l genalbums -A Magic -g Rock[/]" --print
      rich "    [magenta]Play artist containing the string 'Willie' in the 'Country' genre:[/]" --print
      rich "        [bold italic green]roon -a Willie -g Country[/]" --print
      rich "    [magenta]Play album containing the string 'Magic' in the 'Rock' genre:[/]" --print
      rich "        [bold italic green]roon -A Magic -g Rock[/]" --print
      rich "    [magenta]Group the zones listed in roon_api.ini Group_foobar:[/]" --print
      rich "        [bold italic green]roon -G foobar -c group[/]" --print
      rich "    [magenta]Set the volume level to 50 in the currently active zone[/]" --print
      rich "        [bold italic green]roon -v 50[/]" --print
      rich "    [magenta]Decrease the volume level by 10 in the currently active zone[/]" --print
      rich "        [bold italic green]roon -v r:-10[/]" --print
      rich "    [magenta]Set the volume level to 40 in all zones grouped with the zone named 'Mac Pro DAC'[/]" --print
      rich "        [bold italic green]roon -v g:40 -z 'Mac Pro DAC'[/]" --print
      rich "    [magenta]Increase the volume level by 20 in all zones grouped with the zone named 'Mac Pro DAC'[/]" --print
      rich "        [bold italic green]roon -v g:r:20 -z 'Mac Pro DAC'[/]" --print
      rich "    [magenta]Get info on all Roon zones[/]" --print
      rich "        [bold italic green]roon -i[/]" --print
      rich "    [magenta]Get extended info on Roon zone named 'Mac Pro DAC'[/]" --print
      rich "        [bold italic green]roon -i -z 'Mac Pro DAC'[/]" --print
      rich "    [magenta]Get now playing info on all zones regardless of state[/]" --print
      rich "        [bold italic green]roon -N[/]" --print
      rich "    [magenta]Get now playing info on all zones actively playing[/]" --print
      rich "        [bold italic green]roon -n[/]" --print
      rich "    [magenta]Get now playing info on Roon zone named 'Mac Pro DAC'[/]" --print
      rich "        [bold italic green]roon -n -z 'Mac Pro DAC'[/]" --print
      rich "    [magenta]Enable volume fading in default Roon zone[/]" --print
      rich "        [bold italic green]roon -f on[/]" --print
      rich "    [magenta]Disable volume fading in default Roon zone[/]" --print
      rich "        [bold italic green]roon -f off[/]" --print
      rich "    [bold]NOTE:[/] [italic]Use quotes to specify media names which contain spaces.[/]" --print
      rich "    For example, to [magenta]play the album 'Love Bomb':[/]" --print
      rich "        [bold italic green]roon -A \"Love Bomb\"[/]" --print
    else
      printf "\nExample invocations"
      printf "\n\tPlay artist:"
      printf "\n\t\troon -a \"Deep Purple\""
      printf "\n\tPlay album by artist:"
      printf "\n\t\troon -a \"Deep Purple\" -A Burn"
      printf "\n\tPlay track by artist:"
      printf "\n\t\troon -a \"Aretha Franklin\" -T Think"
      printf "\n\tPlay artist in specified zone:"
      printf "\n\t\troon -a \"Jethro Tull\" -z \"Mac Pro DAC\""
      printf "\n\tPlay genre:"
      printf "\n\t\troon -g Classical"
      printf "\n\tPlay default live radio:"
      printf "\n\t\troon -r default"
      printf "\n\tPlay playlist:"
      printf "\n\t\troon -p \"Bowie Favs\""
      printf "\n\tPlay next track:"
      printf "\n\t\troon -c next"
      printf "\n\tStop play in specified zone:"
      printf "\n\t\troon -c stop -z Kitchen"
      printf "\n\tMute/Unmute a specified zone:"
      printf "\n\t\troon -c mute -z \"Mac Pro DAC\""
      printf "\n\tMute/Unmute all zones:"
      printf "\n\t\troon -c mute_all"
      printf "\n\tList all playlists containing the string 'Best':"
      printf "\n\t\troon -l playlists -s Best"
      printf "\n\tList albums by artist:"
      printf "\n\t\troon -l artalbums -a \"Deep Purple\""
      printf "\n\tList artists containing the string 'Will' in the 'Country' genre:"
      printf "\n\t\troon -l genartists -a Will -g Country"
      printf "\n\tList albums containing the string 'Magic' in the 'Rock' genre:"
      printf "\n\t\troon -l genalbums -A Magic -g Rock"
      printf "\n\tPlay artist containing the string 'Willie' in the 'Country' genre:"
      printf "\n\t\troon -a Willie -g Country"
      printf "\n\tPlay album containing the string 'Magic' in the 'Rock' genre:"
      printf "\n\t\troon -A Magic -g Rock"
      printf "\n\tGroup the zones listed in roon_api.ini Group_foobar:"
      printf "\n\t\troon -G foobar -c group"
      printf "\n\tSet the volume level to 50 in the currently active zone"
      printf "\n\t\troon -v 50"
      printf "\n\tDecrease the volume level by 10 in the currently active zone"
      printf "\n\t\troon -v r:-10"
      printf "\n\tSet the volume level to 40 in all zones grouped with the zone named 'Mac Pro DAC'"
      printf "\n\t\troon -v g:40 -z 'Mac Pro DAC'"
      printf "\n\tIncrease the volume level by 20 in all zones grouped with the zone named 'Mac Pro DAC'"
      printf "\n\t\troon -v g:r:20 -z 'Mac Pro DAC'"
      printf "\n\tGet info on all Roon zones"
      printf "\n\t\troon -i"
      printf "\n\tGet extended info on Roon zone named 'Mac Pro DAC'"
      printf "\n\t\troon -i -z 'Mac Pro DAC'"
      printf "\n\tGet now playing info on all zones regardless of state"
      printf "\n\t\troon -N"
      printf "\n\tGet now playing info on all zones actively playing"
      printf "\n\t\troon -n"
      printf "\n\tGet now playing info on Roon zone named 'Mac Pro DAC'"
      printf "\n\t\troon -n -z 'Mac Pro DAC'"
      printf "\n\tEnable volume fading in default Roon zone"
      printf "\n\t\troon -f on"
      printf "\n\tDisable volume fading in default Roon zone"
      printf "\n\t\troon -f off"
      printf "\n\tNOTE: Use quotes to specify media names which contain spaces."
      printf "\n\tFor example, to play the album 'Love Bomb':"
      printf "\n\t\troon -A \"Love Bomb\"\n"
    fi
  }
  [ "${noexit}" ] || exit 1
}

# Display a heading with rich-cli or printf
heading() {
  clear_screen
  if [ "${have_rich}" ]; then
    rich "[cyan]$1[/cyan]" -p -a rounded -c -C
  else
    printf "\n$1\n"
  fi
}

# Add a component to the PATH environment variable
pathadd() {
  if [ -d "$1" ] && [[ ":$PATH:" != *":$1:"* ]]; then
    PATH="$1${PATH:+":$PATH"}"
    export PATH
  fi
}

# Prompt before continuing
prompt_continue() {
  printf "\nPress ${BOLD}<Enter>${NORM} to continue ... "
  read -r yn
  clear_screen
}

# Get the latest RoonCommandLine version and release
get_control_version() {
  VURL="${rcl_url}/master/VERSION"
  curl -fsSL "${VURL}" > /tmp/rcv$$
  rcver=$(cat /tmp/rcv$$ | grep VERSION | awk -F '=' '{ print $2 }')
  rcrel=$(cat /tmp/rcv$$ | grep RELEASE | awk -F '=' '{ print $2 }')
  rm -f /tmp/rcv$$
  echo "v${rcver}r${rcrel}"
}

# Get the installed RoonCommandLine version and release
get_install_version() {
  [ "${ROON}" ] || ROON="/usr/local/Roon"
  RC_INST="${ROON}/etc/VERSION"
  if [ -f ${RC_INST} ]; then
    rcver=$(grep ^VERSION= ${RC_INST} | awk -F '=' '{ print $2 }')
    rcrel=$(grep ^RELEASE= ${RC_INST} | awk -F '=' '{ print $2 }')
  else
    rcver=${VERSION}
    rcrel=${RELEASE}
  fi
  echo "v${rcver}r${rcrel}"
}

# Compare version strings of the format major.middle.minor
# Usage: check_three_version release_version install_version
check_three_version() {
  release_version="$1"
  install_version="$2"

  release_major=$(echo ${release_version} | awk -F '.' '{ print $1 }')
  release_midde=$(echo ${release_version} | awk -F '.' '{ print $2 }')
  release_minor=$(echo ${release_version} | awk -F '.' '{ print $3 }')
  [ "${release_major}" ] || release_major=0
  [ "${release_midde}" ] || release_midde=0
  [ "${release_minor}" ] || release_minor=0

  install_major=$(echo ${install_version} | awk -F '.' '{ print $1 }')
  install_midde=$(echo ${install_version} | awk -F '.' '{ print $2 }')
  install_minor=$(echo ${install_version} | awk -F '.' '{ print $3 }')
  [ "${install_major}" ] || install_major=0
  [ "${install_midde}" ] || install_midde=0
  [ "${install_minor}" ] || install_minor=0

  if [ ${release_major} -gt ${install_major} ]; then
    echo "${release_version}"
  else
    if [ ${release_midde} -gt ${install_midde} ]; then
      echo "${release_version}"
    else
      if [ ${release_minor} -gt ${install_minor} ]; then
        echo "${release_version}"
      else
        echo ""
      fi
    fi
  fi
}

# Display version numbers and available updates if any
show_versions() {
  printf "\n"
  control_version=$(get_control_version)
  install_version=$(get_install_version)
  if [ "${have_rich}" ]; then
    if [ "${install_version}" == "${control_version}" ]; then
      rich "Installed [green]RoonCommandLine[/] version: [yellow]${install_version}[/] ( current)" -p
    else
      rich "Installed [green]RoonCommandLine[/] version: [yellow]${install_version}[/]" -p
      rich "Available [green]RoonCommandLine[/] version: [yellow]${control_version}[/]" -p
    fi
  else
    printf "\nInstalled RoonCommandLine version: ${install_version}"
    if [ "${install_version}" == "${control_version}" ]; then
      printf " ( current)"
    else
      printf "\nAvailable RoonCommandLine version: ${control_version}"
    fi
  fi
  release_version=$(curl -fsSL "${fzf_url}" | grep ^version= | awk -F '=' '{ print $2 }')
  if [ "${have_fzf}" ]; then
    install_version=$(fzf --version | awk '{ print $1 }')
  else
    install_version="uninstalled"
  fi
  if [ "${have_rich}" ]; then
    if [ "${install_version}" == "${release_version}" ]; then
      rich "Installed [green]fzf[/] version:             [yellow]${install_version}[/] ( current)" -p
    else
      rich "Installed [green]fzf[/] version:             [yellow]${install_version}[/]" -p
      rich "Available [green]fzf[/] version:             [yellow]${release_version}[/]" -p
    fi
  else
    printf "\nInstalled fzf version: ${install_version}"
    if [ "${install_version}" == "${release_version}" ]; then
      printf " ( current)\n"
    else
      printf "\nAvailable fzf version: ${release_version}\n"
    fi
  fi
  if [ "${have_gui}" ]; then
    release_version=$(${ROON}/etc/install-roon-gui version)
    gv=$(flatpak info com.theappgineer.community_remote | grep Version | awk -F ':' '{ print $2 }')
    install_version="$(echo -e "${gv}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
    if [ "${have_rich}" ]; then
      if [ "${install_version}" == "${release_version}" ]; then
        rich "Installed [green]Roon GUI[/] version:        [yellow]${install_version}[/] ( current)" -p
      else
        rich "Installed [green]Roon GUI[/] version:        [yellow]${install_version}[/]" -p
        rich "Available [green]Roon GUI[/] version:        [yellow]${release_version}[/]" -p
      fi
    else
      printf "\nInstalled Roon GUI version: ${install_version}"
      if [ "${install_version}" == "${release_version}" ]; then
        printf " ( current)\n"
      else
        printf "\nAvailable Roon GUI version: ${release_version}\n"
      fi
    fi
  else
    [ "${have_flat}" ] && {
      if [ "${have_rich}" ]; then
        rich "[red]Roon GUI[/] not installed" -p
      else
        printf "\nRoon GUI not installed\n"
      fi
    }
  fi
  if [ "${have_tui}" ]; then
    release_version=$(${ROON}/etc/install-roon-tui version)
    install_version=$(roon-tui --version | awk '{ print $2 }')
    if [ "${have_rich}" ]; then
      if [ "${install_version}" == "${release_version}" ]; then
        rich "Installed [green]Roon TUI[/] version:        [yellow]${install_version}[/] ( current)" -p
      else
        rich "Installed [green]Roon TUI[/] version:        [yellow]${install_version}[/]" -p
        rich "Available [green]Roon TUI[/] version:        [yellow]${release_version}[/]" -p
      fi
    else
      printf "\nInstalled Roon TUI version: ${install_version}"
      if [ "${install_version}" == "${release_version}" ]; then
        printf " ( current)\n"
      else
        printf "\nAvailable Roon TUI version: ${release_version}\n"
      fi
    fi
  else
    if [ "${have_rich}" ]; then
      rich "[red]Roon TUI[/] not installed" -p
    else
      printf "\nRoon TUI not installed\n"
    fi
  fi
}

set_fzf_release() {
  fzf_release_version=$(curl -fsSL "${fzf_url}" | grep ^version= | awk -F '=' '{ print $2 }')
  if [ "${have_fzf}" ]; then
    fzf_install_version=$(fzf --version | awk '{ print $1 }')
    update_fzf=$(check_three_version "${fzf_release_version}" "${fzf_install_version}")
  else
    fzf_install_version="uninstalled"
    update_fzf=
  fi
}

set_gui_release() {
  gui_release_version=$(${ROON}/etc/install-roon-gui version)
  if [ "${have_gui}" ]; then
    gv=$(flatpak info com.theappgineer.community_remote | grep Version | awk -F ':' '{ print $2 }')
    gui_install_version="$(echo -e "${gv}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
    update_gui=$(check_three_version "${gui_release_version}" "${gui_install_version}")
  else
    gui_install_version="uninstalled"
    update_gui=
  fi
}

set_tui_release() {
  tui_release_version=$(${ROON}/etc/install-roon-tui version)
  if [ "${have_tui}" ]; then
    tui_install_version=$(roon-tui --version | awk '{ print $2 }')
    update_tui=$(check_three_version "${tui_release_version}" "${tui_install_version}")
  else
    tui_install_version="uninstalled"
    update_tui=
  fi
}

set_have_gui() {
  if [ "${have_flat}" ]; then
    flatpak info com.theappgineer.community_remote >/dev/null 2>&1
    if [ $? -eq 0 ]; then
      have_gui=1
    else
      have_gui=
    fi
  else
    have_gui=
  fi
}

install_roon_gui() {
  ${ROONETC}/install-roon-gui
  set_have_gui
  set_gui_release
}

install_roon_tui() {
  ${ROONETC}/install-roon-tui
  have_tui=$(type -p roon-tui)
  set_tui_release
}

# Display RoonCommandLine info, versions, and update availability
show_about() {
  [ "${have_gum}" ] && [ "${have_figlet}" ] && {
    [ -x ${ROON}/bin/roonanim ] && {
      clear
      ${ROON}/bin/roonanim -a -q
      [ $? -eq 0 ] || tput cup 0 0 2>/dev/null
      sleep 3
    }
  }
  F_URL="https://community.roonlabs.com/search?q=RoonCommandLine"
  R_URL="https://github.com/doctorfree/RoonCommandLine"
  W_URL="https://github.com/doctorfree/RoonCommandLine/wiki"
  heading "About RoonCommandLine" "About"
  if [ "${have_rich}" ]; then
    rich "[cyan]RoonCommandLine[/] is an open source command line suite of utilities to" -p
    rich "control the [green]Roon[/] audio system using the [green]Python Roon API[/] facility." -p
    rich "[cyan]RoonCommandLine[/] enables automation of [green]Roon[/] actions and provides an" -p
    rich "additional layer of convenience. Scripted [green]Roon[/] actions enable quick" -p
    rich "and easy control and configuration of [green]Roon[/] in automated environments." -p
    rich "[cyan]RoonCommandLine[/] is written in [yellow]Bash[/] and [yellow]Python[/] by Ronald Record." -p
    rich "The [green]Python Roon API[/] is written and maintained by Greg Dowling." -p
    rich "[magenta]RoonCommandLine Repo[/]: [link=${R_URL}#readme][yellow]${R_URL}[/yellow][/link]" -p
    rich "[magenta]RoonCommandLine Wiki[/]: [link=${W_URL}][yellow]${W_URL}[/yellow][/link]" -p
    rich "[magenta]Roon Community Forum[/]: [link=${F_URL}][yellow]${F_URL}[/yellow][/link]" -p
  else
    printf "\n'RoonCommandLine' is an open source command line suite of utilities to"
    printf "\ncontrol the 'Roon' audio system using the 'Python Roon API' facility."
    printf "\n'RoonCommandLine' enables automation of 'Roon' actions and provides an"
    printf "\nadditional layer of convenience. Scripted 'Roon' actions enable quick"
    printf "\nand easy control and configuration of 'Roon' in automated environments."
    printf "\n'RoonCommandLine' is written in 'Bash' and 'Python' by Ronald Record."
    printf "\nThe 'Python Roon API' is written and maintained by Greg Dowling."
    printf "\nRoonCommandLine Repo: ${R_URL}"
    printf "\nRoonCommandLine Wiki: ${W_URL}"
    printf "\nRoon Community Forum: ${F_URL}\n"
  fi
  show_versions
}

# Get the value of the specified entry in roon_api.ini
# get_default_ini <EntryName>
get_default_ini() {
  entry="$1"
  de=$(grep ^${entry} ${ROON_INI} | awk -F '=' ' { print $2 } ')
  # Remove leading and trailing spaces
  de="$(echo -e "${de}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
  echo "${de}"
}

# Display RoonCommandLine info
show_info() {
  fullinfo=1
  [ "$1" == "brief" ] && fullinfo=
  [ "${fullinfo}" ] && {
    rc_version=$(get_default_ini RoonCommandLineVersion)
    rc_release=$(get_default_ini RoonCommandLineRelease)
    rc_versrel="v${rc_version}r${rc_release}"
    rc_port=$(get_default_ini RoonCorePort)
    rc_ip=$(get_default_ini RoonCoreIP)
    heading "Roon Command Line ${rc_versrel}" "${rc_versrel}"
    if [ "${have_rich}" ]; then
      rich "[red]Roon Core IP[/]:        [link=http://${rc_ip}][yellow]${rc_ip}[/yellow][/link]" -p
      rich "[red]Roon Core Port[/]:      [yellow]${rc_port}[/]" -p
    else
      printf "\nRoon Core IP:\t${rc_ip}"
      printf "\nRoon Core Port:\t${rc_port}"
    fi
  }
  for media in Album Artist Composer Genre Playlist Radio Tag Zone; do
    DEFAULT=$(get_default_ini Default${media})
    if [ "${have_rich}" ]; then
      numspaces=$((12-${#media}))
      spaces=""
      for i in $(seq ${numspaces})
      do
        spaces="${spaces} "
      done
      rich "[red]Default ${media}[/]:${spaces}[yellow]${DEFAULT}[/]" -p
    else
      printf "\nDefault ${media}:\t${DEFAULT}"
    fi
  done
  [ "${fullinfo}" ] && show_now_playing
}

# Install the fzf fuzzy finder utility
install_fzf() {
  printf "\nInstalling fzf\n"
  [ -f ${HOME}/.local/bin/fzf ] && {
    mv ${HOME}/.local/bin/fzf ${HOME}/.local/bin/fzf-bak$$
  }
  [ -d ${HOME}/.fzf ] && mv ${HOME}/.fzf ${HOME}/.fzf$$
  git clone --depth 1 https://github.com/junegunn/fzf.git \
    ${HOME}/.fzf > /dev/null 2>&1
  [ -f ${HOME}/.fzf/install ] && chmod 755 ${HOME}/.fzf/install
  [ -x ${HOME}/.fzf/install ] && ${HOME}/.fzf/install --all > /dev/null 2>&1
  [ -d ${HOME}/.fzf/bin ] && pathadd "${HOME}/.fzf/bin"
  if [ -f ${HOME}/.fzf/bin/fzf ]; then
    ln -s ${HOME}/.fzf/bin/fzf ${HOME}/.local/bin/fzf
    rm -f ${HOME}/.local/bin/fzf-bak$$
  else
    [ -f ${HOME}/.local/bin/fzf-bak$$ ] && {
      mv ${HOME}/.local/bin/fzf-bak$$ ${HOME}/.local/bin/fzf
    }
  fi
  [ "${have_fzf}" ] && use_fzf=1
}

# Upgrade the fzf fuzzy finder utility
upgrade_fzf() {
  [ -d ${HOME}/.fzf/.git ] && git -C ${HOME}/.fzf pull > /dev/null 2>&1
  if [ -d ${HOME}/.fzf ]; then
    if [ -f ${HOME}/.fzf/install ]; then
      chmod 755 ${HOME}/.fzf/install
      ${HOME}/.fzf/install --all > /dev/null 2>&1
    else
      install_fzf
    fi
  else
    [ "${have_brew}" ] && brew uninstall fzf > /dev/null 2>&1
    install_fzf
  fi
  [ -d ${HOME}/.fzf/bin ] && pathadd "${HOME}/.fzf/bin"
}

# Successful exit gets a farewell message
farewell_exit() {
  heading "$1" "Farewell"
  exit 0
}

# Use 'roon -d -m' to avoid clearing the screen between menus
clear_screen() {
  [ "${debug}" ] || tput clear
}

# The 'media_options' array must be set prior to calling set_zone_options
set_zone_options() {
  ${IFS+"false"} && unset oldifs || oldifs="$IFS"
  IFS=$'\n'
  if [ "${LOCAL}" == "true" ]; then
    zones=$(${ROON}/bin/get_zones | sed -e 's/\, /\,/g')
  else
    zones=$(ssh ${user}@${server} "bash -l -c \"${ROON}/bin/get_zones | sed -e 's/\, /\,/g'\"")
  fi
  media_options+=($(echo "${zones}" | awk -F "," ' { for(i=1;i<=NF;i++) printf "%s\n",$i }'))
  ${oldifs+"false"} && unset IFS || IFS="$oldifs"
}

# Display currently playing info for specified zone or all zones
show_now_playing() {
  zone="$1"
  nowarg="$2"
  if [ "${nowarg}" ]; then
    if [ "${LOCAL}" = true ]; then
      if [ "${zone}" ]; then
        ${ROON}/bin/now_playing ${nowarg} -z "${zone}"
      else
        ${ROON}/bin/now_playing ${nowarg}
      fi
    else
      if [ "${zone}" ]; then
        ssh ${user}@${server} "bash -l -c \"${ROON}/bin/now_playing ${nowarg} -z ${zone}\""
      else
        ssh ${user}@${server} "bash -l -c \"${ROON}/bin/now_playing ${nowarg}\""
      fi
    fi
  else
    [ "${zone}" ] || zone=$(get_default_ini DefaultZone)
    if [ "${have_rich}" ]; then
      rich "[red]Now Playing[/]:" -p
    else
      printf "\nNow Playing:\n"
    fi
    if [ "${have_jq}" ]; then
      ${ROON}/bin/get_zone_info -n -z "${zone}" | \
      jq -r 'to_entries[] | "\(.key)=\"\(.value)\""' | while read i
      do
        k=$(echo $i | awk -F '=' '{ print $1 }')
        v=$(echo $i | awk -F '=' '{ print $2 }')
        k="$(echo -e "${k}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
        v="$(echo -e "${v}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
        v="$(echo -e "${v}" | sed -e 's/^\"//' -e 's/\"$//')"
        if echo "${k}" | grep Now > /dev/null; then
          pre=""
          siz=19
        else
          pre="    "
          siz=15
        fi
        numspaces=$((${siz} - ${#k}))
        spaces=""
        for i in $(seq ${numspaces}); do
          spaces="${spaces} "
        done
        if [ "${have_rich}" ]; then
          rich "${pre}[red]${k}[/]:${spaces} [yellow]${v}[/]" -p
        else
          printf "\n\t${pre}$k:${spaces} $v"
        fi
      done
    else
      ${ROON}/bin/get_zone_info -n -z "${zone}"
    fi
  fi
  if [ "${have_jq}" ]; then
    pre="    "
    vol=$(${ROON}/bin/get_zone_volume -n)
    if [ "${have_rich}" ]; then
      rich "${pre}[red]Volume[/]:          [yellow]${vol}[/]" -p
    else
      printf "\n\t${pre}Volume:          $vol"
    fi
  else
    ${ROON}/bin/get_zone_volume
  fi
}

show_roon_menu=
[ "$1" ] || show_roon_menu=1

ROON=/usr/local/Roon
ROONAPI=${ROON}/api
ROONETC=${ROON}/etc
ROON_INI=${ROONETC}/roon_api.ini
ROONCONF=${ROONETC}/pyroonconf
LOCAL=false

# Set a default TERM if one not already set
[ "${TERM}" ] || export TERM="vt100"

BOLD=$(tput bold 2>/dev/null)
NORMAL=$(tput sgr0 2>/dev/null)

# Check Python virtual environment
[ -e ${ROON}/venv/bin/python3 ] || {
  printf "\nRepairing RoonCommandLine Python virtual environment ..."
  [ -x ${ROONETC}/upgrade-venv ] && ${ROONETC}/upgrade-venv
  printf " done\n"
}

[ -f ${ROON}/venv/bin/activate ] && source ${ROON}/venv/bin/activate
[ -x ${ROON}/venv/bin/python ] && export PYTHON=${ROON}/venv/bin/python

[[ ":$PATH:" == *":/usr/local/bin:"* ]] || export PATH=${PATH}:/usr/local/bin
[[ ":$PATH:" == *":/usr/local/Roon/bin:"* ]] || {
  export PATH=/usr/local/Roon/bin:${PATH}
}
[[ ":$PATH:" == *":/usr/local/Roon/venv/bin:"* ]] || {
  export PATH=/usr/local/Roon/venv/bin:${PATH}
}
if [ -x /home/linuxbrew/.linuxbrew/bin/brew ]; then
  eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
else
  [ -x /usr/local/bin/brew ] && eval "$(/usr/local/bin/brew shellenv)"
fi

clear_screen

set_default_conf() {
  if [ -w ${ROONETC} ]; then
    echo "LOCAL=true" >${ROONCONF}
    DEFZONE=$(get_default_ini DefaultZone)
    echo "ROON_ZONE=\"$DEFZONE\"" >>${ROONCONF}
  else
    echo "${ROONETC} is not writeable by this user."
    echo "Correct permissions on ${ROONETC} and re-run this command."
    echo "Exiting."
    exit 1
  fi
}

[ -f ${ROONCONF} ] || set_default_conf

bash -n ${ROONCONF} >/dev/null 2>&1
[ $? -eq 0 ] || {
  echo "WARNING: Syntax errors in ${ROONCONF} have been detected."
  echo "The following is the output of bash -n ${ROONCONF}"
  echo ""
  bash -n ${ROONCONF}
  echo ""
  while true; do
    read -r -p "Revert to default settings and continue? (y/n) " answer
    case ${answer} in
      [Yy]*)
        set_default_conf
        break
        ;;
      [Nn]*)
        echo "Correct syntax errors in ${ROONCONF} and re-run this command."
        echo "Exiting."
        exit 1
        ;;
      *)
        echo "Please answer 'y' to repair configuration, or 'n' to exit."
        ;;
    esac
  done
}
[ -f ${ROONCONF} ] && . ${ROONCONF}

select_zone() {
  media_options=()
  set_zone_options
  media_options+=("Defaults Menu    [d]")
  media_options+=("Main Menu        [m]")
  media_options+=("Quit             [q]")
  while true; do
    clear_screen
    [ "${have_rich}" ] && {
      rich "[bold][cyan]Select Roon Zone[/cyan][/bold]" -p -a rounded -c -C
    }
    PS3="${BOLD}Please enter the Roon zone you wish to use (numeric or text): ${NORMAL}"
    select opt in "${media_options[@]}"; do
      case "$opt,$REPLY" in
        "Main Menu"*,* | *,"Main Menu"* | "m",* | *,"m")
          main_menu
          break 2
          ;;
        "Quit"*,* | *,"Quit"* | "quit"*,* | *,"quit"* | "q",* | *,"q")
          farewell_exit "Exiting RoonCommandLine"
          ;;
        "Defaults Menu"*,* | *,"Defaults Menu"* | "d",* | *,"d")
          list_defaults
          break 2
          ;;
        *,*)
          if [[ " ${media_options[*]} " =~ " ${opt} " ]]; then
            echo "${BOLD}Executing Roon command to set default zone to: ${opt}${NORMAL}"
            if [ "${LOCAL}" = true ]; then
              ${ROON}/bin/set_zone "${opt}"
            else
              ssh ${user}@${server} "bash -l -c \"${ROON}/bin/set_zone ${opt}\""
            fi
            status=$?
            [ ${status} -eq 0 ] || {
              echo "Unable to set zone for zone = $opt"
            }
            [ -f ${ROONCONF} ] && . ${ROONCONF}
            break 2
          else
            printf "\n\nInvalid option: ${opt}"
            printf "\n\tPlease enter either the exact text, shortcut, or"
            printf "\n\tnumeric designation for one of the listed options.\n\n"
            break
          fi
          ;;
      esac
    done
  done
}

select_default() {
  media="$1"
  have_python3=$(type -p python3)
  if [ "${have_python3}" ]; then
    pycom="python3 ${ROONAPI}/set_default.py"
  else
    pycom="python ${ROONAPI}/set_default.py"
  fi
  case "${media}" in
    "Album")
      setdefcom="${pycom} -A"
      listcom="list_albums"
      ;;
    "Artist")
      setdefcom="${pycom} -a"
      listcom="list_artists"
      ;;
    "Composer")
      setdefcom="${pycom} -c"
      listcom="list_composers"
      ;;
    "Genre")
      setdefcom="${pycom} -g"
      listcom="list_genres"
      ;;
    "Playlist")
      setdefcom="${pycom} -p"
      listcom="list_playlists"
      ;;
    "Radio")
      setdefcom="${pycom} -r"
      listcom="list_radio"
      ;;
    "Tag")
      setdefcom="${pycom} -t"
      listcom="list_tags"
      ;;
    "Track")
      setdefcom="true"
      listcom="list_tracks"
      ;;
    "Zone")
      setdefcom="${pycom} -z"
      listcom="list_zones"
      ;;
    *)
      return 1
      ;;
  esac
  printf "\nRetrieving ${media}s in your Roon library ..."
  if [ "${have_fzf}" ]; then
    media_options=("Set Defaults Menu" "Main Menu" "Quit")
  else
    media_options=()
  fi
  if [ "${media}" == "Zone" ]; then
    set_zone_options
  else
    ${IFS+"false"} && unset oldifs || oldifs="$IFS"
    IFS=$'\n'
    if [ "${LOCAL}" = true ]; then
      media_options+=($(${listcom} -q))
    else
      media_options+=($(ssh ${user}@${server} "bash -l -c \"${ROON}/bin/${listcom} -q\""))
    fi
    ${oldifs+"false"} && unset IFS || IFS="$oldifs"
  fi
  DEFAULT=$(get_default_ini Default${media})
  printf " Done\n\n"
  printf "Default${media} = ${DEFAULT}\n\n"

  if [ "${have_fzf}" ]; then
    while true; do
      heading "RoonCommandLine Default ${media}" "Default ${media}"
      case ${media} in
        Zone)
          [ -f ${ROONCONF} ] && . ${ROONCONF}
          if [ "${LOCAL}" = true ]; then
            if [ "${ROON_ZONE}" ]; then
              echo "Current Roon Zone: ${ROON_ZONE}"
            else
              echo "No Roon Zone is set in ${ROONCONF}"
            fi
          else
            roon_zone=$(ssh ${user}@${server} "bash -l -c \"grep ROON_ZONE ${ROONCONF}\"")
            if [ "${roon_zone}" ]; then
              echo "Current Roon Zone: ${roon_zone}"
            else
              echo "No Roon Zone is set in ${ROONCONF}"
            fi
          fi
          DEFZONE=$(get_default_ini DefaultZone)
          if [ "${DEFZONE}" ]; then
            echo "Default Roon Zone: ${DEFZONE}"
          else
            echo "No Default Roon Zone is set in ${ROON_INI}"
          fi
          ;;
        *)
          default=$(get_default_ini Default${media})
          if [ "${default}" ]; then
            echo "Default Roon ${media}: ${default}"
          else
            echo "No Default Roon ${media} is set in ${ROON_INI}"
          fi
          ;;
      esac
      choice=$(printf "%s\n" "${media_options[@]}" | fzf -m --prompt=" 🎶 Select Default ${media} ('Main Menu' or 'Esc' to return, 'Quit' to exit)  " --height=18 --layout=reverse --exit-0)
      if [ "${choice}" ]; then
        case "${choice}" in
          "Quit"* | "quit"* | "Q" | "q")
            farewell_exit "Exiting RoonCommandLine"
            ;;
          "Main Menu"* | "main menu"*)
            main_menu
            break
            ;;
          "Set Defaults Menu"*)
            break
            ;;
          *)
            echo "${BOLD}Setting Roon ${media} default to: ${choice}${NORMAL}"
            if [ "${LOCAL}" = true ]; then
              ${setdefcom} "${choice}"
            else
              ssh ${user}@${server} "bash -l -c \"${ROON}/bin/${setdefcom} ${choice}\""
            fi
            [ "${media}" == "Zone" ] && {
              if [ "${LOCAL}" = true ]; then
                ${ROON}/bin/set_zone "${choice}"
              else
                ssh ${user}@${server} "bash -l -c \"${ROON}/bin/set_zone ${choice}\""
              fi
              [ -f ${ROONCONF} ] && . ${ROONCONF}
            }
            break
            ;;
        esac
      else
        break
      fi
    done
  else
    media_options+=("Set Defaults Menu    [d]")
    media_options+=("Main Menu            [m]")
    media_options+=("Quit                 [q]")
    while true; do
      clear_screen
      [ "${have_rich}" ] && {
        rich "[bold][cyan]RoonCommandLine Default ${media}[/cyan][/bold]" -p -a rounded -c -C
      }
      PS3="${BOLD}Please enter the ${media} you wish to set as default (numeric or text): ${NORMAL}"
      select opt in "${media_options[@]}"; do
        case "$opt,$REPLY" in
          "Set Defaults Menu"*,* | *,"Set Defaults Menu"* | "d",* | *,"d")
            break 2
            ;;
          "Main Menu"*,* | *,"Main Menu"* | "m",* | *,"m")
            main_menu
            break 3
            ;;
          "Quit"*,* | *,"Quit"* | "quit"*,* | *,"quit"* | "q",* | *,"q")
            farewell_exit "Exiting RoonCommandLine"
            ;;
          *,*)
            echo "${BOLD}Setting Roon ${media} default to: ${opt}${NORMAL}"
            if [ "${LOCAL}" = true ]; then
              ${setdefcom} "${opt}"
            else
              ssh ${user}@${server} "bash -l -c \"${ROON}/bin/${setdefcom} ${opt}\""
            fi
            break 2
            ;;
        esac
      done
    done
  fi
}

play_zone() {
  ${ROON}/bin/zone_command -c play -z "$1"
}

zone_info() {
  this_zone="$1"
  if [ "${have_rich}" ]; then
    rich "[red]Zone[/] [yellow]${this_zone}[/] [red]Groups With:[/]" -p
  else
    printf "\nZone '${this_zone}' Groups With:"
  fi
  ${ROON}/bin/get_zone_info -l -z "${this_zone}" | sed -e "s/,/\n    /g" -e "s/^/    /" \
    | while read l
    do
      if [ "${have_rich}" ]; then
        rich "     [yellow]$l[/]" -p
      else
        printf "\n\t$l"
      fi
    done
  if [ "${have_rich}" ]; then
    rich "[red]Zone Settings:[/]" -p
  else
    printf "\nZone Settings:\n"
  fi
  if [ "${have_jq}" ]; then
    ${ROON}/bin/get_zone_info -s -z "${this_zone}" | \
    jq -r 'to_entries[] | "\(.key)=\"\(.value)\""' | while read i
    do
      k=$(echo $i | awk -F '=' '{ print $1 }')
      v=$(echo $i | awk -F '=' '{ print $2 }')
      if [ "${have_rich}" ]; then
        rich "     [yellow]$k[/]: [cyan]$v[/]" -p
      else
        printf "\n\t$k: $v"
      fi
    done
  else
    ${ROON}/bin/get_zone_info -s -z "${this_zone}"
  fi
  show_now_playing "${this_zone}"
}

select_media() {
  media="$1"
  action="$2"
  [ "${action}" ] || action="Play"
  case "${media}" in
    Album)
      playcom="play_album"
      listcom="list_albums"
      details="list_album_tracks"
      ;;
    Artist)
      playcom="play_artist"
      listcom="list_artists"
      details="list_artist_albums"
      ;;
    Composer)
      playcom="play_composer"
      listcom="list_composers"
      details="list_composer_albums"
      ;;
    Genre)
      playcom="play_genre"
      listcom="list_genres"
      details="list_genre_artists"
      ;;
    Playlist)
      playcom="play_playlist"
      listcom="list_playlists"
      details="list_playlist_tracks"
      ;;
    Radio)
      playcom="play_radio"
      listcom="list_radio"
      details=
      ;;
    Tag)
      playcom="play_tag"
      listcom="list_tags"
      details=
      ;;
    Track)
      playcom="play_track"
      listcom="list_tracks"
      details=
      ;;
    Zone)
      playcom="play_zone"
      listcom="list_zones"
      details="zone_info"
      ;;
    *)
      return 1
      ;;
  esac
  printf "\nRetrieving ${media}s in your Roon library ..."
  if [ "${have_fzf}" ]; then
    media_options=("Main Menu" "Quit")
  else
    media_options=()
  fi
  ${IFS+"false"} && unset oldifs || oldifs="$IFS"
  IFS=$'\n'
  if [ "${LOCAL}" = true ]; then
    media_options+=($(${listcom} -q))
  else
    media_options+=($(ssh ${user}@${server} "bash -l -c \"${ROON}/bin/${listcom} -q\""))
  fi
  printf " Done\n\n"
  [ "${media}" == "Track" ] || {
    DEFAULT=$(get_default_ini Default${media})
    printf "Default ${media}: ${DEFAULT}\n\n"
  }

  ${oldifs+"false"} && unset IFS || IFS="$oldifs"
  if [ "${have_fzf}" ]; then
    while true; do
      heading "RoonCommandLine ${action} ${media}" "${action} ${media}"
      choice=$(printf "%s\n" "${media_options[@]}" | fzf -m --prompt=" 🎶 Select ${media} ('Main Menu' or 'Esc' to return, 'Quit' to exit)  " --height=18 --layout=reverse --exit-0)
      if [ "${choice}" ]; then
        case "${choice}" in
          "Quit"* | "quit"* | "Q" | "q")
            farewell_exit "Exiting RoonCommandLine"
            ;;
          "Main Menu"* | "main menu"*)
            main_menu
            break
            ;;
          *)
            heading "${action} ${media}: ${choice}" "${action} ${media}"
            if [ "${LOCAL}" == true ]; then
              if [ "${action}" == "List" ] || [ "${action}" == "list" ]; then
                [ "${details}" ] && {
                  ${details} "${choice}"
                  prompt_continue
                }
              else
                ${playcom} "${choice}"
                prompt_continue
              fi
            else
              if [ "${action}" == "List" ] || [ "${action}" == "list" ]; then
                [ "${details}" ] && {
                  ssh ${user}@${server} "bash -l -c \"${ROON}/bin/${details} ${choice}\""
                  prompt_continue
                }
              else
                ssh ${user}@${server} "bash -l -c \"${ROON}/bin/${playcom} ${choice}\""
              fi
            fi
            break
            ;;
        esac
      else
        break
      fi
    done
  else
    media_options+=("Main Menu    [m]")
    media_options+=("Quit         [q]")
    while true; do
      clear_screen
      [ "${have_rich}" ] && {
        rich "[bold][cyan]RoonCommandLine ${action} ${media}[/cyan][/bold]" -p -a rounded -c -C
      }
      PS3="${BOLD}Please enter the ${media} you wish to ${action} (numeric or text): ${NORMAL}"
      select opt in "${media_options[@]}"; do
        case "$opt,$REPLY" in
          "Main Menu"*,* | *,"Main Menu"* | "m",* | *,"m")
            main_menu
            break 2
            ;;
          "Quit"*,* | *,"Quit"* | "quit"*,* | *,"quit"* | "q",* | *,"q")
            farewell_exit "Exiting RoonCommandLine"
            ;;
          *,*)
            echo "${BOLD}${action} ${media}: ${opt}${NORMAL}"
            if [ "${LOCAL}" == true ]; then
              if [ "${action}" == "List" ] || [ "${action}" == "list" ]; then
                [ "${details}" ] && {
                  ${details} "${opt}"
                  prompt_continue
                }
              else
                ${playcom} "${opt}"
                prompt_continue
              fi
            else
              if [ "${action}" == "List" ] || [ "${action}" == "list" ]; then
                [ "${details}" ] && {
                  ssh ${user}@${server} "bash -l -c \"${ROON}/bin/${details} ${opt}\""
                  prompt_continue
                }
              else
                ssh ${user}@${server} "bash -l -c \"${ROON}/bin/${playcom} ${opt}\""
              fi
            fi
            break 2
            ;;
        esac
      done
    done
  fi
}

select_set_volume() {
  volume_options=()
  volume_options+=("Mute/Unmute Zone      [m]")
  volume_options+=("Mute/Unmute All Zones [M]")
  volume_options+=("Set Volume to 10" "Set Volume to 20" "Set Volume to 30" "Set Volume to 40" "Set Volume to 50" "Set Volume to 60" "Set Volume to 70" "Set Volume to 80" "Set Volume to 90" "Set Volume to 100" "Increase Volume by 1" "Increase Volume by 5" "Increase Volume by 10" "Increase Volume by 20" "Increase Volume by 40" "Decrease Volume by 1" "Decrease Volume by 5" "Decrease Volume by 10" "Decrease Volume by 20" "Decrease Volume by 40")
  volume_options+=("Main Menu             [r]")
  volume_options+=("Quit                  [q]")
  while true; do
    clear_screen
    [ "${have_rich}" ] && {
      rich "[bold][cyan]RoonCommandLine Volume Control[/cyan][/bold]" -p -a rounded -c -C
    }
    ${ROON}/bin/get_zone_volume
    printf "\n"
    PS3="${BOLD}Please enter the volume adjustment you wish to make (numeric or text): ${NORMAL}"
    select opt in "${volume_options[@]}"; do
      case "$opt,$REPLY" in
        "Set Volume to "*,* | *,"Set Volume to "*)
          volume=$(echo $opt | awk ' { print $NF } ')
          if [ "${LOCAL}" = true ]; then
            set_volume -v ${volume} -g
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/set_volume -v ${volume} -g\""
          fi
          break
          ;;
        "Increase Volume by "*,* | *,"Increase Volume by "*)
          volume=$(echo $opt | awk ' { print $NF } ')
          if [ "${LOCAL}" = true ]; then
            set_volume -v ${volume} -g -r
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/set_volume -v ${volume} -g -r\""
          fi
          break
          ;;
        "Decrease Volume by "*,* | *,"Decrease Volume by "*)
          volume=$(echo $opt | awk ' { print $NF } ')
          if [ "${LOCAL}" = true ]; then
            set_volume -v -${volume} -g -r
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/set_volume -v -${volume} -g -r\""
          fi
          break
          ;;
        "Mute/Unmute Zone"*,* | *,"Mute/Unmute Zone"* | "m",* | *,"m")
          printf "\nExecuting Roon command to toggle mute audio ..."
          if [ "${LOCAL}" = true ]; then
            ${ROON}/bin/zone_command -c mute
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c mute\""
          fi
          printf " Done\n\n"
          break
          ;;
        "Mute/Unmute All Zones"*,* | *,"Mute/Unmute All Zones"* | "M",* | *,"M")
          printf "\nExecuting Roon command to toggle mute in all zones ..."
          if [ "${LOCAL}" = true ]; then
            ${ROON}/bin/zone_command -c mute_all
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c mute_all\""
          fi
          printf " Done\n\n"
          break
          ;;
        "Main Menu"*,* | *,"Main Menu"* | "r",* | *,"r")
          main_menu
          break 2
          ;;
        "Quit"*,* | *,"Quit"* | "quit"*,* | *,"quit"* | "q",* | *,"q")
          farewell_exit "Exiting RoonCommandLine"
          ;;
      esac
    done
  done
}

list_defaults() {
  defaults_options=()
  defaults_options+=("Set Default Album    [a]")
  defaults_options+=("Set Default Artist   [A]")
  defaults_options+=("Set Default Composer [c]")
  defaults_options+=("Set Default Genre    [g]")
  defaults_options+=("Set Default Playlist [p]")
  defaults_options+=("Set Default Radio    [r]")
  defaults_options+=("Set Default Tag      [t]")
  defaults_options+=("Set Default Zone     [z]")
  defaults_options+=("Main Menu            [m]")
  defaults_options+=("Quit                 [q]")
  while true; do
    clear_screen
    [ "${have_rich}" ] && {
      rich "[bold][cyan]RoonCommandLine Defaults Menu[/cyan][/bold]" -p -a rounded -c -C
    }
    show_info brief
    printf "\n"
    PS3="${BOLD}Please enter the default you wish to set (numeric or text): ${NORMAL}"
    select opt in "${defaults_options[@]}"; do
      case "$opt,$REPLY" in
        "Main Menu"*,* | *,"Main Menu"* | "m",* | *,"m")
          main_menu
          break 2
          ;;
        "Quit"*,* | *,"Quit"* | "quit"*,* | *,"quit"* | "q",* | *,"q")
          farewell_exit "Exiting RoonCommandLine"
          ;;
        "Set Default Album"*,* | *,"Set Default Album"* | "a",* | *,"a")
          select_default Album
          break
          ;;
        "Set Default Artist"*,* | *,"Set Default Artist"* | "A",* | *,"A")
          select_default Artist
          break
          ;;
        "Set Default Composer"*,* | *,"Set Default Composer"* | "c",* | *,"c")
          select_default Composer
          break
          ;;
        "Set Default Genre"*,* | *,"Set Default Genre"* | "g",* | *,"g")
          select_default Genre
          break
          ;;
        "Set Default Playlist"*,* | *,"Set Default Playlist"* | "p",* | *,"p")
          select_default Playlist
          break
          ;;
        "Set Default Radio"*,* | *,"Set Default Radio"* | "r",* | *,"r")
          select_default Radio
          break
          ;;
        "Set Default Tag"*,* | *,"Set Default Tag"* | "t",* | *,"t")
          select_default Tag
          break
          ;;
        "Set Default Zone"*,* | *,"Set Default Zone"* | "z",* | *,"z")
          select_default Zone
          break
          ;;
      esac
    done
  done
}

main_menu() {
  noexit=1
  while true; do
    clear_screen
    media_options=()
    [ "${have_rich}" ] && {
      rich "[bold][cyan]RoonCommandLine Main Menu[/cyan][/bold]" -p -a rounded -c -C
    }
    PS3="${BOLD}Please enter your Roon command choice (numeric, shortcut, or text): ${NORMAL}"
    options=("Get/Set Defaults [g]")
    options+=("Get/Set Zone     [z]")
    options+=("Play             [p]")
    options+=("Play All         [A]")
    options+=("Pause            [P]")
    options+=("Pause All       [Pa]")
    options+=("Next Track       [n]")
    options+=("Previous Track  [pt]")
    options+=("Stop             [x]")
    options+=("Stop All         [X]")
    options+=("Toggle Mute      [m]")
    options+=("Toggle Mute All  [M]")
    options+=("Disable Repeat   [R]")
    options+=("Enable Repeat    [r]")
    options+=("Disable Shuffle  [S]")
    options+=("Enable Shuffle   [s]")
    options+=("List Albums     [la]")
    options+=("List Artists    [lA]")
    options+=("List Composers  [lc]")
    options+=("List Genres     [lg]")
    options+=("List Playlists  [lp]")
    options+=("List Radio      [lr]")
    options+=("List Tags       [lt]")
    options+=("List Tracks     [lT]")
    options+=("List Zones      [lz]")
    options+=("Select Album    [sa]")
    options+=("Select Artist   [sA]")
    options+=("Select Composer [sc]")
    options+=("Select Genre    [sg]")
    options+=("Select Radio    [sr]")
    options+=("Select Playlist [sp]")
    options+=("Select Tag      [st]")
    options+=("Select Track    [sT]")
    options+=("Select Zone     [sz]")
    options+=("Play Album      [pa]")
    options+=("Play Artist     [pA]")
    options+=("Play Composer   [pc]")
    options+=("Play Genre      [pg]")
    options+=("Play Radio      [pr]")
    options+=("Play Playlist   [pp]")
    options+=("Play Tag        [pt]")
    options+=("Play Zone       [pz]")
    options+=("Fade Menu        [f]")
    options+=("Volume           [v]")

    have_fzf=$(type -p fzf)
    if [ "${have_fzf}" ]; then
      options+=("Now Playing      [N]")
      [ "${update_fzf}" ] && {
        options+=("Upgrade Fzf -> ${fzf_release_version}")
      }
    else
      [ -x ${ROONETC}/install-fzf ] && options+=("Install fzf")
    fi
    [ "${have_flat}" ] && {
      if [ "${have_gui}" ]; then
        options+=("Open Roon GUI    [G]")
        [ "${update_gui}" ] && {
          options+=("Upgrade GUI -> ${gui_release_version}")
        }
      else
        [ -x ${ROONETC}/install-roon-gui ] && options+=("Install Roon GUI [G]")
      fi
    }
    have_tui=$(type -p roon-tui)
    if [ "${have_tui}" ]; then
      options+=("Open Roon TUI    [T]")
      [ "${update_tui}" ] && {
        options+=("Upgrade TUI -> ${tui_release_version}")
      }
    else
      [ -x ${ROONETC}/install-roon-tui ] && options+=("Install Roon TUI [T]")
    fi
    options+=("Zone Info        [Z]" "About            [a]" "Examples         [e]")
    options+=("Info             [i]" "Usage            [u]" "Quit             [q]")

    select opt in "${options[@]}"; do
      case "$opt,$REPLY" in
        "Get/Set Defaults"*,* | *,"Get/Set Defaults"* | "g",* | *,"g")
          list_defaults
          break
          ;;
        "Get/Set Zone"*,* | *,"Get/Set Zone"* | "z",* | *,"z")
          [ -f ${ROONCONF} ] && . ${ROONCONF}
          if [ "${LOCAL}" = true ]; then
            if [ "${ROON_ZONE}" ]; then
              echo "Current Roon Zone: ${ROON_ZONE}"
            else
              echo "No default Roon Zone is set in ${ROONCONF}"
            fi
          else
            roon_zone=$(ssh ${user}@${server} "bash -l -c \"grep ROON_ZONE ${ROONCONF}\"")
            if [ "${roon_zone}" ]; then
              echo "Current Roon Zone: ${roon_zone}"
            else
              echo "No default Roon Zone is set in ${ROONCONF}"
            fi
          fi
          select_zone
          break
          ;;
        "Play All"*,* | *,"Play All"* | "A",* | *,"A")
          printf "\nExecuting Roon command to play in all zones ..."
          if [ "${LOCAL}" = true ]; then
            ${ROON}/bin/zone_command -c play_all
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c play_all\""
          fi
          printf " Done\n\n"
          break
          ;;
        "Pause All"*,* | *,"Pause All"* | "Pa",* | *,"Pa")
          printf "\nExecuting Roon command to pause play in all zones ..."
          if [ "${LOCAL}" = true ]; then
            ${ROON}/bin/zone_command -c pause_all
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c pause_all\""
          fi
          printf " Done\n\n"
          break
          ;;
        "Pause"*,* | *,"Pause"* | "P",* | *,"P")
          printf "\nExecuting Roon command to pause play ..."
          if [ "${LOCAL}" = true ]; then
            ${ROON}/bin/zone_command -c pause
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c pause\""
          fi
          printf " Done\n\n"
          break
          ;;
        "Next Track"*,* | *,"Next Track"* | "n",* | *,"n")
          printf "\nExecuting Roon command to play next track ..."
          if [ "${LOCAL}" = true ]; then
            ${ROON}/bin/zone_command -c next
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c next\""
          fi
          printf " Done\n\n"
          break
          ;;
        "Previous Track"*,* | *,"Previous Track"* | "pt",* | *,"pt")
          printf "\nExecuting Roon command to play previous track ..."
          if [ "${LOCAL}" = true ]; then
            ${ROON}/bin/zone_command -c previous
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c previous\""
          fi
          printf " Done\n\n"
          break
          ;;
        "Stop All"*,* | *,"Stop All"* | "X",* | *,"X")
          printf "\nExecuting Roon command to stop in all zones ..."
          if [ "${LOCAL}" = true ]; then
            ${ROON}/bin/zone_command -c stop_all
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c stop_all\""
          fi
          printf " Done\n\n"
          break
          ;;
        "Stop"*,* | *,"Stop"* | "x",* | *,"x")
          printf "\nExecuting Roon command to stop ..."
          if [ "${LOCAL}" = true ]; then
            ${ROON}/bin/zone_command -c stop
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c stop\""
          fi
          printf " Done\n\n"
          break
          ;;
        "Fade Menu"*,* | *,"Fade Menu"* | "f",* | *,"f")
          exec roon_fade -i
          break
          ;;
        "Toggle Mute"*,* | *,"Toggle Mute"* | "m",* | *,"m")
          printf "\nExecuting Roon command to toggle mute audio ..."
          if [ "${LOCAL}" = true ]; then
            ${ROON}/bin/zone_command -c mute
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c mute\""
          fi
          printf " Done\n\n"
          break
          ;;
        "Toggle Mute All"*,* | *,"Toggle Mute All"* | "M",* | *,"M")
          printf "\nExecuting Roon command to toggle mute in all zones ..."
          if [ "${LOCAL}" = true ]; then
            ${ROON}/bin/zone_command -c mute_all
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c mute_all\""
          fi
          printf " Done\n\n"
          break
          ;;
        "Disable Repeat"*,* | *,"Disable Repeat"* | "R",* | *,"R")
          printf "\nExecuting Roon command to disable repeat ..."
          if [ "${LOCAL}" = true ]; then
            ${ROON}/bin/zone_command -c unrepeat
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c unrepeat\""
          fi
          printf " Done\n\n"
          break
          ;;
        "Enable Repeat"*,* | *,"Enable Repeat"* | "r",* | *,"r")
          printf "\nExecuting Roon command to enable repeat ..."
          if [ "${LOCAL}" = true ]; then
            ${ROON}/bin/zone_command -c repeat
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c repeat\""
          fi
          printf " Done\n\n"
          break
          ;;
        "Disable Shuffle"*,* | *,"Disable Shuffle"* | "S",* | *,"S")
          printf "\nExecuting Roon command to disable shuffle ..."
          if [ "${LOCAL}" = true ]; then
            ${ROON}/bin/zone_command -c unshuffle
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c unshuffle\""
          fi
          printf " Done\n\n"
          break
          ;;
        "Enable Shuffle"*,* | *,"Enable Shuffle"* | "s",* | *,"s")
          printf "\nExecuting Roon command to enable shuffle ..."
          if [ "${LOCAL}" = true ]; then
            ${ROON}/bin/zone_command -c shuffle
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c shuffle\""
          fi
          printf " Done\n\n"
          break
          ;;
        "List Albums"*,* | *,"List Albums"* | "la",* | *,"la")
          select_media Album List
          break
          ;;
        "List Artists"*,* | *,"List Artists"* | "lA",* | *,"lA")
          select_media Artist List
          break
          ;;
        "List Composers"*,* | *,"List Composers"* | "lc",* | *,"lc")
          select_media Composer List
          break
          ;;
        "List Genres"*,* | *,"List Genres"* | "lg",* | *,"lg")
          select_media Genre List
          break
          ;;
        "List Playlists"*,* | *,"List Playlists"* | "lp",* | *,"lp")
          select_media Playlist List
          break
          ;;
        "List Radio"*,* | *,"List Radio"* | "lr",* | *,"lr")
          select_media Radio List
          break
          ;;
        "List Tags"*,* | *,"List Tags"* | "lt",* | *,"lt")
          select_media Tag List
          break
          ;;
        "List Tracks"*,* | *,"List Tracks"* | "lT",* | *,"lT")
          select_media Track List
          break
          ;;
        "List Zones"*,* | *,"List Zones"* | "lz",* | *,"lz")
          select_media Zone List
          break
          ;;
        "Select Album"*,* | *,"Select Album"* | "sa",* | *,"sa")
          select_media Album
          break
          ;;
        "Select Artist"*,* | *,"Select Artist"* | "sA",* | *,"sA")
          select_media Artist
          break
          ;;
        "Select Composer"*,* | *,"Select Composer"* | "sc",* | *,"sc")
          select_media Composer
          break
          ;;
        "Select Genre"*,* | *,"Select Genre"* | "sg",* | *,"sg")
          select_media Genre
          break
          ;;
        "Select Playlist"*,* | *,"Select Playlist"* | "sp",* | *,"sp")
          select_media Playlist
          break
          ;;
        "Select Radio"*,* | *,"Select Radio"* | "sr",* | *,"sr")
          select_media Radio
          break
          ;;
        "Select Tag"*,* | *,"Select Tag"* | "st",* | *,"st")
          select_media Tag
          break
          ;;
        "Select Track"*,* | *,"Select Track"* | "sT",* | *,"sT")
          select_media Track
          break
          ;;
        "Select Zone"*,* | *,"Select Zone"* | "sz",* | *,"sz")
          select_media Zone
          break
          ;;
        "Play Album"*,* | *,"Play Album"* | "pa",* | *,"pa")
          if [ "${LOCAL}" = true ]; then
            play_album
            prompt_continue
          else
            ssh ${user}@${server} "bash -l -c ${ROON}/bin/play_album"
          fi
          break
          ;;
        "Play Artist"*,* | *,"Play Artist"* | "pA",* | *,"pA")
          if [ "${LOCAL}" = true ]; then
            play_artist
            prompt_continue
          else
            ssh ${user}@${server} "bash -l -c ${ROON}/bin/play_artist"
          fi
          break
          ;;
        "Play Composer"*,* | *,"Play Composer"* | "pc",* | *,"pc")
          if [ "${LOCAL}" = true ]; then
            play_composer
            prompt_continue
          else
            ssh ${user}@${server} "bash -l -c ${ROON}/bin/play_composer"
          fi
          break
          ;;
        "Play Genre"*,* | *,"Play Genre"* | "pg",* | *,"pg")
          if [ "${LOCAL}" = true ]; then
            play_genre
            prompt_continue
          else
            ssh ${user}@${server} "bash -l -c ${ROON}/bin/play_genre"
          fi
          break
          ;;
        "Play Playlist"*,* | *,"Play Playlist"* | "pp",* | *,"pp")
          if [ "${LOCAL}" = true ]; then
            play_playlist
            prompt_continue
          else
            ssh ${user}@${server} "bash -l -c ${ROON}/bin/play_playlist"
          fi
          break
          ;;
        "Play Radio"*,* | *,"Play Radio"* | "pr",* | *,"pr")
          if [ "${LOCAL}" = true ]; then
            play_radio
            prompt_continue
          else
            ssh ${user}@${server} "bash -l -c ${ROON}/bin/play_radio"
          fi
          break
          ;;
        "Play Tag"*,* | *,"Play Tag"* | "pt",* | *,"pt")
          if [ "${LOCAL}" = true ]; then
            play_tag
            prompt_continue
          else
            ssh ${user}@${server} "bash -l -c ${ROON}/bin/play_tag"
          fi
          break
          ;;
        "Play Zone"*,* | *,"Play Zone"* | "pz",* | *,"pz")
          ${ROON}/bin/zone_command -c play
          prompt_continue
          break
          ;;
        "Play"*,* | *,"Play"* | "p",* | *,"p")
          printf "\nExecuting Roon command to play ..."
          if [ "${LOCAL}" = true ]; then
            ${ROON}/bin/zone_command -c play
            prompt_continue
          else
            ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c play\""
          fi
          printf " Done\n\n"
          break
          ;;
        "Volume"*,* | *,"Volume"* | "v",* | *,"v")
          select_set_volume
          break
          ;;
        "Now Playing"*,* | *,"Now Playing"* | "N",* | *,"N")
          heading "Roon Now Playing" "Now Playing"
          show_now_playing
          prompt_continue
          break
          ;;
        "Open Roon GUI"*,* | *,"Open Roon GUI"* | "G",* | *,"G")
          if [ "${have_gui}" ]; then
            roongui
          else
            install_roon_gui
          fi
          break
          ;;
        "Install Roon GUI"*,* | *,"Install Roon GUI"* | "G",* | *,"G")
          install_roon_gui
          break
          ;;
        "Upgrade GUI"*,* | *,"Upgrade GUI"*)
          flatpak update -y --noninteractive com.theappgineer.community_remote
          set_gui_release
          break
          ;;
        "Open Roon TUI"*,* | *,"Open Roon TUI"* | "T",* | *,"T")
          if [ "${have_tui}" ]; then
            roontui
          else
            install_roon_tui
          fi
          break
          ;;
        "Install Roon TUI"*,* | *,"Install Roon TUI"* | "T",* | *,"T")
          install_roon_tui
          break
          ;;
        "Upgrade TUI"*,* | *,"Upgrade TUI"*)
          ${ROON}/etc/install-roon-tui
          set_tui_release
          break
          ;;
        "Upgrade Fzf"*,* | *,"Upgrade Fzf"* | "upgrade fzf"*,* | *,"upgrade fzf"*)
          upgrade_fzf
          set_fzf_release
          break
          ;;
        "About"*,* | *,"About"* | "about"*,* | *,"about"* | "a",* | *,"a")
          show_about
          prompt_continue
          break
          ;;
        "Example"*,* | *,"Example"* | "example"*,* | *,"example"* | "e",* | *,"e")
          showusage=
          showexamples=1
          usage
          prompt_continue
          break
          ;;
        "Info"*,* | *,"Info"* | "info"*,* | *,"info"* | "i",* | *,"i")
          show_info
          prompt_continue
          break
          ;;
        "Zone Info"*,* | *,"Zone Info"* | "zone info"*,* | *,"zone info"* | "Z",* | *,"Z")
          infozone=$(get_default_ini DefaultZone)
          heading "Roon Zone $infozone" "$infozone"
          zone_info "$infozone"
          prompt_continue
          break
          ;;
        "Usage"*,* | *,"Usage"* | "usage"*,* | *,"usage"* | "u",* | *,"u")
          showusage=1
          showexamples=
          usage
          prompt_continue
          break
          ;;
        "Quit"*,* | *,"Quit"* | "quit"*,* | *,"quit"* | "q",* | *,"q")
          farewell_exit "Exiting RoonCommandLine"
          ;;
        *,*)
          printf "\n\tUnrecognized menu selection: ${opt} ${REPLY}"
          printf "\n\tPlease enter either the exact text, shortcut, or"
          printf "\n\tnumeric designation for one of the listed options.\n"
          prompt_continue
          break
          ;;
      esac
    done
  done
}

set_have_gui
debug=
info=
fading=
logfade=
now_playing=
inst_roon_gui=
open_roon_gui=
inst_roon_tui=
open_roon_tui=
skip_anim=
while getopts A:a:bBc:C:dD:f:F:g:G:hHiImnNOp:T:t:z:l:s:LSr:v:x:X:EuU flag; do
  case $flag in
    A)
      album="$OPTARG"
      ;;
    a)
      artist="$OPTARG"
      ;;
    B)
      inst_roon_gui=1
      ;;
    b)
      [ -x ${ROON}/bin/roongui ] && open_roon_gui=1
      ;;
    c)
      comm="$OPTARG"
      ;;
    C)
      composer="$OPTARG"
      ;;
    d)
      debug=1
      ;;
    D)
      dest_zone="$OPTARG"
      ;;
    F)
      from_zone="$OPTARG"
      ;;
    f)
      fading="$OPTARG"
      case ${fading} in
        On | ON | on)
          fading="on"
          ;;
        Onlog | ONLOG | OnLog | onlog)
          fading="on"
          logfade="-l"
          ;;
        Off | OFF | off)
          fading="off"
          ;;
        Stat* | stat*)
          fading="status"
          ;;
        *)
          echo "Unsupported -f argument: ${fading}"
          echo "No fading will be enabled or disabled"
          fading=
          ;;
      esac
      ;;
    g)
      genre="$OPTARG"
      ;;
    i)
      info=1
      ;;
    I)
      inst_roon_tui=1
      ;;
    m)
      show_roon_menu=1
      skip_anim=1
      ;;
    N)
      now_playing=1
      nowarg="-a"
      ;;
    n)
      now_playing=1
      nowarg=
      ;;
    O)
      [ -x ${ROON}/bin/roontui ] && open_roon_tui=1
      ;;
    p)
      playlist="$OPTARG"
      ;;
    T)
      track="$OPTARG"
      ;;
    t)
      tag="$OPTARG"
      ;;
    z)
      zone="$OPTARG"
      # Support '-z default' and '-z last'
      if [ "${zone}" == "default" ]; then
        zone=$(get_default_ini DefaultZone)
      else
        [ "${zone}" == "last" ] && {
          if [ "${ROON_ZONE}" ]; then
            zone="${ROON_ZONE}"
          else
            zone=$(get_default_ini DefaultZone)
          fi
        }
      fi
      ;;
    l)
      listname="$OPTARG"
      if [ "$listname" == "albums" ] || [ "$listname" == "album" ]; then
        albumlist=1
      elif [ "$listname" == "artists" ] || [ "$listname" == "artist" ]; then
        artistlist=1
      elif [ "$listname" == "artalbums" ] || [ "$listname" == "artalbum" ]; then
        artalbumlist=1
      elif [ "$listname" == "albtracks" ] || [ "$listname" == "albtrack" ]; then
        albtracklist=1
      elif [ "$listname" == "arttracks" ] || [ "$listname" == "arttrack" ]; then
        arttracklist=1
      elif [ "$listname" == "playtracks" ] || [ "$listname" == "playtrack" ]; then
        playtracklist=1
      elif [ "$listname" == "composers" ] || [ "$listname" == "composer" ]; then
        composerlist=1
      elif [ "$listname" == "comalbums" ] || [ "$listname" == "comalbum" ]; then
        comalbumlist=1
      elif [ "$listname" == "genres" ] || [ "$listname" == "genre" ]; then
        genrelist=1
      elif [ "$listname" == "genalbums" ] || [ "$listname" == "genalbum" ]; then
        genalbumlist=1
      elif [ "$listname" == "genartists" ] || [ "$listname" == "genartist" ]; then
        genartistlist=1
      elif [ "$listname" == "playlists" ] || [ "$listname" == "playlist" ]; then
        playlistlist=1
      elif [ "$listname" == "stations" ] || [ "$listname" == "radio" ]; then
        radiolist=1
      elif [ "$listname" == "tags" ] || [ "$listname" == "tag" ]; then
        taglist=1
      elif [ "$listname" == "zones" ] || [ "$listname" == "zone" ]; then
        zonelist=1
      else
        echo "Unknown list type: $listname"
        usage
      fi

      ;;
    G)
      zonegroup="$OPTARG"
      ;;
    L)
      if [ -f ${ROONCONF} ]; then
        grep -v ^LOCAL= ${ROONCONF} >/tmp/roon$$
        echo "LOCAL=true" >>/tmp/roon$$
        cp /tmp/roon$$ ${ROONCONF}
        rm -f /tmp/roon$$
        . ${ROONCONF}
      else
        echo "${ROONCONF} does not exist"
        echo "RoonCommandLine is not installed locally"
      fi
      ;;
    r)
      radio="$OPTARG"
      ;;
    s)
      search="$OPTARG"
      ;;
    S)
      setdefs=1
      ;;
    v)
      # The volume argument has the format [g:][r:][s:]num
      # Where 'g' indicates set volume for all zones in the group
      # 'r' specifies use relative method volume setting
      # 's' specifies use relative_step method volume setting
      # 'num' can be absolute, relative, and negative or positive
      volume=$OPTARG
      grouped=
      relative=
      step=
      need_num=1
      while [ "${need_num}" ]; do
        first_two=${volume:0:2}
        case "${first_two}" in
          g:)
            grouped="-g"
            volume=${volume:2}
            ;;
          r:)
            relative="-r"
            volume=${volume:2}
            ;;
          s:)
            step="-s"
            volume=${volume:2}
            ;;
          *)
            need_num=
            ;;
        esac
      done
      ;;
    X)
      exalbum="$OPTARG"
      ;;
    x)
      exartist="$OPTARG"
      ;;
    E)
      showusage=
      showexamples=1
      usage
      ;;
    h)
      have_rich=
      showusage=1
      showexamples=
      usage
      ;;
    H)
      have_rich=
      showusage=1
      showexamples=1
      usage
      ;;
    U)
      showusage=1
      showexamples=
      usage
      ;;
    *)
      usage
      ;;
  esac
done

[ "${comm}" == "discover" ] && {
  if [ -x ${ROONETC}/discover ]; then
    ${ROONETC}/discover
    exit 0
  else
    echo "ERROR: ${ROONETC}/discover not found or not executable. Reinstall."
    exit 1
  fi
}

[ "${inst_roon_gui}" ] && {
  [ -x ${ROON}/etc/install-roon-gui ] && ${ROON}/etc/install-roon-gui
  if [ -x ${ROON}/bin/roongui ]; then
    ${ROON}/bin/roongui
    echo ""
    farewell_exit "Successful installation of Roon GUI"
  else
    echo "Installation of Roon GUI failed or unable to locate $ROON/bin/roongui"
    echo "Exiting"
    exit 1
  fi
}
[ "${inst_roon_tui}" ] && {
  [ -x ${ROON}/etc/install-roon-tui ] && ${ROON}/etc/install-roon-tui
  if [ -x ${ROON}/bin/roontui ]; then
    ${ROON}/bin/roontui
    echo ""
    farewell_exit "Successful installation of Roon TUI"
  else
    echo "Installation of Roon TUI failed or unable to locate $ROON/bin/roontui"
    echo "Exiting"
    exit 1
  fi
}

[ "${nowarg}" ] || {
  [ "${zone}" ] || {
    if [ "${ROON_ZONE}" ]; then
      zone="${ROON_ZONE}"
    else
      zone=$(get_default_ini DefaultZone)
    fi
  }
}
[ "${search}" ] || search="__all__"

# Set Defaults
[ "${setdefs}" ] && list_defaults

# Set Zone
[ "${zone}" ] && {
  if [ "${LOCAL}" = true ]; then
    ${ROON}/bin/set_zone ${zone}
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/set_zone ${zone}\""
  fi
  status=$?
  [ ${status} -eq 0 ] || {
    echo "Unable to set zone for zone = ${zone}"
    echo "Exiting"
    exit ${status}
  }
  [ -f ${ROONCONF} ] && . ${ROONCONF}
}

# Zone Grouping
[ "${zonegroup}" ] && {
  [ "${comm}" == "group" ] || [ "${comm}" == "ungroup" ] || comm=group
  if [ "${LOCAL}" = true ]; then
    ${ROON}/bin/set_zone_group ${comm} ${zonegroup}
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/set_zone_group ${comm} ${zonegroup}\""
  fi
  status=$?
  [ ${status} -eq 0 ] || {
    echo "Unable to set zone group for zone group = ${zonegroup}"
    echo "Exiting"
    exit ${status}
  }
}

[ "${info}" ] && {
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      zone_info "${zone}"
    else
      infozone=$(get_default_ini DefaultZone)
      zone_info "$infozone"
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/get_zone_info -z ${zone}\""
    else
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/get_zone_info\""
    fi
  fi
}

# Transfer Zone
[ "$dest_zone" ] && {
  [ "$from_zone" ] || from_zone="${ROON_ZONE}"
  if [ "${LOCAL}" = true ]; then
    ${ROON}/bin/transfer_zone "$from_zone" "$dest_zone"
  else
    ssh ${user}@${server} bash -l -c "${ROON}/bin/transfer_zone \"$from_zone\" \"$dest_zone\""
  fi
  status=$?
  [ ${status} -eq 0 ] || {
    echo "Unable to transfer zone to zone = $dest_zone"
  }
}

[ "${fading}" ] && {
  [ "${fading}" == "status" ] && fading=
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      ${ROON}/bin/roon_fade ${logfade} -z "${zone}" ${fading}
    else
      ${ROON}/bin/roon_fade ${logfade} ${fading}
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} \
        "bash -l -c \"${ROON}/bin/roon_fade ${logfade} -z ${zone} ${fading}\""
    else
      ssh ${user}@${server} \
        "bash -l -c \"${ROON}/bin/roon_fade ${logfade} ${fading}\""
    fi
  fi
}

[ "$now_playing" ] && show_now_playing "${zone}" "${nowarg}"

[ "$albumlist" ] && {
  [ "$album" ] || {
    [ "$search" ] && album="$search"
  }
  [ "$album" ] || album="__all__"
  if [ "${LOCAL}" = true ]; then
    list_albums "$album" "$exalbum"
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/list_albums $album $exalbum\""
  fi
  album=
}
[ "$artistlist" ] && {
  [ "$artist" ] || {
    [ "$search" ] && artist="$search"
  }
  [ "$artist" ] || artist="__all__"
  if [ "${LOCAL}" = true ]; then
    list_artists "$artist" "$exartist"
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/list_artists $artist $exartist\""
  fi
  artist=
}
[ "$artalbumlist" ] && {
  [ "$artist" ] || {
    [ "$search" ] && artist=$search
  }
  [ "$album" ] || album="__all__"
  [ "${exalbum}" ] && {
    [ "${exartist}" ] || exartist="None"
  }
  if [ "${LOCAL}" = true ]; then
    list_artist_albums "$artist" "$album" "$exartist" "$exalbum"
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/list_artist_albums $artist $album $exartist $exalbum\""
  fi
  album=
  artist=
}
[ "$albtracklist" ] && {
  [ "$album" ] || {
    [ "$search" ] && album=$search
  }
  [ "$track" ] || track="__all__"
  if [ "${LOCAL}" = true ]; then
    list_album_tracks "$album" "$track" "$exalbum" "$extrack"
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/list_album_tracks $album $track $exalbum $extrack\""
  fi
  track=
  album=
}
[ "$arttracklist" ] && {
  [ "$artist" ] || {
    [ "$search" ] && artist=$search
  }
  [ "$track" ] || track="__all__"
  [ "${exalbum}" ] && {
    [ "${exartist}" ] || exartist="None"
  }
  if [ "${LOCAL}" = true ]; then
    list_artist_tracks "$artist" "$track" "$exartist" "$exalbum"
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/list_artist_tracks $artist $track $exartist $exalbum\""
  fi
  track=
  artist=
}
[ "$playtracklist" ] && {
  [ "$playlist" ] || {
    [ "$search" ] && playlist=$search
  }
  [ "$track" ] || track="__all__"
  [ "${extrack}" ] && {
    [ "${explaylist}" ] || explaylist="None"
  }
  if [ "${LOCAL}" = true ]; then
    list_playlist_tracks "$playlist" "$track" "$explaylist" "$extrack"
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/list_playlist_tracks $playlist $track $explaylist $extrack\""
  fi
  track=
  playlist=
}
[ "$comalbumlist" ] && {
  [ "$composer" ] || {
    [ "$search" ] && composer=$search
  }
  [ "$album" ] || album="__all__"
  [ "${exalbum}" ] && {
    [ "${exartist}" ] || exartist="None"
  }
  if [ "${LOCAL}" = true ]; then
    list_composer_albums "$composer" "$album" "$exartist" "$exalbum"
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/list_composer_albums $composer $album $exartist $exalbum\""
  fi
  album=
  composer=
}
[ "$composerlist" ] && {
  [ "$composer" ] || {
    [ "$search" ] && composer="$search"
  }
  [ "$composer" ] || composer="__all__"
  if [ "${LOCAL}" = true ]; then
    list_composers "$composer" "$exartist"
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/list_composers $composer $exartist\""
  fi
  composer=
}
[ "$genrelist" ] && {
  [ "$genre" ] || {
    [ "$search" ] && genre="$search"
  }
  [ "$genre" ] || genre="__all__"
  if [ "${LOCAL}" = true ]; then
    list_genres "$genre" "$exalbum"
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/list_genres $genre $exalbum\""
  fi
  genre=
}
[ "$genalbumlist" ] && {
  [ "$album" ] || album="__all__"
  [ "${exalbum}" ] && {
    [ "${exartist}" ] || exartist="None"
  }
  if [ "${LOCAL}" = true ]; then
    list_genre_albums "$genre" "$album" "$exartist" "$exalbum"
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/list_genre_albums $genre $album $exartist $exalbum\""
  fi
  album=
  genre=
}
[ "$genartistlist" ] && {
  [ "$genre" ] || {
    [ "$search" ] && genre=$search
  }
  [ "${exalbum}" ] && {
    [ "${exartist}" ] || exartist="None"
  }
  if [ "${LOCAL}" = true ]; then
    list_genre_artists "$genre" "$artist" "$exartist" "$exalbum"
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/list_genre_artists $genre $artist $exartist $exalbum\""
  fi
  artist=
  genre=
}
[ "$playlistlist" ] && {
  [ "$playlist" ] || {
    [ "$search" ] && playlist="$search"
  }
  if [ "${LOCAL}" = true ]; then
    list_playlists $playlist "$exartist"
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/list_playlists $playlist $exartist\""
  fi
  playlist=
}
[ "$radiolist" ] && {
  if [ "${LOCAL}" = true ]; then
    list_radio $search
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/list_radio $search\""
  fi
}
[ "$taglist" ] && {
  if [ "${LOCAL}" = true ]; then
    list_tags $search
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/list_tags $search\""
  fi
}
[ "$zonelist" ] && {
  if [ "${LOCAL}" = true ]; then
    list_zones $search
  else
    ssh ${user}@${server} "bash -l -c \"${ROON}/bin/list_zones $search\""
  fi
}

# Issue commands before playback begins
[ "${comm}" ] && {
  case "${comm}" in
    "shuffle" | "unshuffle" | "repeat" | "unrepeat" | "mute" | "unmute" | "mute_all" | "next" | "previous" | "play" | "play_all" | "pause" | "pause_all" | "stop" | "stop_all" | "playpause")
      if [ "${LOCAL}" = true ]; then
        if [ "${zone}" ]; then
          ${ROON}/bin/zone_command -c ${comm} -z "${zone}"
        else
          ${ROON}/bin/zone_command -c ${comm}
        fi
      else
        if [ "${zone}" ]; then
          ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c ${comm} -z ${zone}\""
        else
          ssh ${user}@${server} "bash -l -c \"${ROON}/bin/zone_command -c ${comm}\""
        fi
      fi
      ;;
    "group" | "ungroup") ;;
    *)
      echo "Unrecognized Roon command: $comm"
      usage
      ;;
  esac
}

# Shuffle action only supported in Artist, Genre, and Playlist playback for now
shuffled=
[ "${comm}" == "shuffle" ] && shuffled="-s"

# Handle album and artist requested
[ "$album" ] && [ "$artist" ] && {
  [ "${album}" == "default" ] && album=$(get_default_ini DefaultAlbum)
  [ "${artist}" == "default" ] && artist=$(get_default_ini DefaultArtist)
  printf "\nSearching for album and artist: \"$album\" and \"$artist\"\n"
  [ "${exalbum}" ] && {
    [ "${exartist}" ] || exartist="None"
  }
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      play_artist_album -z "${zone}" "$artist" "$album" "$exartist" "$exalbum"
    else
      play_artist_album "$artist" "$album" "$exartist" "$exalbum"
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_artist_album -z ${zone} $artist $album $exartist $exalbum\""
    else
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_artist_album $artist $album $exartist $exalbum\""
    fi
  fi
  album=
  artist=
}
# Handle album and track requested
[ "$track" ] && [ "$album" ] && {
  [ "${album}" == "default" ] && album=$(get_default_ini DefaultAlbum)
  printf "\nSearching for album and track: \"$album\" and \"$track\"\n"
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      play_album_track -z "${zone}" "$album" "$track"
    else
      play_album_track "$album" "$track"
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_album_track -z ${zone} $album $track\""
    else
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_album_track $album $track\""
    fi
  fi
  album=
  track=
}
# Handle artist and track requested
[ "$track" ] && [ "$artist" ] && {
  [ "${artist}" == "default" ] && artist=$(get_default_ini DefaultArtist)
  printf "\nSearching for artist and track: \"$artist\" and \"$track\"\n"
  [ "${exalbum}" ] && {
    [ "${exartist}" ] || exartist="None"
  }
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      play_artist_track -z "${zone}" "$artist" "$track" "$exartist" "$exalbum"
    else
      play_artist_track "$artist" "$track" "$exartist" "$exalbum"
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_artist_track -z ${zone} $artist $track $exartist $exalbum\""
    else
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_artist_track $artist $track $exartist $exalbum\""
    fi
  fi
  artist=
  track=
}
# Third, handle album or artist and genre requested
[ "$album" ] && [ "$genre" ] && {
  [ "${album}" == "default" ] && album=$(get_default_ini DefaultAlbum)
  printf "\nSearching for album and genre: \"$album\" and \"$genre\"\n"
  [ "${exalbum}" ] && {
    [ "${exartist}" ] || exartist="None"
  }
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      play_genre_album -z "${zone}" "$genre" "$album" "$exartist" "$exalbum"
    else
      play_genre_album "$genre" "$album" "$exartist" "$exalbum"
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_genre_album -z ${zone} $genre $album $exartist $exalbum\""
    else
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_genre_album $genre $album $exartist $exalbum\""
    fi
  fi
  album=
  genre=
}
# Fourth, handle album and composer requested
[ "$album" ] && [ "$composer" ] && {
  [ "${album}" == "default" ] && album=$(get_default_ini DefaultAlbum)
  [ "${composer}" == "default" ] && composer=$(get_default_ini DefaultComposer)
  printf "\nSearching for album and composer: \"$album\" and \"$composer\"\n"
  [ "${exalbum}" ] && {
    [ "${exartist}" ] || exartist="None"
  }
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      play_composer_album -z "${zone}" "$composer" "$album" "$exartist" "$exalbum"
    else
      play_composer_album "$composer" "$album" "$exartist" "$exalbum"
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_composer_album -z ${zone} $composer $album $exartist $exalbum\""
    else
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_composer_album $composer $album $exartist $exalbum\""
    fi
  fi
  album=
  composer=
}
[ "$artist" ] && [ "$genre" ] && {
  [ "${artist}" == "default" ] && artist=$(get_default_ini DefaultArtist)
  printf "\nSearching for artist and genre: \"$artist\" and \"$genre\"\n"
  [ "${exalbum}" ] && {
    [ "${exartist}" ] || exartist="None"
  }
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      play_genre_artist -z "${zone}" "$genre" "$artist" "$exartist" "$exalbum"
    else
      play_genre_artist "$genre" "$artist" "$exartist" "$exalbum"
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_genre_artist -z ${zone} $genre $artist $exartist $exalbum\""
    else
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_genre_artist $genre $artist $exartist $exalbum\""
    fi
  fi
  artist=
  genre=
}
[ "$artist" ] && {
  [ "${artist}" == "default" ] && artist=$(get_default_ini DefaultArtist)
  printf "\nSearching for artist: \"$artist\"\n"
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      play_artist $shuffled -z "${zone}" "$artist" "$exartist"
    else
      play_artist $shuffled "$artist" "$exartist"
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_artist $shuffled -z ${zone} $artist $exartist\""
    else
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_artist $shuffled $artist $exartist\""
    fi
  fi
}
[ "$composer" ] && {
  [ "${composer}" == "default" ] && composer=$(get_default_ini DefaultComposer)
  printf "\nSearching for composer: \"$composer\"\n"
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      play_composer -z "${zone}" "$composer" "$exartist"
    else
      play_composer "$composer" "$exartist"
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_composer -z ${zone} $composer $exartist\""
    else
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_composer $composer $exartist\""
    fi
  fi
}
[ "$genre" ] && {
  [ "${genre}" == "default" ] && genre=$(get_default_ini DefaultGenre)
  printf "\nSearching for genre: \"$genre\"\n"
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      play_genre $shuffled -z "${zone}" "$genre" "$exalbum"
    else
      play_genre $shuffled "$genre" "$exalbum"
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_genre $shuffled -z ${zone} $genre $exalbum\""
    else
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_genre $shuffled $genre $exalbum\""
    fi
  fi
}
[ "$tag" ] && {
  [ "${tag}" == "default" ] && tag=$(get_default_ini DefaultTag)
  printf "\nSearching for tag: \"$tag\"\n"
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      play_tag -z "${zone}" "$tag"
    else
      play_tag "$tag"
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_tag -z ${zone} $tag\""
    else
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_tag $tag\""
    fi
  fi
}
[ "$radio" ] && {
  [ "${radio}" == "default" ] && radio=$(get_default_ini DefaultRadio)
  printf "\nSearching for radio station: \"$radio\"\n"
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      play_radio -z "${zone}" "${radio}"
    else
      play_radio "${radio}"
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_radio -z ${zone} ${radio}\""
    else
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_radio ${radio}\""
    fi
  fi
}
[ "$track" ] && {
  printf "\nSearching for track: \"$track\"\n"
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      play_track -z "${zone}" "$track"
    else
      play_track "$track"
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_track -z ${zone} $track\""
    else
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_track $track\""
    fi
  fi
}

[ "${volume}" ] && {
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      set_volume -v ${volume} -z "${zone}" ${grouped} ${relative} ${step}
    else
      set_volume -v ${volume} ${grouped} ${relative} ${step}
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/set_volume -v ${volume} -z ${zone} ${grouped} ${relative} ${step}\""
    else
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/set_volume -v ${volume} ${grouped} ${relative} ${step}\""
    fi
  fi
}

[ "$album" ] && {
  [ "${album}" == "default" ] && album=$(get_default_ini DefaultAlbum)
  printf "\nSearching for album: \"$album\"\n"
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      play_album -z "${zone}" "$album" "$exalbum"
    else
      play_album "$album" "$exalbum"
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_album -z ${zone} $album $exalbum\""
    else
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_album $album $exalbum\""
    fi
  fi
}

[ "$playlist" ] && {
  [ "${playlist}" == "default" ] && playlist=$(get_default_ini DefaultPlaylist)
  printf "\nSearching for playlist: \"$playlist\"\n"
  if [ "${LOCAL}" = true ]; then
    if [ "${zone}" ]; then
      play_playlist $shuffled -z "${zone}" "$playlist" "$exartist"
    else
      play_playlist $shuffled "$playlist" "$exartist"
    fi
  else
    if [ "${zone}" ]; then
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_playlist $shuffled -z ${zone} $playlist $exartist\""
    else
      ssh ${user}@${server} "bash -l -c \"${ROON}/bin/play_playlist $shuffled $playlist $exartist\""
    fi
  fi
}

if [ "${open_roon_gui}" ]; then
  [ -x ${ROON}/bin/roongui ] && ${ROON}/bin/roongui
else
  if [ "${open_roon_tui}" ]; then
    [ -x ${ROON}/bin/roontui ] && ${ROON}/bin/roontui
  else
    [ "${show_roon_menu}" ] && {
      [ "${skip_anim}" ] || {
        clear
        have_gum=$(type -p gum)
        have_figlet=$(type -p figlet)
        if [ "${have_gum}" ] && [ "${have_figlet}" ]; then
          if [ -x ${ROON}/bin/roonanim ]; then
            ${ROON}/bin/roonanim -a -q
            [ $? -eq 0 ] || tput cup 0 0 2>/dev/null
          else
            if [ "${have_rich}" ]; then
              heading "Welcome to RoonCommandLine" "Roon Command"
            else
              printf "\nWelcome to RoonCommandLine\n"
            fi
          fi
        else
          if [ "${have_rich}" ]; then
            heading "Welcome to RoonCommandLine" "Roon Command"
          else
            printf "\nWelcome to RoonCommandLine\n"
          fi
        fi
      }
      set_fzf_release
      set_gui_release
      set_tui_release
      main_menu
    }
  fi
fi

exit 0
