Browse Source

Refactoring

bryan 3 years ago
parent
commit
437f3da360
2 changed files with 1114 additions and 1278 deletions
  1. 11 11
      README.md
  2. 1103 1267
      installJRMC

+ 11 - 11
README.md

@@ -11,21 +11,21 @@ This program will install [JRiver Media Center](https://www.jriver.com/) and ass
 
 `installJRMC [--option [ARGUMENT]]`
 
-Running `installJRMC` without any options will install the latest version of JRiver Media Center from the official JRiver repository (Ubuntu/Debian) or my [unofficial repository](https://repos.bryanroessler.com/jriver/) (Fedora/CentOS) using the system package manager. If any other option is specified then the default install method will need to be specified using `--install-repo` (or `--install-rpm`). This makes it possible to install services, containers, repos, etc. independent from Media Center.
+Running `installJRMC` without any options will install the latest version of JRiver Media Center from the official JRiver repository (Ubuntu/Debian) or my [unofficial repository](https://repos.bryanroessler.com/jriver/) (Fedora/CentOS) using the system package manager. If any other option is specified then the default install method will need to be specified using `--repo` or `--rpm`. This makes it possible to install services, containers, repos, etc. independent of Media Center.
 
 ## Options
 
 Here is a list of possible options that can be passed to the script. You can always find the latest supported options by running `installJRMC --help`.
 
 ```text
---install-repo
-    Install JRiver Media Center from repository using package manager (Default)
+--repo
+    Install JRiver Media Center from repository using package manager
     DEB-based OSes: Official package repository
     RPM-based OSes: BryanC's unofficial repository
---install-rpm
-     (RPM-based OSes only) Build RPM from source DEB and install it
+--rpm
+     Build RPM from source DEB and install it
 --rpmbuild
-    Build RPM from source DEB
+    Build RPM from source DEB but do not install
 --outputdir PATH
     Generate rpmbuild output in this directory (Default: $PWD/outputdir)
 --mcversion VERSION
@@ -81,7 +81,7 @@ jriver-createrepo
     Install hourly service to build latest MC RPM and run createrepo
 ```
 
-It is possible to install multiple services at one time using multiple `--service` blocks: `installJRMC --install-repo --service jriver-x11vnc --service jriver-mediacenter`
+It is possible to install multiple services at one time using multiple `--service` blocks: `installJRMC --repo --service jriver-x11vnc --service jriver-mediacenter`
 
 #### `jriver-x11vnc` versus `jriver-xvnc-mediacenter`
 
@@ -105,11 +105,11 @@ It is possible to install multiple services at one time using multiple `--servic
 
     Installs the latest version of JRiver Media Center from the repository.
 
-* `installJRMC --install-repo --service jriver-mediaserver`
+* `installJRMC --repo --service jriver-mediaserver`
 
     Installs JRiver Media Center from the repository and starts/enables the /MediaServer service.
 
-* `installJRMC --install-rpm --restorefile /path/to/license.mjr --mcversion 26.0.56`
+* `installJRMC --rpm --restorefile /path/to/license.mjr --mcversion 26.0.56`
 
     Builds JRiver Media Center version 26.0.56 RPM from the source DEB, installs it (RPM distros only), and activates it using the specified .mjr license file.
 
@@ -121,11 +121,11 @@ It is possible to install multiple services at one time using multiple `--servic
 
     Installs the jriver-createrepo timer and service to build the RPM, move it to the webroot, and run createrepo as `www-user` hourly.
 
-* `installJRMC --install-repo --service jriver-x11vnc --service jriver-mediacenter --vncpass "letmein"`
+* `installJRMC --repo --service jriver-x11vnc --service jriver-mediacenter --vncpass "letmein"`
 
     Installs services to share the existing local desktop via VNC and automatically run Media Center on startup.
 
-* `installJRMC --install-repo --service jriver-xvnc-mediacenter --display ":2"`
+* `installJRMC --repo --service jriver-xvnc-mediacenter --display ":2"`
 
     Installs an Xvnc server on display ':2' that starts Media Center.
 

+ 1103 - 1267
installJRMC

@@ -10,1431 +10,1267 @@ shopt -s extglob
 #   1. Raspberry Pi OS support
 #   2. Interactive installation (ncurses?)
 #
-# installJRMC can be run directly or sourced as a function (by sourcing this file)
-# Arguments:
-#   see _printHelpAndExit() and _parseInput() for available options
-# Returns:
-#   0 if critical functions complete successfully
 #######################################
-installJRMC() {
-
-    _scriptversion="0.9.5"
-    _boardurl="https://yabb.jriver.com/interact/index.php/board,67.0.html"
-    _outputdir="$_basedir/output"
-    _createrepo_webroot="/srv/jriver"
-    _exec_user="$(whoami)"
-    _available_services=("jriver-createrepo" "jriver-x11vnc" "jriver-mediaserver" "jriver-mediacenter" "jriver-xvnc-mediacenter")
-    #_available_containers=("mediacenter-xvnc" "createrepo")
 
-    _printHelpAndExit() {
-        debug "Running: ${FUNCNAME[0]}"
-
-        cat <<- 'EOF'
-			USAGE:
-				installJRMC [[OPTION] [VALUE]]...
-
-			OPTIONS
-				--install-repo
-					Install JRiver Media Center from repository using package manager (Default)
-					DEB-based OSes: Official package repository
-					RPM-based OSes: BryanC unofficial repository
-				--install-rpm
-						(RPM-based OSes only) Build RPM from source DEB and install it
-				--rpmbuild
-					Build RPM from source DEB
-				--outputdir PATH
-					Generate rpmbuild output in this directory (Default: $PWD/outputdir)
-				--mcversion VERSION
-					Build or install a specific version (Default: install the latest version)
-				--restorefile RESTOREFILE
-					Restore file location for registration (Default: skip registration)
-				--betapass PASSWORD
-					Enter beta team password for access to beta builds
-				--service-user USER
-					Install systemd services and containers for USER
-				--service, -s SERVICE
-					See SERVICES section below for a list of possible services to install
-				--container, -c CONTAINER (TODO: Under construction)
-					See CONTAINERS section below for a list of possible services to install
-				--createrepo
-					Build rpm, copy to webroot, and run createrepo
-				--createrepo-webroot PATH
-					The webroot directory to install the repo (Default: /srv/jriver/)
-				--createrepo-user USER
-					The web server user (Default: current user)
-				--version, -v
-					Print this script version and exit
-				--debug, -d
-					Print debug output
-				--help, -h
-					Print help dialog and exit
-				--uninstall, -u
-					Uninstall JRiver MC, cleanup service files, and remove firewall rules (does not remove library files)
-
-			SERVICES
-				jriver-mediaserver
-					Enable and start a mediaserver systemd service (requires an existing X server)
-				jriver-mediacenter
-					Enable and start a mediacenter systemd service (requires an existing X server)
-				jriver-x11vnc
-					Enable and start x11vnc for the local desktop (requires an existing X server)
-					Usually combined with jriver-mediaserver or jriver-mediacenter services
-					--vncpass and --display are also valid options (see below)
-				jriver-xvnc-mediacenter
-					Enable and start a new Xvnc session running JRiver Media Center
-					--vncpass PASSWORD
-						Set vnc password for x11vnc/Xvnc access. If no password is set, the script
-						will either use existing password stored in ~/.vnc/jrmc_passwd or use no password
-					--display DISPLAY
-						Display to start x11vnc/Xvnc (Default: The current display (x11vnc) or the
-						current display incremented by 1 (Xvnc))
-				jriver-createrepo
-					Install hourly service to build latest MC RPM and run createrepo
-
-			CONTAINERS (TODO: Under construction)
-				mediacenter-xvnc
-				createrepo
-		EOF
+_scriptversion="0.9.6"
+_boardurl="https://yabb.jriver.com/interact/index.php/board,67.0.html"
+_outputdir="$PWD/output"
+_createrepo_webroot="/srv/jriver"
+_exec_user="$(whoami)"
+
+_printHelpAndExit() {
+    debug "Running: ${FUNCNAME[0]}"
+
+    cat <<- 'EOF'
+		USAGE:
+			installJRMC [[OPTION] [VALUE]]...
+
+			If no options (besides -d) are provided, the script will default to --repo
+
+		OPTIONS
+			--repo
+				Install JRiver Media Center from repository using package manager
+				DEB-based OSes: JRiver official package repository
+				RPM-based OSes: BryanC unofficial repository
+			--rpm
+				Build RPM from source DEB and install it
+			--rpmbuild
+				Build RPM from source DEB (no installation)
+			--outputdir PATH
+				Generate rpmbuild output in this directory (Default: $PWD/outputdir)
+			--mcversion VERSION
+				Build or install a specific version (Default: install the latest version)
+			--restorefile RESTOREFILE
+				Restore file location for registration (Default: skip registration)
+			--betapass PASSWORD
+				Enter beta team password for access to beta builds
+			--service-user USER
+				Install systemd services and containers for USER (Default: current user)
+			--service, -s SERVICE
+				See SERVICES section below for a list of possible services to install
+			--container, -c CONTAINER (TODO: Under construction)
+				See CONTAINERS section below for a list of possible services to install
+			--createrepo
+				Build rpm, copy to webroot, and run createrepo
+			--createrepo-webroot PATH
+				The webroot directory to install the repo (Default: /srv/jriver/)
+			--createrepo-user USER
+				The web server user (Default: current user)
+			--version, -v
+				Print this script version and exit
+			--debug, -d
+				Print debug output
+			--help, -h
+				Print help dialog and exit
+			--uninstall, -u
+				Uninstall JRiver MC, cleanup service files, and remove firewall rules (does not remove library files)
+
+		SERVICES
+			jriver-mediaserver
+				Enable and start a mediaserver systemd service (requires an existing X server)
+			jriver-mediacenter
+				Enable and start a mediacenter systemd service (requires an existing X server)
+			jriver-x11vnc
+				Enable and start x11vnc for the local desktop (requires an existing X server)
+				Usually combined with jriver-mediaserver or jriver-mediacenter services
+				--vncpass and --display are also valid options (see below)
+			jriver-xvnc-mediacenter
+				Enable and start a new Xvnc session running JRiver Media Center
+				--vncpass PASSWORD
+					Set vnc password for x11vnc/Xvnc access. If no password is set, the script
+					will either use existing password stored in ~/.vnc/jrmc_passwd or use no password
+				--display DISPLAY
+					Display to start x11vnc/Xvnc (Default: The current display (x11vnc) or the
+					current display incremented by 1 (Xvnc))
+			jriver-createrepo
+				Install hourly service to build latest MC RPM and run createrepo
+
+		CONTAINERS (TODO: Under construction)
+			mediacenter-xvnc
+			createrepo
+	EOF
 
         # Exit using passed exit code
         [[ ! -v 1 ]] && exit 0 || exit "$1"
     }
 
 
-    _parseInput() {
-        debug "Running: ${FUNCNAME[0]}"
+_init() {
+    debug "Running: ${FUNCNAME[0]}"
+
+    _getOS
+
+    _parseInput "$@"
+
+    # Agnostic commands
+    _bash_cmd(){ _ifSudo bash -c "$@"; }
+    _rm_cmd(){ _ifSudo rm -rf "$@"; }
+    _cp_cmd(){ _ifSudo cp -n "$@"; }
+    _mkdir_cmd(){ _ifSudo mkdir -p "$@"; }
+    _ln_cmd(){ _ifSudo ln -s "$@"; }
+    _systemctl_reload(){ _ifSudo systemctl daemon-reload; }
+    _systemctl_enable(){ _ifSudo systemctl enable --now "$@"; }
+    _systemctl_disable(){ _ifSudo systemctl disable --now "$@"; }
+
+    # OS-specific commands
+    if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
+        _pkg_install(){ _ifSudo dnf install -y "$@"; }
+        _pkg_reinstall(){ _ifSudo dnf reinstall -y "$@"; }
+        _pkg_install_nogpg(){ _ifSudo dnf install --nogpgcheck -y "$@"; }
+        _pkg_remove(){ _ifSudo dnf remove -y "$@"; }
+        _pkg_update(){ _ifSudo dnf makecache; }
+        _pkg_query(){ _ifSudo rpm -q "$@"; }
+        _firewall_cmd(){ _ifSudo firewall-cmd "$@"; }
+    elif [[ "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
+        _pkg_install(){ _ifSudo apt-get install -y -q0 "$@"; }
+        _pkg_reinstall(){ _ifSudo apt-get reinstall -y -q0 "$@"; }
+        _pkg_install_nogpg(){ _ifSudo apt-get install -y -q0 "$@"; }
+        _pkg_remove(){ _ifSudo apt-get remove -y -q0 "$@"; }
+        _pkg_update(){ _ifSudo apt-get update -y -q0; }
+        _pkg_query(){ _ifSudo dpkg -s "$@"; }
+        _firewall_cmd(){ _ifSudo ufw "$@"; }
+    fi
+
+    # Set defaults
+    if [[ $# -eq 0 ]] || [[ $# -eq 1 && "$1" =~ ^(--debug|-d)$ ]]; then
+        debug "No options passed, defaulting to --repo installation method"
+        _repoinstall="true"
+    fi
+
+    _service_user="${_service_user:-$_exec_user}"
+    _createrepo_user="${_createrepo_user:-$_exec_user}"
+
+    # Set package aliases
+    if [[ "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
+        declare -Ag PKG_ALIASES
+        PKG_ALIASES["xorg-x11-utils"]="xorg-x11"
+        PKG_ALIASES["rpm-build"]="rpm"
+        PKG_ALIASES["createrepo_c"]="createrepo"
+        PKG_ALIASES["tigervnc-server"]="tigervnc-standalone-server"
+    fi
+
+    # Install script dependencies
+    [[ "$ID" == "centos" ]] && _installPackage epel-release
+    [[ ! -v _mcversion ]] && _installPackage wget
+
+    # Set MC version
+    _setVersion
+}
 
-        # set default behavior
-        if [[ $# -eq 0 ]] || [[ $# -eq 1 && "$1" =~ ^(--debug|-d)$ ]]; then
-            _repoinstall="true"
-        fi
 
-        if _input=$(getopt -o +vdhus:c: -l install-repo,install-rpm,rpmbuild,outputdir:,mcversion:,restorefile:,betapass:,service-user:,service:,version,debug,help,uninstall,createrepo,createrepo-webroot:,createrepo-user:,vncpass:,display:,container: -- "$@"); then
-            eval set -- "$_input"
-            while true; do
-                case "$1" in
-                    --install-repo)
-                        _repoinstall="true"
-                        ;;
-                    --install-rpm)
-                        _rpmbuild="true"
-                        _rpminstall="true"
-                        ;;
-                    --rpmbuild)
-                        _rpmbuild="true"
-                        ;;
-                    --outputdir)
-                        shift && _outputdir="$1"
-                        ;;
-                    --mcversion)
-                        shift && _mcversion="$1"
-                        ;;
-                    --restorefile)
-                        shift && _restorefile="$1"
-                        ;;
-                    --betapass)
-                        shift && _betapass="$1"
-                        ;;
-                    --service-user)
-                        shift && _service_user="$1"
-                        ;;
-                    --service|-s)
-                        shift && _services+=("$1")
-                        ;;
-                    --container|-c)
-                        shift && _containers+=("$1")
-                        ;;
-                    --version|-v)
-                        echo "Version: $_scriptversion"
-                        exit 0
-                        ;;
-                    --debug|-d)
-                        echo "Debugging on"
-                        echo "installJRMC version: $_scriptversion"
-                        _debug="true"
-                        ;;
-                    --help|-h)
-                        _printHelpAndExit 0
-                        ;;
-                    --uninstall|-u)
-                        _uninstall="true"
-                        ;;
-                    --createrepo)
-                        _createrepo="true"
-                        _rpmbuild="true"
-                        ;;
-                    --createrepo-webroot)
-                        shift && _createrepo_webroot="$1"
-                        ;;
-                    --createrepo-user)
-                        shift && _createrepo_user="$1"
-                        ;;
-                    --vncpass)
-                        shift && _vncpass="$1"
-                        ;;
-                    --display)
-                        shift && _display="$1"
-                        ;;
-                    --)
-                        shift
-                        break
-                        ;;
-                esac
-                shift
-            done
-        else
-            err "Incorrect options provided"
-            _printHelpAndExit 1
-        fi
-    }
+_main() {
 
-    err() { echo "Error: $*" >&2; }
+    _init "$@"
 
-    debug() { [[ -v _debug ]] && echo "Debug: $*"; }
+    # Uninstall and exit
+    if [[ -v _uninstall ]]; then
+        _uninstall
+        exit $?
+    fi
 
-    #######################################
-    # Prepend this to any command that you wish to execute with sudo
-    # Requires:
-    #   _exec_user
-    #######################################
-    _ifSudo() {
-        if [[ "$_exec_user" != "root" ]]; then
-            sudo "$@"
-        else
-            "$@"
+    # Install MC using package manager
+    if [[ -v _repoinstall ]]; then
+        _installMCFromRepo
+        _symlinkCerts
+        _restoreLicense
+        _openFirewall "jriver"
+    fi
+
+    # Build RPM from source deb package
+    if [[ -v _rpmbuild ]]; then
+        _acquireDeb
+        _buildRPM
+    fi
+
+    # Run createrepo
+    if [[ -v _createrepo ]]; then
+        _runCreaterepo "$_mcrpm"
+    fi
+
+    # Install the rpm
+    if [[ -v _rpminstall ]]; then
+        _installPackage --noquery "$_mcrpm"
+        _symlinkCerts
+        _restoreLicense
+        _openFirewall "jriver"
+    fi
+
+    # Install services
+    _setDisplay
+    for _service in "${_services[@]}"; do
+        _servicePrep "$_service"
+        if ! "_service_$_service"; then
+            if [[ $? -eq 127 ]]; then
+                err "Service $_service does not exist, check your service name"
+            else
+                err "Failed to create service: $_service"
+            fi
         fi
-    }
+    done
 
+    # Install containers
+    for _container in "${_containers[@]}"; do
+        if ! "_container_$_container"; then
+            if [[ $? -eq 127 ]]; then
+                err "Container $_container does not exist, check your container name"
+            else
+                err "Failed to create container: $_container"
+            fi
+        fi
+    done
+}
 
-    #######################################
-    # Sources /etc/os-release so we know which OS we're running on
-    # Used in: _buildCommands()
-    #######################################
-    _getOS() {
-        debug "Running: ${FUNCNAME[0]}"
 
-        if [[ -e "/etc/os-release" ]]; then
-            source "/etc/os-release"
-        else
-            err "No /etc/os-release found"
-            err "Your OS is unsupported"
-            _printHelpAndExit 1
+#######################################
+# Helper functions
+#######################################
+err() { echo "Error: $*" >&2; }
+debug() { 
+    if [[ -v _debug ]]; then
+        if [[ $# -gt 0 ]]; then
+            echo "Debug: $*"
         fi
+    else
+        return 1
+    fi
+}
 
-        debug "Platform: $ID $VERSION_ID"
-    }
 
+#######################################
+# Prepend this to any command that you wish to execute with sudo
+# Requires:
+#   _exec_user
+#######################################
+_ifSudo() {
+    if [[ "$_exec_user" != "root" ]]; then
+        sudo "$@"
+    else
+        "$@"
+    fi
+}
 
-    #######################################
-    # Creates some OS-specific functions to query, install, and remove packages and edit
-    # firewalls, run bash, remove and copy files, etc.
-    #######################################
-    _buildCommands() {
 
-        # Detect OS
-        _getOS
+#######################################
+# Parse CLI input from the user w/ getopt
+#######################################
+_parseInput() {
+    debug "Running: ${FUNCNAME[0]}"
+
+    if _input=$(getopt -o +vdhus:c: -l repo,rpm,rpmbuild,outputdir:,mcversion:,restorefile:,betapass:,service-user:,service:,version,debug,help,uninstall,createrepo,createrepo-webroot:,createrepo-user:,vncpass:,display:,container: -- "$@"); then
+        eval set -- "$_input"
+        while true; do
+            case "$1" in
+                --repo)
+                    _repoinstall="true"
+                    ;;
+                --rpm)
+                    [[ ! "$ID" =~ ^(fedora|centos)$ ]] && \
+                        err "RPM installation not available on $ID" && \
+                        _printHelpAndExit 1
+                    _rpmbuild="true"
+                    _rpminstall="true"
+                    ;;
+                --rpmbuild)
+                    _rpmbuild="true"
+                    ;;
+                --outputdir)
+                    shift && _outputdir="$1"
+                    ;;
+                --mcversion)
+                    shift && _mcversion="$1"
+                    ;;
+                --restorefile)
+                    shift && _restorefile="$1"
+                    ;;
+                --betapass)
+                    shift && _betapass="$1"
+                    ;;
+                --service-user)
+                    shift && _service_user="$1"
+                    ;;
+                --service|-s)
+                    shift && _services+=("$1")
+                    ;;
+                --createrepo)
+                    _rpmbuild="true"
+                    _createrepo="true"
+                    ;;
+                --createrepo-webroot)
+                    shift && _createrepo_webroot="$1"
+                    ;;
+                --createrepo-user)
+                    shift && _createrepo_user="$1"
+                    ;;
+                --vncpass)
+                    shift && _vncpass="$1"
+                    ;;
+                --display)
+                    shift && _display="$1"
+                    ;;
+                --container|-c)
+                    shift && _containers+=("$1")
+                    ;;
+                --version|-v)
+                    echo "Version: $_scriptversion"
+                    exit 0
+                    ;;
+                --debug|-d)
+                    echo "Debugging on"
+                    echo "installJRMC version: $_scriptversion"
+                    _debug="true"
+                    ;;
+                --help|-h)
+                    _printHelpAndExit 0
+                    ;;
+                --uninstall|-u)
+                    _uninstall="true"
+                    ;;
+                --)
+                    shift
+                    break
+                    ;;
+            esac
+            shift
+        done
+    else
+        err "Incorrect options provided"
+        _printHelpAndExit 1
+    fi
+}
 
-        debug "Running: ${FUNCNAME[0]}"
 
-        # Agnostic commands
-        _bash_cmd(){ _ifSudo bash -c "$@"; }
-        _rm_cmd(){ _ifSudo rm -rf "$@"; }
-        _cp_cmd(){ _ifSudo cp -n "$@"; }
-        _mkdir_cmd(){ _ifSudo mkdir -p "$@"; }
-        _ln_cmd(){ _ifSudo ln -s "$@"; }
-        _systemctl_reload(){ _ifSudo systemctl daemon-reload; }
-        _systemctl_start(){
-            echo "Starting $*"
-            if ! _ifSudo systemctl start "$@"; then
-                err "Could not start $*"
-                err "Check service status using \"sudo systemctl status $*\""
-                return 1
-            fi
-        }
-        _systemctl_enable(){ _ifSudo systemctl enable "$@"; }
-        _systemctl_disable(){ _ifSudo systemctl disable --now "$@"; }
+#######################################
+# Get host OS from /etc/os-release
+#######################################
+_getOS() {
+    debug "Running: ${FUNCNAME[0]}"
+
+    if [[ -e "/etc/os-release" ]]; then
+        source "/etc/os-release"
+    else
+        err "/etc/os-release not found"
+        err "Your OS is unsupported"
+        _printHelpAndExit 1
+    fi
+
+    debug "Platform: $ID $VERSION_ID"
+}
 
-        # OS-specific commands
-        if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
-            _pkg_install(){ _ifSudo dnf install -y "$@"; }
-            _pkg_reinstall(){ _ifSudo dnf reinstall -y "$@"; }
-            _pkg_install_nogpg(){ _ifSudo dnf install --nogpgcheck -y "$@"; }
-            _pkg_remove(){ _ifSudo dnf remove -y "$@"; }
-            _pkg_update(){ _ifSudo dnf makecache; }
-            _pkg_query(){ _ifSudo rpm -q "$@"; }
-            _firewall_cmd(){ _ifSudo firewall-cmd "$@"; }
-        elif [[ "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
-            _pkg_install(){ _ifSudo apt-get install -y -q0 "$@"; }
-            _pkg_reinstall(){ _ifSudo apt-get reinstall -y -q0 "$@"; }
-            _pkg_install_nogpg(){ _ifSudo apt-get install -y -q0 "$@"; }
-            _pkg_remove(){ _ifSudo apt-get remove -y -q0 "$@"; }
-            _pkg_update(){ _ifSudo apt-get update -y -q0; }
-            _pkg_query(){ _ifSudo dpkg -s "$@"; }
-            _firewall_cmd(){ _ifSudo ufw "$@"; }
-        fi
 
-        # Some additional commands specifically for createrepo (primarily to handle user rights)
-        # Could also go in runCreaterepo() but let's leave it here for now
-        if [[ $_createrepo_user != "root" ]]; then
-            if [[ -d "$_createrepo_webroot/repodata" ]]; then
-                _createrepo_cmd(){ sudo -u "$_createrepo_user" createrepo -q --update "$@"; }
-            else
-                _createrepo_cmd(){ sudo -u "$_createrepo_user" createrepo -q "$@"; }
-            fi
-            _cr_mkdir_cmd(){ sudo -u "$_createrepo_user" mkdir -p "$@"; }
-            _cr_cp_cmd(){ sudo -u "$_createrepo_user" cp -n "$@"; }
-        else
-            if [[ -d "$_createrepo_webroot/repodata" ]]; then
-                _createrepo_cmd(){ createrepo -q --update "$@"; }
-            else
-                _createrepo_cmd(){ createrepo -q "$@"; }
-            fi
+#######################################
+# Get our MC working version from input argument or scraping Interact
+# Requires:
+#   _boardurl
+#######################################
+_setVersion() {
+    debug "Running: ${FUNCNAME[0]}"
+
+    # If user does not specify a version, scrape the latest from Interact
+    if [[ ! -v _mcversion ]]; then
+        echo "Scraping latest MC version number from Interact..."
+        if ! _mcversion=$(wget -qO- "$_boardurl" | grep -o "[0-9][0-9]\.[0-9]\.[0-9]\+" | head -n 1); then
+            err "MC version could not be scraped. Please recheck the boardurl: $_boardurl or specify a version manually using --mcversion"
+            _printHelpAndExit 1
         fi
-    }
+    fi
 
+    echo "Using version: $_mcversion"
 
-    #######################################
-    # Sets default user variables
-    #######################################
-    _setUser() {
+    # Extract major version number
+    _mversion="${_mcversion%%.*}"
 
-        [[ ! -v _service_user ]] && _service_user="$_exec_user"
-        [[ ! -v _createrepo_user ]] && _createrepo_user="$_exec_user"
-    }
+    # Saving this substituion in case it's needed in the future
+    #_variation="${_mcversion##*.}"
+}
 
 
-    #######################################
-    # Installs a package using the system package manager
-    # Arguments:
-    #   One or more package names
-    # Options:
-    #   --noquery, -n: Do not query the package state (useful if installing a local RPM)
-    # Returns:
-    #   Will exit 1 if failed
-    #######################################
-    _installPackage() {
-
-        debug "Running: ${FUNCNAME[0]}" "$@"
-
-        if _input=$(getopt -o +n -l noquery -- "$@"); then
-            eval set -- "$_input"
-            while true; do
-                case "$1" in
-                    --noquery|-n)
-                        local _noquery="true"
-                        ;;
-                    --)
-                        shift
-                        break
-                        ;;
-                esac
-                shift
-            done
-        else
-            err "Incorrect options provided"
-            _printHelpAndExit 1
-        fi
-
-        # We will add packages to this array if their command is not available
-        local -a _pkg_array
-        local -a _url_pkg_array
-
-        # parse arguments (packages)
-        for _pkg in "$@"; do
-            # Clean up package name and handle OS-specific tweaks
-            _packageQuirks "$_pkg"
-            # Insert the package name to test if already installed
-            if [[ "$_pkg" != "" ]]; then
-                if [[ -v _noquery ]] || ! _pkg_query "$_pkg" > /dev/null 2>&1; then
-                    if [[ -v _url_pkg ]]; then
-                        _url_pkg_array+=("$_url_pkg")
-                    else
-                        _pkg_array+=("$_pkg")
-                    fi
-                fi
-            fi
+#######################################
+# Installs a package using the system package manager
+# Arguments:
+#   One or more package names
+# Options:
+#   --noquery, -n: Do not query the package state (useful if installing a local RPM)
+# Returns:
+#   Will exit 1 if failed
+#######################################
+_installPackage() {
+    debug "Running: ${FUNCNAME[0]}" "$@"
+
+    if _input=$(getopt -o +n -l noquery -- "$@"); then
+        eval set -- "$_input"
+        while true; do
+            case "$1" in
+                --noquery|-n)
+                    local _noquery="true"
+                    ;;
+                --)
+                    shift
+                    break
+                    ;;
+            esac
+            shift
         done
+    else
+        err "Incorrect options provided"
+        _printHelpAndExit 1
+    fi
+
+    # We will add packages to this array if their command is not available
+    local -a _pkg_array
+    local -a _url_pkg_array
+
+    # Parse packages
+    for _pkg in "$@"; do
+        [[ -v PKG_ALIASES && -v PKG_ALIASES["$_pkg"] ]] && _pkg=PKG_ALIASES["$_pkg"]
+        # Insert the package name to test if already installed
+        if [[ -v _noquery ]] || ! _pkg_query "$_pkg" > /dev/null 2>&1; then
+            if [[ -v _url_pkg ]]; then
+                _url_pkg_array+=("$_url_pkg")
+            else
+                _pkg_array+=("$_pkg")
+            fi
+        fi
+    done
 
-        # Install from package name (with gpg check)
-        if [[ ${#_pkg_array[@]} -ge 1 ]]; then
-            echo "Installing:" "${_pkg_array[@]}"
-            if [[ -v _debug ]]; then
-                if ! _pkg_install "${_pkg_array[@]}"; then
-                    err "Failed to install package. Attempting to continue..."
-                    return 1
-                fi
-            elif ! _pkg_install "${_pkg_array[@]}" > /dev/null 2>&1; then
+    # Install from package name (with gpg check)
+    if [[ ${#_pkg_array[@]} -ge 1 ]]; then
+        echo "Installing:" "${_pkg_array[@]}"
+        if debug; then
+            if ! _pkg_install "${_pkg_array[@]}"; then
                 err "Failed to install package. Attempting to continue..."
                 return 1
             fi
+        elif ! _pkg_install "${_pkg_array[@]}" > /dev/null 2>&1; then
+            err "Failed to install package. Attempting to continue..."
+            return 1
         fi
+    fi
 
-        # Install from package url (without gpg check)
-        if [[ ${#_url_pkg_array[@]} -ge 1 ]]; then
-            echo "Installing:" "${_url_pkg_array[@]}"
-            if [[ -v _debug ]]; then
-                if ! _pkg_install_nogpg "${_url_pkg_array[@]}"; then
-                    err "Failed to install package. Attempting to continue..."
-                    return 1
-                fi
-            elif ! _pkg_install_nogpg "${_url_pkg_array[@]}" > /dev/null 2>&1; then
+    # Install from package url (without gpg check)
+    if [[ ${#_url_pkg_array[@]} -ge 1 ]]; then
+        echo "Installing:" "${_url_pkg_array[@]}"
+        if debug; then
+            if ! _pkg_install_nogpg "${_url_pkg_array[@]}"; then
                 err "Failed to install package. Attempting to continue..."
                 return 1
             fi
+        elif ! _pkg_install_nogpg "${_url_pkg_array[@]}" > /dev/null 2>&1; then
+            err "Failed to install package. Attempting to continue..."
+            return 1
         fi
-    }
+    fi
+}
 
 
-    #######################################
-    # Handles OS-specific package name tweaks and source urls
-    # Arguments:
-    #   A package name
-    # Globals:
-    #   _pkg
-    #   _url_pkg
-    #######################################
-    _packageQuirks() {
-
-        debug "Running: ${FUNCNAME[0]}" "$@"
-
-        unset _url_pkg
-
-        if [[ "$1" == "xorg-x11-utils" && "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
-            _pkg="x11-utils"
-        elif [[ "$1" == "rpm-build" && "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
-            _pkg="rpm"
-        elif [[ "$1" == "createrepo_c" && "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
-            _pkg="createrepo"
-        elif [[ "$1" == "rpmfusion-free-release" ]]; then
-            if [[ "$ID" == "fedora" ]]; then
-                # As of MC26 and Fedora 32 I don't believe that the rpmfusion repo is necessary
-                #_url_pkg="https://download1.rpmfusion.org/free/$ID/rpmfusion-free-release-$VERSION_ID.noarch.rpm"
-                #_pkg="$1"
-                _pkg=""
-            elif [[ "$ID" == "centos" ]]; then
-                _url_pkg="https://download1.rpmfusion.org/free/el/rpmfusion-free-release-$VERSION_ID.noarch.rpm"
-                _pkg="$1"
-            else
-                _pkg=""
-            fi
-        elif [[ "$1" == "epel-release" && "$ID" != "centos" ]]; then
-            _pkg=""
-        elif [[ "$1" == "tigervnc-server" && "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
-            _pkg="tigervnc-standalone-server"
-        else
-            _pkg="$1"
-        fi
-    }
+#######################################
+# Installs JRiver Media Center from a repository
+# Returns:
+#   0 if JRiver Media Center installed sucessfully
+#######################################
+_installMCFromRepo() {
+    debug "Running: ${FUNCNAME[0]}"
 
+    echo "Installing JRiver Media Center from repo..."
 
-    #######################################
-    # Get our MC working version from input argument or scraping Interact
-    # Requires:
-    #   _boardurl
-    #   _installPackage
-    # Globals:
-    #   _mcversion
-    #   _mversion
-    #######################################
-    _setVersion() {
+    ! debug && \
+        echo "This may take a few minutes to complete"; \
+        echo "Use --debug for verbose output"
 
-        debug "Running: ${FUNCNAME[0]}"
+    local _mcpkg
 
-        if [[ ! -v _mcversion ]]; then
+    # Add repository files
+    _addRepo() {
+        debug "Running: ${FUNCNAME[0]}"
 
+        if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
+            _bash_cmd 'cat <<- EOF > /etc/yum.repos.d/jriver.repo
+				[jriver]
+				name=JRiver Media Center repo by BryanC
+				baseurl=https://repos.bryanroessler.com/jriver
+				gpgcheck=0
+			EOF'
+        elif [[ "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
             _installPackage wget
-
-            # Get latest version from Interact
-            echo "Scraping latest MC version number from Interact..."
-            if ! _mcversion=$(wget -qO- "$_boardurl" | grep -o "[0-9][0-9]\.[0-9]\.[0-9]\+" | head -n 1); then
-                err "MC version could not be scraped. Please specify a version manually using --mcversion or check your --boardurl"
-                _printHelpAndExit 1
-            fi
+            wget -q "http://dist.jriver.com/mediacenter@jriver.com.gpg.key" -O- | _ifSudo apt-key add - > /dev/null 2>&1
+            _bash_cmd 'cat <<- EOF > /etc/apt/sources.list.d/jriver.list
+				deb [arch=amd64,i386,armhf] http://dist.jriver.com/latest/mediacenter/ buster main
+			EOF'
         fi
-
-        echo "Using version: $_mcversion"
-
-        # Extract major version number
-        _mversion="${_mcversion%%.*}"
-
-        # Saving this substituion in case it's needed in the future
-        #_variation="${_mcversion##*.}"
-    }
-
-
-    #######################################
-    # Check if an argument exists in an array
-    # Arguments:
-    #   The first argument is the string to match to the following arguments
-    # Example:
-    #   _inArray "zebra" "${animals_arr[@]}"
-    # Returns:
-    #   0 if a match is found, 1 if not
-    #######################################
-    _inArray() {
-
-        local _match="$1"
-        shift
-
-        local _item
-        for _item in "$@"; do
-            [[ "$_item" == "$_match" ]] && return 0
-        done
-
-        return 1
     }
-
-
-    #######################################
-    # Clean up nonsensical user input
-    # Notes:
-    #   I try to keep this function as short as possible and provide better input options and
-    #   sensible defaults than workarounds
-    # Test:
-    #   _installJRMC should run sucessfully even without running _sanityChecks()
-    #######################################
-    _sanityChecks() {
-        debug "Running: ${FUNCNAME[0]}"
-
-        # Check for bad service name
-        _checkServices() {
-
-            debug "Running: ${FUNCNAME[0]}"
-
-            for _service in "${_services[@]}"; do
-                if ! _inArray "$_service" "${_available_services[@]}"; then
-                    echo "Incorrect service type provided"
-                    _printHelpAndExit 1
-                fi
-            done
-        }
-
-
-        _checkMCInstalled() {
-            debug "Running: ${FUNCNAME[0]}"
-
-            for _service in "${_services[@]}"; do
-                if [[ "$_service" =~ ^(jriver-mediacenter|jriver-mediaserver|jriver-xvnc-mediacenter|jriver-x11vnc)$ ]] \
-                && [[ ! -v _repoinstall && ! -v _rpminstall ]] \
-                && [[ ! -x $(command -v "mediacenter$_mversion") ]]; then
-                    err "You are attempting to install a service that depends on JRiver Media Center"
-                    err "without installing JRiver Media Center"
-                    err "Automatically enabling --repo-install"
-                    _repoinstall="true"
-                fi
-            done
-        }
-
-
-        _checkUser() {
-            debug "Running: ${FUNCNAME[0]}"
-
-            if [[ "$_exec_user" == "root" && ! -v _service_user && "${_services[*]}" ]]; then
-                err "Attempting to install services as the root user"
-                err "This is not recommended and we are exiting now to prevent permission hell"
-                err "You can override this safety check by manually specifying --user root"
-                return 1
+    _addRepo
+
+    # Update package list
+    debug "Updating package list"
+    if ! _pkg_update > /dev/null 2>&1; then
+        err "Package update failed!"
+        exit 1
+    fi
+
+    local _mcpkg
+
+    # Fedora/CentOS use a universal package name -- easy
+    if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
+        _mcpkg="MediaCenter"
+    # Ubuntu/Debian incorporate the mversion into the package name -- more fun!
+    elif [[ "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
+        if [[ ! -v _mversion ]]; then
+            # Try parsing the latest mversion from the repo
+            if _mcpkg=$(apt-get install mediacenter?? -s -q0 | grep "selecting" | tail -1| awk '{print $3}'); then
+                _mcpkg="${_mcpkg%\'}"
+                _mcpkg="${_mcpkg#\'}"
+            # Scrape Interact
+            else
+                _mcpkg="mediacenter$_mversion"
             fi
-        }
-
-
-        # Enable/disable sanity checks
-        if _checkServices && _checkMCInstalled && _checkUser; then
-            debug "Sanity checks passed!"
-            return 0
         else
-            err "Sanity checks failed!"
-            exit 1
+            _mcpkg="mediacenter$_mversion"
         fi
-    }
-
-
-    #######################################
-    # Installs JRiver Media Center from a repository
-    # Returns:
-    #   0 if JRiver Media Center installed sucessfully
-    #######################################
-    _installMCFromRepo() {
-        debug "Running: ${FUNCNAME[0]}"
-
-        echo "Installing JRiver Media Center from repo..."
-        [[ ! -v _debug ]] && \
-            echo "This may take a few minutes"; \
-            echo "Use --debug for verbose output"
-
-        local _mcpkg
-
-        # Add repository files
-        _addRepo() {
-            debug "Running: ${FUNCNAME[0]}"
-            # Add repositories to OS-specific package managers
-            if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
-                _bash_cmd 'cat <<- EOF > /etc/yum.repos.d/jriver.repo
-					[jriver]
-					name=JRiver Media Center repo by BryanC
-					baseurl=https://repos.bryanroessler.com/jriver
-					gpgcheck=0
-				EOF'
-            elif [[ "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
-                _installPackage wget
-                wget -q "http://dist.jriver.com/mediacenter@jriver.com.gpg.key" -O- | _ifSudo apt-key add - > /dev/null 2>&1
-                _bash_cmd 'cat <<- EOF > /etc/apt/sources.list.d/jriver.list
-					deb [arch=amd64,i386,armhf] http://dist.jriver.com/latest/mediacenter/ buster main
-				EOF'
-            fi
-        }
-        _addRepo
-
-        # Update package list
-        debug "Updating package list"
-        if ! _pkg_update > /dev/null 2>&1; then
-            err "Package update failed!"
+        # Sanity check
+        if [[ ! "$_mcpkg" =~ ^mediacenter[0-9][0-9]$ ]]; then
+            err "Could not parse MC package name"
             exit 1
         fi
+    fi
 
-        # If user specifies a version, use that
-        if [[ -v _mcversion ]]; then
-            _setVersion
-            local _specific_version="true"
-        fi
-
-        local _mcpkg
-
-        # Fedora/CentOS use a universal package name -- easy
+    if [[ -v _specific_version ]]; then
         if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
-            _mcpkg="MediaCenter"
-        fi
-
-        # Ubuntu/Debian incorporate the mversion into the package name -- more fun!
-        if [[ "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
-            if [[ ! -v _mversion ]]; then
-                # Try parsing the latest mversion from the repo
-                if _mcpkg=$(apt-get install mediacenter?? -s -q0 | grep "selecting" | tail -1| awk '{print $3}'); then
-                    _mcpkg="${_mcpkg%\'}"
-                    _mcpkg="${_mcpkg#\'}"
-                # Scrape Interact
-                else
-                    _setVersion
-                    _mcpkg="mediacenter$_mversion"
-                fi
+            if debug; then
+                _installPackage "$_mcpkg-$_mcversion"
             else
-                _mcpkg="mediacenter$_mversion"
+                _installPackage "$_mcpkg-$_mcversion" > /dev/null 2>&1
             fi
-            # Sanity check
-            if [[ ! "$_mcpkg" =~ ^mediacenter[0-9][0-9]$ ]]; then
-                err "Could not parse MC package name"
-                exit 1
-            fi
-        fi
-
-        if [[ -v _specific_version ]]; then
-            if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
-                if [[ -v _debug ]]; then
-                    _installPackage "$_mcpkg-$_mcversion"
-                else
-                    _installPackage "$_mcpkg-$_mcversion" > /dev/null 2>&1
-                fi
-            elif [[ "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
-                if [[ -v _debug ]]; then
-                    _installPackage "$_mcpkg=$_mcversion"
-                else
-                    _installPackage "$_mcpkg=$_mcversion" > /dev/null 2>&1
-                fi
-            fi
-        else
-            if [[ -v _debug ]]; then
-                _installPackage "$_mcpkg"
+        elif [[ "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
+            if debug; then
+                _installPackage "$_mcpkg=$_mcversion"
             else
-                _installPackage "$_mcpkg" > /dev/null 2>&1
+                _installPackage "$_mcpkg=$_mcversion" > /dev/null 2>&1
             fi
         fi
-
-        # shellcheck disable=SC2181
-        # Rationale: More compact to check this once
-        if [[ $? -eq 0 ]]; then
-            echo "JRiver Media Center installed successfully"
-            return 0
+    else
+        if debug; then
+            _installPackage "$_mcpkg"
         else
-            err "JRiver Media Center installation failed"
-            exit 1
+            _installPackage "$_mcpkg" > /dev/null 2>&1
         fi
-    }
+    fi
 
+    # shellcheck disable=SC2181
+    if [[ $? -ne 0 ]]; then
+        err "JRiver Media Center installation failed"
+        exit 1
+    fi
 
-    #######################################
-    # Acquire the source DEB package from JRiver's servers
-    # Returns:
-    #   0 if DEB file downloaded successfully, 1 if failed
-    #######################################
-    _acquireDeb() {
-        debug "Running: ${FUNCNAME[0]}"
+    echo "JRiver Media Center installed successfully"
+}
 
-        local _debfilename="$_outputdir/SOURCES/MediaCenter-${_mcversion}-amd64.deb"
 
-        # If necessary, create SOURCES dir
-        [[ ! -d "$_outputdir/SOURCES" ]] && mkdir -p "$_outputdir/SOURCES"
+#######################################
+# Acquire the source DEB package from JRiver's servers
+# Returns:
+#   0 if DEB file downloaded successfully, 1 if failed
+#######################################
+_acquireDeb() {
+    debug "Running: ${FUNCNAME[0]}"
 
-        # If deb file already exists, skip download
-        if [[ -f "$_debfilename" ]]; then
-            echo "Using local DEB file: $_debfilename"
-        # Else check beta repo
-        elif [[ -v _betapass ]]; then
-            if wget -q -O "$_debfilename" \
-            "https://files.jriver.com/mediacenter/channels/v${_mversion}/beta/${_betapass}/MediaCenter-${_mcversion}-amd64.deb"; then
-                true
-            fi
-        # Else check test repo
-        elif wget -q -O "$_debfilename" \
-        "https://files.jriver.com/mediacenter/test/MediaCenter-${_mcversion}-amd64.deb"; then
-            true
-        # Else check latest repo
-        elif wget -q -O "$_debfilename" \
-        "https://files.jriver.com/mediacenter/channels/v${_mversion}/latest/MediaCenter-${_mcversion}-amd64.deb"; then
-            true
-        else
-            err "Cannot find DEB file. Exiting..."
-            exit 1
-        fi
+    local _debfilename="$_outputdir/SOURCES/MediaCenter-$_mcversion-amd64.deb"
 
-        if [[ ! -f "$_debfilename" ]]; then
-            err "Downloaded DEB file missing or corrupted, exiting..."
-            exit 1
+    # If necessary, create SOURCES dir
+    [[ ! -d "$_outputdir/SOURCES" ]] && mkdir -p "$_outputdir/SOURCES"
+
+    # If deb file already exists, skip download
+    if [[ -f "$_debfilename" ]]; then
+        echo "Using local DEB file: $_debfilename"
+    # Else check beta repo
+    elif [[ -v _betapass ]]; then
+        if wget -q -O "$_debfilename" \
+        "https://files.jriver.com/mediacenter/channels/v$_mversion/beta/$_betapass/MediaCenter-$_mcversion-amd64.deb"; then
+            true
         fi
-    }
+    # Else check test repo
+    elif wget -q -O "$_debfilename" \
+    "https://files.jriver.com/mediacenter/test/MediaCenter-$_mcversion-amd64.deb"; then
+        true
+    # Else check latest repo
+    elif wget -q -O "$_debfilename" \
+    "https://files.jriver.com/mediacenter/channels/v$_mversion/latest/MediaCenter-$_mcversion-amd64.deb"; then
+        true
+    else
+        err "Cannot find DEB file. Exiting..."
+        exit 1
+    fi
+
+    if [[ ! -f "$_debfilename" ]]; then
+        err "Downloaded DEB file missing or corrupted, exiting..."
+        exit 1
+    fi
+}
 
 
-    #######################################
-    # Creates a SPEC file and builds the RPM from the source DEB using rpmbuild
-    # Requires:
-    #   _outputdir
-    #   ID
-    #   _mcversion
-    #   _mversion
-    #   _installPackage
-    # Globals:
-    #   _mcrpm
-    # Returns:
-    #   0 if rpmbuild is successful, 1 if not
-    #######################################
-    _buildRPM() {
-        debug "Running: ${FUNCNAME[0]}"
+#######################################
+# Creates a SPEC file and builds the RPM from the source DEB using rpmbuild
+# Requires:
+#   _outputdir
+#   ID
+#   _mcversion
+#   _mversion
+#   _installPackage
+# Globals:
+#   _mcrpm
+# Returns:
+#   0 if rpmbuild is successful, 1 if not
+#######################################
+_buildRPM() {
+    debug "Running: ${FUNCNAME[0]}"
+
+    # install build dependencies
+    _installPackage wget dpkg rpm-build
+
+    # If necessary, make build directories
+    [[ ! -d "$_outputdir/SPECS" ]] && mkdir -p "$_outputdir/SPECS"
+
+    # rpmbuild uses rpm to check for build dependencies
+    # this will fail on non-rpm distros
+    if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
+        local _build_requires=$'BuildRequires: rpm >= 4.11.0\nBuildRequires: dpkg'
+    fi
+
+    # Create spec file
+    cat <<- EOF > "$_outputdir/SPECS/mediacenter.spec"
+		Name:    MediaCenter
+		Version: $_mcversion
+		Release: 1
+		Summary: JRiver Media Center
+		Group:   Applications/Media
+		Source0: http://files.jriver.com/mediacenter/channels/v$_mversion/latest/MediaCenter-$_mcversion-amd64.deb
+		${_build_requires:-}
+		BuildArch: x86_64
+		%define _rpmfilename %%{ARCH}/%%{NAME}-%%{version}.%%{ARCH}.rpm
+
+		AutoReq:  0
+		Requires: glibc >= 2.19
+		Requires: alsa-lib >= 1.0.28
+		Requires: libuuid >= 2.25
+		Requires: libX11 >= 1.6
+		Requires: libX11-common >= 1.6
+		Requires: libXext >= 1.3
+		Requires: libxcb >= 1.1
+		Requires: libXdmcp >= 1.1
+		Requires: libstdc++ >= 4.9
+		Requires: gtk3 >= 3.14
+		Requires: mesa-libGL
+		Requires: libglvnd-glx
+		Requires: pango >= 1.36
+		Requires: libXScrnSaver
+		Requires: xdg-utils
+		Requires: libgomp >= 4.9
+		Requires: nss >= 3.26
+		Requires: nspr >= 4.12
+		Requires: ca-certificates
+		Requires: python3
+		Recommends: vorbis-tools >= 1.4.0
+		Recommends: lame >= 3.0
+
+		Provides: mediacenter$_mversion
+
+		License: Copyright 1998-2021, JRiver, Inc.  All rights reserved.  Protected by U.S. patents #7076468 and #7062468
+		URL: http://www.jriver.com/
+
+		%define __provides_exclude_from ^%{_libdir}/jriver/.*/.*\\.so.*$
+
+		%description
+		Media Center is more than a world class player.
+
+		%global __os_install_post %{nil}
+		%prep
+
+		%build
+
+		%install
+		dpkg -x %{S:0} %{buildroot}
+
+		%post -p /sbin/ldconfig
+		%postun -p /sbin/ldconfig
+
+		%files
+		%{_bindir}/mediacenter$_mversion
+		%{_libdir}/jriver
+		%{_datadir}
+		%exclude %{_datadir}/applications/media_center_packageinstaller_$_mversion.desktop
+		/etc/security/limits.d/*
+	EOF
+
+    declare -g _mcrpm="$_outputdir/RPMS/x86_64/MediaCenter-$_mcversion.x86_64.rpm"
+
+    # skip rebuilding the rpm if it already exists
+    if [[ -f "$_mcrpm" ]]; then
+        echo "$_mcrpm already exists. Skipping build step..."
+        return 0
+    fi
+
+    # Run rpmbuild
+    echo "Building version $_mcversion, please wait..."
+    if debug; then
+        rpmbuild --define="%_topdir $_outputdir" --define="%_libdir /usr/lib" -bb "$_outputdir/SPECS/mediacenter.spec"
+    else
+        rpmbuild --quiet --define="%_topdir $_outputdir" --define="%_libdir /usr/lib" -bb "$_outputdir/SPECS/mediacenter.spec" > /dev/null 2>&1
+    fi
+
+    # Check return code
+    # shellcheck disable=SC2181
+    if [[ $? -ne 0 || ! -f "$_mcrpm" ]]; then
+        err "Build failed. Exiting..."
+        exit 1
+    else
+        echo "Build successful. The RPM file is located at: $_mcrpm"
+    fi
+}
 
-        # install build dependencies
-        _installPackage wget dpkg rpm-build
 
-        # If necessary, make build directories
-        [[ ! -d "$_outputdir/SPECS" ]] && mkdir -p "$_outputdir/SPECS"
+#######################################
+# Copy the RPM to createrepo-webroot and runs createrepo as the createrepo-user
+# Arguments:
+#   Requires one argument, the path to the RPM file (typically _mcrpm)
+# Requires:
+#   _createrepo_webroot
+# Returns:
+#   0 if createrepo is successful, 1 if not
+#######################################
+_runCreaterepo() {
+    debug "Running: ${FUNCNAME[0]}"
 
-        # rpmbuild uses rpm to check for build dependencies
-        # this will fail on non-rpm distros
-        if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
-            local _build_requires=$'BuildRequires: rpm >= 4.11.0\nBuildRequires: dpkg'
+    # Some additional commands specifically for createrepo (primarily to handle user rights)
+    if [[ $_createrepo_user != "root" ]]; then
+        if [[ -d "$_createrepo_webroot/repodata" ]]; then
+            _createrepo_cmd(){ sudo -u "$_createrepo_user" createrepo -q --update "$@"; }
+        else
+            _createrepo_cmd(){ sudo -u "$_createrepo_user" createrepo -q "$@"; }
         fi
-
-        # Create spec file
-        cat <<- EOF > "$_outputdir/SPECS/mediacenter.spec"
-			Name:    MediaCenter
-			Version: $_mcversion
-			Release: 1
-			Summary: JRiver Media Center
-			Group:   Applications/Media
-			Source0: http://files.jriver.com/mediacenter/channels/v$_mversion/latest/MediaCenter-$_mcversion-amd64.deb
-			${_build_requires:-}
-			BuildArch: x86_64
-			%define _rpmfilename %%{ARCH}/%%{NAME}-%%{version}.%%{ARCH}.rpm
-
-			AutoReq:  0
-			Requires: glibc >= 2.19
-			Requires: alsa-lib >= 1.0.28
-			Requires: libuuid >= 2.25
-			Requires: libX11 >= 1.6
-			Requires: libX11-common >= 1.6
-			Requires: libXext >= 1.3
-			Requires: libxcb >= 1.1
-			Requires: libXdmcp >= 1.1
-			Requires: libstdc++ >= 4.9
-			Requires: gtk3 >= 3.14
-			Requires: mesa-libGL
-			Requires: libglvnd-glx
-			Requires: pango >= 1.36
-			Requires: libXScrnSaver
-			Requires: xdg-utils
-			Requires: libgomp >= 4.9
-			Requires: nss >= 3.26
-			Requires: nspr >= 4.12
-			Requires: ca-certificates
-			Requires: python3
-			Recommends: vorbis-tools >= 1.4.0
-			Recommends: lame >= 3.0
-
-			Provides: mediacenter$_mversion
-
-			License: Copyright 1998-2020, JRiver, Inc.  All rights reserved.  Protected by U.S. patents #7076468 and #7062468
-			URL: http://www.jriver.com/
-
-			%define __provides_exclude_from ^%{_libdir}/jriver/.*/.*\\.so.*$
-
-			%description
-			Media Center is more than a world class player.
-
-			%global __os_install_post %{nil}
-			%prep
-
-			%build
-
-			%install
-			dpkg -x %{S:0} %{buildroot}
-
-			%post -p /sbin/ldconfig
-			%postun -p /sbin/ldconfig
-
-			%files
-			%{_bindir}/mediacenter$_mversion
-			%{_libdir}/jriver
-			%{_datadir}
-			%exclude %{_datadir}/applications/media_center_packageinstaller_$_mversion.desktop
-			/etc/security/limits.d/*
-		EOF
-
-        declare -g _mcrpm="$_outputdir/RPMS/x86_64/MediaCenter-$_mcversion.x86_64.rpm"
-
-        # skip rebuilding the rpm if it already exists
-        if [[ -f "$_mcrpm" ]]; then
-            echo "$_mcrpm already exists. Skipping build step..."
-            return 0
+        _cr_mkdir_cmd(){ sudo -u "$_createrepo_user" mkdir -p "$@"; }
+        _cr_cp_cmd(){ sudo -u "$_createrepo_user" cp -n "$@"; }
+    else
+        if [[ -d "$_createrepo_webroot/repodata" ]]; then
+            _createrepo_cmd(){ createrepo -q --update "$@"; }
         else
-            # Run rpmbuild
-            echo "Building version $_mcversion, please wait..."
-            if [[ -v _debug ]]; then
-                rpmbuild --define="%_topdir $_outputdir" --define="%_libdir /usr/lib" -bb "$_outputdir/SPECS/mediacenter.spec"
-            else
-                rpmbuild --quiet --define="%_topdir $_outputdir" --define="%_libdir /usr/lib" -bb "$_outputdir/SPECS/mediacenter.spec" > /dev/null 2>&1
-            fi
-
-            # Check return code
-            # shellcheck disable=SC2181
-            if [[ $? -ne 0 || ! -f "$_mcrpm" ]]; then
-                err "Build failed. Exiting..."
-                exit 1
-            else
-                echo "Build successful. The RPM file is located at: $_mcrpm"
-            fi
+            _createrepo_cmd(){ createrepo -q "$@"; }
         fi
-    }
+    fi
 
+    _installPackage createrepo_c
 
-    #######################################
-    # Copy the RPM to createrepo-webroot and runs createrepo as the createrepo-user
-    # Arguments:
-    #   Requires one argument, the path to the RPM file (typically _mcrpm)
-    # Requires:
-    #   _createrepo_webroot
-    # Returns:
-    #   0 if createrepo is successful, 1 if not
-    #######################################
-    _runCreaterepo() {
-        debug "Running: ${FUNCNAME[0]}"
-
-        _installPackage createrepo_c
+    local _rpmfile="$1"
 
-        local _rpmfile="$1"
-
-        # If the webroot does not exist, create it
-        if [[ ! -d "$_createrepo_webroot" ]]; then
-            if ! _cr_mkdir_cmd "$_createrepo_webroot"; then
-                err "Could not create the createrepo-webroot path!"
-                err "Make sure that the createrepo-webroot is writeable by createrepo-user"
-                return 1
-            fi
-        fi
-
-        # Copy built rpms to webroot
-        if ! _cr_cp_cmd -f "$_rpmfile" "$_createrepo_webroot"; then
-            err "Could not copy the RPM to the createrepo-webroot path"
-            err "Make sure that the createrepo-webroot path is writeable by createrepo-user"
+    # If the webroot does not exist, create it
+    if [[ ! -d "$_createrepo_webroot" ]]; then
+        if ! _cr_mkdir_cmd "$_createrepo_webroot"; then
+            err "Could not create the createrepo-webroot path!"
+            err "Make sure that the createrepo-webroot is writeable by createrepo-user: $_createrepo_user"
             return 1
         fi
+    fi
 
-        # Run createrepo
-        if _createrepo_cmd "$_createrepo_webroot"; then
-            echo "Successfully updated repo"
-            return 0
-        else
-            err "Update repo failed"
-            return 1
-        fi
-    }
+    # Copy built rpms to webroot
+    if ! _cr_cp_cmd -f "$_rpmfile" "$_createrepo_webroot"; then
+        err "Could not copy the RPM to the createrepo-webroot path"
+        err "Make sure that the createrepo-webroot path is writeable by createrepo-user: $_createrepo_user"
+        return 1
+    fi
+
+    # Run createrepo
+    if _createrepo_cmd "$_createrepo_webroot"; then
+        echo "Successfully updated repo"
+        return 0
+    else
+        err "Update repo failed"
+        return 1
+    fi
+}
 
 
-    #######################################
-    # Symlink certificates where JRiver Media Center expects them to be on Fedora/CentOS
-    # Returns:
-    #   0 if symlinking is unecessary or successful, 1 if not
-    #######################################
-    _symlinkCerts() {
-        debug "Running: ${FUNCNAME[0]}"
+#######################################
+# Symlink certificates where JRiver Media Center expects them to be on Fedora/CentOS
+# Returns:
+#   0 if symlinking is unecessary or successful, 1 if not
+#######################################
+_symlinkCerts() {
+    debug "Running: ${FUNCNAME[0]}"
 
-        if [[ ! -f /etc/ssl/certs/ca-certificates.crt && \
-        -f /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem ]]; then
-            if ! _ln_cmd /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem /etc/ssl/certs/ca-certificates.crt; then
-                err "Symlinking certificates failed"
-                return 1
-            fi
+    if [[ ! -f /etc/ssl/certs/ca-certificates.crt && \
+    -f /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem ]]; then
+        if ! _ln_cmd /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem /etc/ssl/certs/ca-certificates.crt; then
+            err "Symlinking certificates failed"
+            return 1
         fi
-    }
+    fi
+}
 
 
-    #######################################
-    # Automatically restore the mjr license file if it is found next to installJRMC or _restorefile
-    # is set
-    # Requires:
-    #   _restorefile OR _basedir
-    #   _mversion
-    # Returns:
-    #   0 if license restored successfully or skipped, 1 if unsuccessful
-    #######################################
-    _restoreLicense() {
-        debug "Running: ${FUNCNAME[0]}"
+#######################################
+# Automatically restore the mjr license file if it is found next to installJRMC or _restorefile
+# is set
+# Requires:
+#   _restorefile OR _basedir
+#   _mversion
+# Returns:
+#   0 if license restored successfully or skipped, 1 if unsuccessful
+#######################################
+_restoreLicense() {
+    debug "Running: ${FUNCNAME[0]}"
 
-        local _mjr
+    local _mjr
 
-        # Allow user to drop an mjr file next to installJRMC
-        if [[ ! -v _restorefile ]]; then
-            for _mjr in "$_basedir"/*.mjr; do
-              [[ $_mjr -nt $_restorefile ]] && _restorefile="$_mjr"
-            done
-        fi
+    # Allow user to drop an mjr file next to installJRMC
+    if [[ ! -v _restorefile ]]; then
+        for _mjr in "$PWD"/*.mjr; do
+            [[ $_mjr -nt $_restorefile ]] && _restorefile="$_mjr"
+        done
+    fi
 
-        # Restore license
-        if [[ -f "$_restorefile" ]]; then
-            if ! "mediacenter${_mversion}" /RestoreFromFile "$_restorefile"; then
-                err "Automatic license restore failed"
-                return 1
-            fi
+    # Restore license
+    if [[ -f "$_restorefile" ]]; then
+        if ! "mediacenter$_mversion" /RestoreFromFile "$_restorefile"; then
+            err "Automatic license restore failed"
+            return 1
         fi
-    }
-
+    fi
+}
 
-    #######################################
-    # Opens ports using the system firewall tool
-    # Arguments
-    #   Takes one argument, the pre-specified name of the service to enable
-    # Requires:
-    #   ID
-    #   _bash_cmd
-    #   _firewall_cmd
-    #   _port
-    # Returns:
-    #   0 if ports opened sucessfully, 1 if not
-    #######################################
-    _openFirewall() {
-        debug "Running: ${FUNCNAME[0]}" "$@"
-
-        # Create OS-specific port rules based on argument (service) name
-        local -a _f_ports # for firewall-cmd
-        local _u_ports # for ufw
-        if [[ "$1" == "jriver" ]]; then
-            _f_ports=("52100-52200/tcp" "1900/udp")
-            _u_ports="52100:52200/tcp|1900/udp"
-        elif [[ "$1" =~ ^(jriver-x11vnc|jriver-xvnc)$ ]]; then
-            _f_ports=("$_port/tcp")
-            _u_ports="$_port/tcp"
-        else
-            err "_openFirewall unrecognized service name"
-            exit 1
-        fi
 
-        # Open the ports
-        if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
-            [[ ! -x $(command -v firewall-cmd) ]] && _installPackage firewalld
-            if ! _firewall_cmd --get-services | grep -q "$1"; then
-                _firewall_cmd --permanent --new-service="$1" > /dev/null 2>&1
-                _firewall_cmd --permanent --service="$1" --set-description="$1 installed by installJRMC" > /dev/null 2>&1
-                _firewall_cmd --permanent --service="$1" --set-short="$1" > /dev/null 2>&1
-                for _f_port in "${_f_ports[@]}"; do
-                    _firewall_cmd --permanent --service="$1" --add-port="$_f_port" > /dev/null 2>&1
-                done
-                _firewall_cmd --add-service "$1" --permanent > /dev/null 2>&1
-                _firewall_cmd --reload > /dev/null 2>&1
-            fi
-        elif [[ "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
-            # Debian ufw package state is broken on fresh installations
-            [[ ! -x $(command -v ufw) ]] && _installPackage ufw
-            if [[ ! -f "/etc/ufw/applications.d/$1" ]]; then
-                _bash_cmd "cat <<- EOF > /etc/ufw/applications.d/$1
-					[$1]
-					title=$1
-					description=$1 installed by installJRMC
-					ports=$_u_ports
-				EOF"
-            fi
-            _firewall_cmd app update "$1"
-            _firewall_cmd allow "$1" > /dev/null 2>&1
+#######################################
+# Opens ports using the system firewall tool
+# Arguments
+#   Service to enable (pre-defined)
+# Requires:
+#   ID
+#   _bash_cmd
+#   _firewall_cmd
+#   _port
+# Returns:
+#   0 if ports opened sucessfully, 1 if not
+#######################################
+_openFirewall() {
+    debug "Running: ${FUNCNAME[0]}" "$@"
+
+    # Create OS-specific port rules based on argument (service) name
+    local -a _f_ports # for firewall-cmd
+    local _u_ports # for ufw
+    if [[ "$1" == "jriver" ]]; then
+        _f_ports=("52100-52200/tcp" "1900/udp")
+        _u_ports="52100:52200/tcp|1900/udp"
+    elif [[ "$1" =~ ^(jriver-x11vnc|jriver-xvnc)$ ]]; then
+        _f_ports=("$_port/tcp" "1900/udp")
+        _u_ports="$_port/tcp|1900/udp"
+    fi
+
+    # Open the ports
+    if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
+        [[ ! -x $(command -v firewall-cmd) ]] && _installPackage firewalld
+        if ! _firewall_cmd --get-services | grep -q "$1"; then
+            _firewall_cmd --permanent --new-service="$1" > /dev/null 2>&1
+            _firewall_cmd --permanent --service="$1" --set-description="$1 installed by installJRMC" > /dev/null 2>&1
+            _firewall_cmd --permanent --service="$1" --set-short="$1" > /dev/null 2>&1
+            for _f_port in "${_f_ports[@]}"; do
+                _firewall_cmd --permanent --service="$1" --add-port="$_f_port" > /dev/null 2>&1
+            done
+            _firewall_cmd --add-service "$1" --permanent > /dev/null 2>&1
+            _firewall_cmd --reload > /dev/null 2>&1
         fi
-
-        # shellcheck disable=SC2181
-        # Rationale: much more concise to check exit codes at the end
-        if [[ $? -ne 0 ]]; then
-            err "Firewall ports could not be opened"
-            return 1
+    elif [[ "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
+        # Debian ufw package state is broken on fresh installations
+        [[ ! -x $(command -v ufw) ]] && _installPackage ufw
+        if [[ ! -f "/etc/ufw/applications.d/$1" ]]; then
+            _bash_cmd "cat <<- EOF > /etc/ufw/applications.d/$1
+				[$1]
+				title=$1
+				description=$1 installed by installJRMC
+				ports=$_u_ports
+			EOF"
         fi
-    }
+        _firewall_cmd app update "$1"
+        _firewall_cmd allow "$1" > /dev/null 2>&1
+    fi
+
+    # shellcheck disable=SC2181
+    # Rationale: much more concise to check exit codes at the end
+    if [[ $? -ne 0 ]]; then
+        err "Firewall ports could not be opened"
+        return 1
+    fi
+}
 
 
-    #######################################
-    # Create the x11vnc password file
-    # Globals:
-    #   _novncauth
-    # Returns:
-    #   0 if password created sucessfully, 1 if not
-    #######################################
-    _setX11VNCPass() {
-        debug "Running: ${FUNCNAME[0]}"
+#######################################
+# Create the x11vnc password file
+# Globals:
+#   _novncauth
+# Returns:
+#   0 if password created sucessfully, 1 if not
+#######################################
+_setX11VNCPass() {
+    debug "Running: ${FUNCNAME[0]}"
 
-        _vncpassfile="$HOME/.vnc/jrmc_passwd"
+    _vncpassfile="$HOME/.vnc/jrmc_passwd"
 
-        [[ ! -d "${_vncpassfile%/*}" ]] && mkdir -p "${_vncpassfile%/*}"
+    [[ ! -d "${_vncpassfile%/*}" ]] && mkdir -p "${_vncpassfile%/*}"
 
-        if [[ -f "$_vncpassfile" ]]; then
-            if [[ ! -v _vncpass ]]; then
-                err "Refusing to overwrite existing $_vncpassfile with an empty password"
-                err "Remove existing $_vncpassfile or set --vncpass to use an empty password"
-                exit 1
-            else
-                rm -f "$_vncpassfile"
-            fi
-        fi
-
-        if [[ -v _vncpass ]]; then
-            if ! x11vnc -storepasswd "$_vncpass" "$_vncpassfile"; then
-                err "Could not create VNC password file"
-                return 1
-            fi
+    if [[ -f "$_vncpassfile" ]]; then
+        if [[ ! -v _vncpass ]]; then
+            err "Refusing to overwrite existing $_vncpassfile with an empty password"
+            err "Remove existing $_vncpassfile or set --vncpass to use an empty password"
+            exit 1
         else
-            _novncauth="true"
+            rm -f "$_vncpassfile"
         fi
-    }
+    fi
 
+    if [[ -v _vncpass ]]; then
+        if ! x11vnc -storepasswd "$_vncpass" "$_vncpassfile"; then
+            err "Could not create VNC password file"
+            return 1
+        fi
+    else
+        _novncauth="true"
+    fi
+}
 
-    #######################################
-    # Create the Xvnc password file
-    # Returns:
-    #   0 if password created sucessfully, 1 if not
-    #######################################
-    _setVNCPass() {
-        debug "Running: ${FUNCNAME[0]}"
 
-        _vncpassfile="$HOME/.vnc/jrmc_passwd"
+#######################################
+# Create the Xvnc password file
+# Returns:
+#   0 if password created sucessfully, 1 if not
+#######################################
+_setVNCPass() {
+    debug "Running: ${FUNCNAME[0]}"
 
-        [[ ! -d "${_vncpassfile%/*}" ]] && mkdir -p "${_vncpassfile%/*}"
+    _vncpassfile="$HOME/.vnc/jrmc_passwd"
 
-        if [[ -f "$_vncpassfile" ]]; then
-            if [[ ! -v _vncpass ]]; then
-                err "Refusing to overwrite existing $_vncpassfile with an empty password"
-                err "Remove existing $_vncpassfile or set --vncpass to use an empty password"
-                exit 1
-            else
-                rm -f "$_vncpassfile"
-            fi
-        fi
+    [[ ! -d "${_vncpassfile%/*}" ]] && mkdir -p "${_vncpassfile%/*}"
 
-        if [[ -v _vncpass ]]; then
-            if ! echo "$_vncpass" | vncpasswd -f > "$_vncpassfile"; then
-                err "Could not create VNC password file"
-                return 1
-            fi
+    if [[ -f "$_vncpassfile" ]]; then
+        if [[ ! -v _vncpass ]]; then
+            err "Refusing to overwrite existing $_vncpassfile with an empty password"
+            err "Remove existing $_vncpassfile or set --vncpass to use an empty password"
+            exit 1
         else
-            _novncauth="true"
+            rm -f "$_vncpassfile"
         fi
-    }
-
-
-    #######################################
-    # Set display and port variables
-    # Globals:
-    #   _display
-    #   _displaynum
-    #   _next_display
-    #   _next_displaynum
-    #######################################
-    _setDisplay() {
-        debug "Running: ${FUNCNAME[0]}"
+    fi
 
-        # Check _display, else DISPLAY, else set to :0 by default
-        if [[ -v _display ]]; then
-            _next_display="$_display"
-        elif [[ -v DISPLAY ]]; then
-            _display="${DISPLAY}"
-            _displaynum="${_display#:}" # strip colon
-            _displaynum="${_displaynum%.*}" # strip suffix
-            _next_displaynum=$(( _displaynum + 1 ))
-            _next_display=":$_next_displaynum"
-        else
-            _display=":0"
-            _next_display=":1"
+    if [[ -v _vncpass ]]; then
+        if ! echo "$_vncpass" | vncpasswd -f > "$_vncpassfile"; then
+            err "Could not create VNC password file"
+            return 1
         fi
+    else
+        _novncauth="true"
+    fi
+}
 
+
+#######################################
+# Set display and port variables
+# Globals:
+#   _display
+#   _displaynum
+#   _next_display
+#   _next_displaynum
+#######################################
+_setDisplay() {
+    debug "Running: ${FUNCNAME[0]}"
+
+    # Check _display, else DISPLAY, else set to :0 by default
+    if [[ -v _display ]]; then
+        _next_display="$_display"
+    elif [[ -v DISPLAY ]]; then
+        _display="${DISPLAY}"
         _displaynum="${_display#:}" # strip colon
         _displaynum="${_displaynum%.*}" # strip suffix
         _next_displaynum=$(( _displaynum + 1 ))
-    }
-
-
-    #######################################
-    # Create associated service variables based on service name
-    # Requires:
-    #   _service_user
-    # Globals:
-    #   _service_fname
-    #   _timer_fname
-    #   _service_name
-    #   _timer_name
-    #   _user_specifier
-    #######################################
-    _servicePrep() {
-        debug "Running: ${FUNCNAME[0]}"
-
-        if [[ "$_service_user" == "root" ]]; then
-            _service_fname="/usr/lib/systemd/system/${1}.service"
-            _timer_fname="/usr/lib/systemd/system/${1}.timer"
-            _service_name="jriver-${1}.service"
-            _timer_name="jriver-${1}}.timer"
-            _user_specifier=""
-        else
-            _service_fname="/usr/lib/systemd/system/${1}@.service"
-            _timer_fname="/usr/lib/systemd/system/${1}@.timer"
-            _service_name="${1}@$_service_user.service"
-            _timer_name="${1}@$_service_user.timer"
-            _user_specifier="User=%I"
-        fi
-    }
+        _next_display=":$_next_displaynum"
+    else
+        _display=":0"
+        _next_display=":1"
+    fi
+
+    _displaynum="${_display#:}" # strip colon
+    _displaynum="${_displaynum%.*}" # strip suffix
+    _next_displaynum=$(( _displaynum + 1 ))
+}
 
 
-    #######################################
-    # SERVICES
-    #######################################
+#######################################
+# Create associated service variables based on service name
+# Requires:
+#   _service_user
+# Globals:
+#   _service_fname
+#   _timer_fname
+#   _service_name
+#   _timer_name
+#   _user_specifier
+#######################################
+_servicePrep() {
+    debug "Running: ${FUNCNAME[0]}"
+
+    if [[ "$_service_user" == "root" ]]; then
+        _service_fname="/usr/lib/systemd/system/${1}.service"
+        _timer_fname="/usr/lib/systemd/system/${1}.timer"
+        _service_name="jriver-${1}.service"
+        _timer_name="jriver-${1}}.timer"
+        _user_specifier=""
+    else
+        _service_fname="/usr/lib/systemd/system/${1}@.service"
+        _timer_fname="/usr/lib/systemd/system/${1}@.timer"
+        _service_name="${1}@$_service_user.service"
+        _timer_name="${1}@$_service_user.timer"
+        _user_specifier="User=%I"
+    fi
+}
 
-    #######################################
-    # Starts and enables (at startup) a JRiver Media Center service
-    # Arguments:
-    #   Passes arguments as startup options to /usr/bin/mediacenter26
-    # Requires:
-    #   XAUTHORITY
-    #######################################
-    _service_jriver-mediacenter() {
-        debug "Running: ${FUNCNAME[0]}"
 
-        _bash_cmd "cat <<- EOF > $_service_fname
-			[Unit]
-			Description=JRiver Media Center $_mversion
-			After=graphical.target
-
-			[Service]
-			$_user_specifier
-			Type=simple
-			Environment=DISPLAY=$_display
-			Environment=XAUTHORITY=$XAUTHORITY
-			ExecStart=/usr/bin/mediacenter$_mversion $*
-			Restart=always
-			RestartSec=10
-			KillSignal=SIGHUP
-			TimeoutStopSec=30
-
-			[Install]
-			WantedBy=graphical.target
-		EOF"
-        _systemctl_reload && \
-        _systemctl_start "$_service_name" && \
-        _systemctl_enable "$_service_name" && \
-        _openFirewall "jriver"
-    }
+#######################################
+# Starts and enables (at startup) a JRiver Media Center service
+# Arguments:
+#   Passes arguments as startup options to /usr/bin/mediacenter26
+# Requires:
+#   XAUTHORITY
+#######################################
+_service_jriver-mediacenter() {
+    debug "Running: ${FUNCNAME[0]}"
+
+    _bash_cmd "cat <<- EOF > $_service_fname
+		[Unit]
+		Description=JRiver Media Center $_mversion
+		After=graphical.target
+
+		[Service]
+		$_user_specifier
+		Type=simple
+		Environment=DISPLAY=$_display
+		Environment=XAUTHORITY=$XAUTHORITY
+		ExecStart=/usr/bin/mediacenter$_mversion $*
+		Restart=always
+		RestartSec=10
+		KillSignal=SIGHUP
+		TimeoutStopSec=30
+
+		[Install]
+		WantedBy=graphical.target
+	EOF"
+
+    _systemctl_reload && \
+    _systemctl_enable "$_service_name" && \
+    _openFirewall "jriver"
+}
 
 
-    #######################################
-    # Starts and enables (at startup) a JRiver Media Server service
-    #######################################
-    _service_jriver-mediaserver() {
-        debug "Running: ${FUNCNAME[0]}"
+#######################################
+# Starts and enables (at startup) a JRiver Media Server service
+#######################################
+_service_jriver-mediaserver() {
+    debug "Running: ${FUNCNAME[0]}"
 
-        _service_jriver-mediacenter "/MediaServer"
-    }
+    _service_jriver-mediacenter "/MediaServer"
+}
 
 
-    #######################################
-    # Starts and enables (at startup) JRiver Media Center in a new Xvnc session
-    #######################################
-    _service_jriver-xvnc-mediacenter() {
-        debug "Running: ${FUNCNAME[0]}"
+#######################################
+# Starts and enables (at startup) JRiver Media Center in a new Xvnc session
+#######################################
+_service_jriver-xvnc-mediacenter() {
+    debug "Running: ${FUNCNAME[0]}"
+
+    _installPackage tigervnc-server
+
+    _setVNCPass
+
+    local _port=$(( _next_displaynum + 5900 ))
+
+    if [[ -v _novncauth ]]; then
+        _exec_start_cmd="/usr/bin/vncserver $_next_display -geometry 1440x900 -alwaysshared -name jriver$_next_display -SecurityTypes None -autokill -xstartup /usr/bin/mediacenter$_mversion"
+    else
+        _exec_start_cmd="/usr/bin/vncserver $_next_display -geometry 1440x900 -alwaysshared -rfbauth $HOME/.vnc/jrmc_passwd -autokill -xstartup /usr/bin/mediacenter$_mversion"
+    fi
+
+    _bash_cmd "cat <<- EOF > $_service_fname
+		[Unit]
+		Description=Remote desktop service (VNC)
+		After=syslog.target network.target
+
+		[Service]
+		Type=simple
+		$_user_specifier
+		ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill $_next_display > /dev/null 2>&1 || :'
+		ExecStart=$_exec_start_cmd
+		ExecStop=/usr/bin/vncserver -kill $_next_display
+		Restart=always
+
+		[Install]
+		WantedBy=multi-user.target
+	EOF"
+
+    _systemctl_reload && \
+    _systemctl_enable "$_service_name" && \
+    echo "Xvnc running on localhost:$_port" && \
+    _openFirewall "jriver-xvnc" && \
+    _openFirewall "jriver"
+}
 
-        _installPackage tigervnc-server
 
-        _setVNCPass
+#######################################
+# Starts and enables (at startup) JRiver Media Server and x11vnc sharing the local desktop
+#######################################
+_service_jriver-x11vnc() {
+    debug "Running: ${FUNCNAME[0]}"
 
-        local _port=$(( _next_displaynum + 5900 ))
+    _installPackage x11vnc
 
-        if [[ -v _novncauth ]]; then
-            _exec_start_cmd="/usr/bin/vncserver $_next_display -geometry 1440x900 -alwaysshared -name jriver$_next_display -SecurityTypes None -autokill -xstartup /usr/bin/mediacenter$_mversion"
-        else
-            _exec_start_cmd="/usr/bin/vncserver $_next_display -geometry 1440x900 -alwaysshared -rfbauth $HOME/.vnc/jrmc_passwd -autokill -xstartup /usr/bin/mediacenter$_mversion"
-        fi
+    _setX11VNCPass
 
-        _bash_cmd "cat <<- EOF > $_service_fname
-			[Unit]
-			Description=Remote desktop service (VNC)
-			After=syslog.target network.target
-
-			[Service]
-			Type=simple
-			$_user_specifier
-			ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill $_next_display > /dev/null 2>&1 || :'
-			ExecStart=$_exec_start_cmd
-			ExecStop=/usr/bin/vncserver -kill $_next_display
-			Restart=always
-
-			[Install]
-			WantedBy=multi-user.target
-		EOF"
-
-        _systemctl_reload && \
-        _systemctl_start "$_service_name" && \
-        _systemctl_enable "$_service_name" && \
-        echo "Xvnc running on localhost:$_port" && \
-        _openFirewall "jriver-xvnc" && \
-        _openFirewall "jriver"
-    }
+    local _port=$(( _displaynum + 5900 ))
 
+    # Get current desktop resolution
+    # TODO: may need to break this out into its own function and get smarter at identifying multi-monitors
+    _getResolution() {
 
-    #######################################
-    # Starts and enables (at startup) JRiver Media Server and x11vnc sharing the local desktop
-    #######################################
-    _service_jriver-x11vnc() {
         debug "Running: ${FUNCNAME[0]}"
 
-        _installPackage x11vnc
-
-        _setX11VNCPass
-
-        local _port=$(( _displaynum + 5900 ))
-
-        # Get current desktop resolution
-        # TODO: may need to break this out into its own function and get smarter at identifying multi-monitors
-        _getResolution() {
-
-            debug "Running: ${FUNCNAME[0]}"
-
-            _installPackage xorg-x11-utils
-            _res=$(xdpyinfo | grep dimensions | awk '{print $2}')
-        }
-        _getResolution
-
-        if [[ -v _novncauth ]]; then
-            _exec_start_cmd="/usr/bin/x11vnc -display $_display -noscr -geometry $_res -auth guess -forever -bg -nopw"
-        else
-            _exec_start_cmd="/usr/bin/x11vnc -display $_display -noscr -geometry $_res -auth guess -forever -bg -rfbauth $HOME/.vnc/jrmc_passwd"
-        fi
-
-        _bash_cmd "cat <<-EOF > $_service_fname
-			[Unit]
-			Description=x11vnc
-			After=multi.service
-
-			[Service]
-			$_user_specifier
-			Type=forking
-			Environment=DISPLAY=$_display
-			ExecStart=$_exec_start_cmd
-			Restart=always
-			RestartSec=10
-
-			[Install]
-			WantedBy=multi-user.target
-		EOF"
-
-        _systemctl_reload && \
-        _systemctl_start "$_service_name" && \
-        _systemctl_enable "$_service_name" && \
-        echo "x11vnc running on localhost:$_port" && \
-        _openFirewall "jriver-x11vnc"
+        _installPackage xorg-x11-utils
+        _res=$(xdpyinfo | grep dimensions | awk '{print $2}')
     }
+    _getResolution
+
+    if [[ -v _novncauth ]]; then
+        _exec_start_cmd="/usr/bin/x11vnc -display $_display -noscr -geometry $_res -auth guess -forever -bg -nopw"
+    else
+        _exec_start_cmd="/usr/bin/x11vnc -display $_display -noscr -geometry $_res -auth guess -forever -bg -rfbauth $HOME/.vnc/jrmc_passwd"
+    fi
+
+    _bash_cmd "cat <<-EOF > $_service_fname
+		[Unit]
+		Description=x11vnc
+		After=multi.service
+
+		[Service]
+		$_user_specifier
+		Type=forking
+		Environment=DISPLAY=$_display
+		ExecStart=$_exec_start_cmd
+		Restart=always
+		RestartSec=10
+
+		[Install]
+		WantedBy=multi-user.target
+	EOF"
+
+    _systemctl_reload && \
+    _systemctl_enable "$_service_name" && \
+    echo "x11vnc running on localhost:$_port" && \
+    _openFirewall "jriver-x11vnc"
+}
 
 
-    #######################################
-    # Starts and enables (at startup) an hourly service to build the latest version of JRiver Media
-    # Center RPM from the source DEB and create/update an RPM repository
-    #######################################
-    _service_jriver-createrepo() {
-        debug "Running: ${FUNCNAME[0]}"
-
-        _bash_cmd "cat <<-EOF > $_service_fname
-			[Unit]
-			Description=Builds JRiver Media Center RPM file, moves it to the repo dir, and runs createrepo
-
-			[Service]
-			$_user_specifier
-			ExecStart=$_basedir/installJRMC --outputdir $_outputdir --createrepo --createrepo-webroot $_createrepo_webroot --createrepo-user $_createrepo_user
-
-			[Install]
-			WantedBy=default.target
-		EOF"
-
-        _bash_cmd "cat <<-EOF > $_timer_fname
-			[Unit]
-			Description=Run JRiver MC rpmbuild hourly
-
-			[Timer]
-			OnCalendar=hourly
-			Persistent=true
-
-			[Install]
-			WantedBy=timers.target
-		EOF"
-
-        _systemctl_reload && \
-        _systemctl_start "$_timer_name" && \
-        _systemctl_enable "$_timer_name"
-    }
-
-
-    #######################################
-    # CONTAINERS
-    #######################################
-    _containerCreaterepo() {
-        :
-    }
-
-
-    _containerVNC() {
-        :
-    }
-
-
-    _containerMC() {
-        :
-    }
-
-
-    #######################################
-    # Complete uninstall
-    #######################################
-    _uninstall() {
-        debug "Running: ${FUNCNAME[0]}"
-
-        read -r -p "Do you really want to uninstall JRiver Media Center? [y/N] " _response
-        _response=${_response,,}    # tolower
-        [[ ! "$_response" =~ ^(yes|y)$ ]] && echo "Cancelling uninstall..." && exit 0
-
-        # Uninstall services
-        echo "Stopping and removing all associated Media Center services"
-        for _service in "${_available_services[@]}"; do
-            _servicePrep "$_service"
-            _systemctl_disable "$_service_name"
-            _systemctl_disable "$_timer_name"
-            [[ -f "$_service_fname" ]] && _rm_cmd "$_service_fname"
-            [[ -f "$_timer_fname" ]] && _rm_cmd "$_timer_fname"
-        done
-
-        echo "Removing repo files"
-        [[ -f "/etc/yum.repos.d/jriver.repo" ]] \
-            && _rm_cmd "/etc/yum.repos.d/jriver.repo"
-        [[ -f "/etc/apt/sources.list.d/jriver.list" ]] \
-            && _rm_cmd "/etc/apt/sources.list.d/jriver.list"
-
-        echo "Removing firewall rules"
-        if [[ -x $(command -v firewall-cmd) ]]; then
-            _firewall_cmd --permanent --remove-service=jriver
-            _firewall_cmd --permanent --delete-service=jriver
-            _firewall_cmd --reload
-        elif [[ -x $(command -v ufw) ]]; then
-            _firewall_cmd delete allow jriver
-            [[ -f "/etc/ufw/applications.d/jriver" ]] \
-                && _rm_cmd /etc/ufw/applications.d/jriver
-        fi
-
-        echo "Uninstalling Media Center"
-        if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
-            _pkg_remove MediaCenter
-        elif [[ "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
-            _pkg_remove "mediacenter$_mversion"
-        fi
+#######################################
+# Starts and enables (at startup) an hourly service to build the latest version of JRiver Media
+# Center RPM from the source DEB and create/update an RPM repository
+#######################################
+_service_jriver-createrepo() {
+    debug "Running: ${FUNCNAME[0]}"
 
-        echo "JRiver Media Center has been completely uninstalled"
-        echo "If you wish to remove your library files: rm -rf $HOME/.jriver"
-        echo "If you wish to remove your rpmbuild output files: rm -rf $_outputdir"
-    }
+    _bash_cmd "cat <<-EOF > $_service_fname
+		[Unit]
+		Description=Builds JRiver Media Center RPM file, moves it to the repo dir, and runs createrepo
 
+		[Service]
+		$_user_specifier
+		ExecStart=$PWD/installJRMC --outputdir $_outputdir --createrepo --createrepo-webroot $_createrepo_webroot --createrepo-user $_createrepo_user
 
-    _main() {
+		[Install]
+		WantedBy=default.target
+	EOF"
 
-        # Parse input
-        _parseInput "$@"
+    _bash_cmd "cat <<-EOF > $_timer_fname
+		[Unit]
+		Description=Run JRiver MC rpmbuild hourly
 
-        # Sanity checks
-        _sanityChecks
+		[Timer]
+		OnCalendar=hourly
+		Persistent=true
 
-        # Set user variables
-        _setUser
+		[Install]
+		WantedBy=timers.target
+	EOF"
 
-        # Build some OS-specific commands based on the selected OS
-        _buildCommands
+    _systemctl_reload && \
+    _systemctl_enable "$_timer_name"
+}
 
-        # Install MC using package manager
-        if [[ -v _repoinstall ]]; then
-            [[ "$ID" =~ ^(fedora|centos)$ ]] && _installPackage rpmfusion-free-release epel-release
-            _installMCFromRepo
-            _symlinkCerts
-            _restoreLicense
-            _openFirewall "jriver"
-        fi
 
-        # Set version to install/uninstall
-        _setVersion
+#######################################
+# CONTAINERS
+#######################################
+_containerCreaterepo() {
+    :
+}
 
-        # Uninstall and exit
-        if [[ -v _uninstall ]]; then
-            _uninstall
-            exit $?
-        fi
 
-        # Build RPM from source DEB
-        if [[ -v _rpmbuild ]]; then
-            _installPackage epel-release
-            _acquireDeb
-            _buildRPM
-        fi
+_containerVNC() {
+    :
+}
 
-        # Run createrepo
-        if [[ -v _createrepo ]]; then
-            _runCreaterepo "$_mcrpm"
-        fi
 
-        # Install the rpm
-        if [[ -v _rpminstall ]]; then
-            if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
-                _installPackage rpmfusion-free-release epel-release
-                _installPackage --noquery "$_mcrpm"
-                _symlinkCerts
-                _restoreLicense
-                _openFirewall "jriver"
-            fi
-        fi
+_containerMC() {
+    :
+}
 
-        # Install services
-        _setDisplay
-        for _service in "${_services[@]}"; do
-            _servicePrep "$_service"
-            "_service_$_service"
-        done
 
-        # Install containers
-        for _container in "${_containers[@]}"; do
-            "_container_$_container"
-        done
-    }
+#######################################
+# Complete uninstall
+#######################################
+_uninstall() {
+    debug "Running: ${FUNCNAME[0]}"
+
+    read -r -p "Do you really want to uninstall JRiver Media Center? [y/N] " _response
+    _response=${_response,,}    # tolower
+    [[ ! "$_response" =~ ^(yes|y)$ ]] && echo "Cancelling uninstall..." && exit 0
+
+    # Uninstall services
+    echo "Stopping and removing all associated Media Center services"
+    for _service in $(compgen -A "function" "_service"); do 
+        _servicePrep "$_service"
+        _systemctl_disable "$_service_name"
+        _systemctl_disable "$_timer_name"
+        [[ -f "$_service_fname" ]] && _rm_cmd "$_service_fname"
+        [[ -f "$_timer_fname" ]] && _rm_cmd "$_timer_fname"
+    done
+
+    echo "Removing repo files"
+    [[ -f "/etc/yum.repos.d/jriver.repo" ]] \
+        && _rm_cmd "/etc/yum.repos.d/jriver.repo"
+    [[ -f "/etc/apt/sources.list.d/jriver.list" ]] \
+        && _rm_cmd "/etc/apt/sources.list.d/jriver.list"
+
+    echo "Removing firewall rules"
+    if [[ -x $(command -v firewall-cmd) ]]; then
+        _firewall_cmd --permanent --remove-service=jriver
+        _firewall_cmd --permanent --delete-service=jriver
+        _firewall_cmd --reload
+    elif [[ -x $(command -v ufw) ]]; then
+        _firewall_cmd delete allow jriver
+        [[ -f "/etc/ufw/applications.d/jriver" ]] \
+            && _rm_cmd /etc/ufw/applications.d/jriver
+    fi
+
+    echo "Uninstalling Media Center"
+    if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
+        _pkg_remove MediaCenter
+    elif [[ "$ID" =~ ^(debian|ubuntu|linuxmint)$ ]]; then
+        _pkg_remove "mediacenter$_mversion"
+    fi
+
+    echo "JRiver Media Center has been completely uninstalled"
+    echo "If you wish to remove your library files: rm -rf $HOME/.jriver"
+    echo "If you wish to remove your rpmbuild output files: rm -rf $_outputdir"
 }
 
-# Allow this file to be executed directly if not being sourced
-if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
-    _basedir=$(dirname "$(readlink -f "$0")")
-    installJRMC
-    _main "$@"
-fi
+
+_main "$@"