Files
installJRMC/installJRMC
2020-04-25 09:27:23 -04:00

1355 lines
42 KiB
Bash
Executable File

#!/usr/bin/env bash
shopt -s extglob
#######################################
# This script will download, build, and install JRiver Media Center with optional systemd services
# on Fedora, CentOS, Debian, and Ubuntu
#
# Run installJRMC --help to see available options
#
# To-dos:
# 1. Raspberry Pi support -- do not own one so difficult to test
# 2. Arch support -- would love some testing and PRs
# 3. ncurses graphical installer
# 4. Refactor to generalize functions
#
# installJRMC can be run directly or sourced as a function (by sourcing this file)
# Arguments:
# see _printHelpAndExit() and/or check getopt's in _parseInput() for available options
# Returns:
# 0 if critical functions complete successfully
#######################################
installJRMC() {
_scriptversion="0.2"
_boardurl="https://yabb.jriver.com/interact/index.php/board,64.0.html"
_outputdir="$_basedir/output"
_createrepo_webroot="/srv/jriver"
_createrepo_user="$(whoami)"
_user="$(whoami)"
_available_services=("createrepo" "x11vnc" "mediaserver" "mediacenter" "vncserver")
#_available_containers=("mediacenter-vncserver" "createrepo")
_printHelpAndExit() {
_runDebug "${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-rpmbuild
(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: scrape the latest version from Interact)
--restorefile RESTOREFILE
Restore file location for registration (Default: skip registration)
--betapass PASSWORD
Enter beta team password for access to beta builds
--service, -s SERVICE
See SERVICES section below for a list of possible services to install
--container, -c CONTAINER
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
--force, -f
Force reinstallation and ignore/overwrite previous 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
mediaserver
Enable and start a mediaserver systemd service (requires an existing X server)
mediacenter
Enable and start a mediacenter systemd service (requires an existing X server)
x11vnc
Enable and start x11vnc for the local desktop (requires an existing X server)
--vncpass and --display are valid options (see below)
mediacenter-vncserver
Enable and start a vncserver running JRiver Media Center
--vncpass PASSWORD
Set vnc password for x11vnc 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 vncserver/x11vnc (Default: The current display or :0 if current display
is unaccessible)
createrepo
Install hourly service to build latest MC RPM and run createrepo
CONTAINERS
mediacenter-vncserver (Under construction!)
createrepo (Under construction!)
EOF
# Exit using passed exit code
[[ -z $1 ]] && exit 0 || exit "$1"
}
_parseInput() {
_runDebug "${FUNCNAME[0]}"
if _input=$(getopt -o +vdhus:c: -l install-repo,install-rpmbuild,rpmbuild,outputdir:,mcversion:,restorefile:,betapass:,service:,version,debug,force,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-rpmbuild)
_rpmbuild="true"
_rpminstall="true"
;;
--rpmbuild)
_rpmbuild="true"
;;
--outputdir)
shift && _outputdir="$1"
;;
--mcversion)
shift && _mcversion="$1"
;;
--restorefile)
shift && _restorefile="$1"
;;
--betapass)
shift && _betapass="$1"
;;
--service|-s)
shift && _services+=("$1")
;;
--container|-c)
shift && _containers+=("$1")
;;
--version|-v)
echo "Version: $_scriptversion"
exit 0
;;
--debug|-d)
echo "Debugging on"
_debug="true"
;;
--force|-f)
_force="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
}
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
#######################################
# Call this at the beginning of every function in order to track
#######################################
_runDebug() {
[[ -n $_debug ]] && echo "Running: " "$@"
}
#######################################
# Prepend this to any command that you wish to execute with sudo (i.e. when _user is NOT root)
#######################################
_ifSudo() {
if [[ "$_user" != "root" ]]; then
sudo "$@"
else
"$@"
fi
}
_checkUser() {
_runDebug "${FUNCNAME[0]}"
if [[ "$_user" == "root" ]]; then
cat <<EOF
Warning! You are currently running installJRMC as the root user. This is not recommended! When
running as a regular user, installJRMC will ask you for your sudo password when necessary.
Installation will continue but any systemd services will be installed as system services and you
may run into permissions issues.
EOF
else
[[ -n $_debug ]] && echo "Installing as user: $_user"
fi
}
#######################################
# Sources /etc/os-release so we know which OS we're running on
# Used in: _buildCommands()
#######################################
_getOS() {
_runDebug "${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
fi
[[ -n $_debug ]] && echo "Platform: $ID $VERSION_ID"
}
#######################################
# Creates some OS-specific functions to query, install, and remove packages and edit
# firewalls, run bash, remove and copy files, etc.
# Requires:
# ID
# _createrepo_user
# _createrepo_webroot
# Globals:
# _bash_cmd
# _rm_cmd
# _cp_cmd
# _mkdir_cmd
# _ln_cmd
# _createrepo_cmd
# _pkg_install
# _pkg_reinstall
# _pkg_install_nogpg
# _pkg_remove
# _pkg_update
# _pkg_query
# _firewall_cmd
# _systemctl_reload
# _systemctl_enable
# _systemctl_disable
#######################################
_buildCommands() {
# Detect OS
_getOS
_runDebug "${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_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" =~ ^(ubuntu|debian)$ ]]; then
_pkg_install(){ _ifSudo apt-get install -y "$@"; }
_pkg_reinstall(){ _ifSudo apt-get reinstall -y "$@"; }
_pkg_install_nogpg(){ _ifSudo apt-get install -y "$@"; }
_pkg_remove(){ _ifSudo apt-get remove -y "$@"; }
_pkg_update(){ _ifSudo apt-get update -y; }
_pkg_query(){ _ifSudo dpkg -l "$@"; }
_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
_mkdir_cmd(){ sudo -u "$_createrepo_user" mkdir -p "$@"; }
_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
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() {
_runDebug "${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 [[ -n $_noquery ]] || ! _pkg_query "$_pkg" > /dev/null 2>&1; then
if [[ -n $_url_pkg ]]; then
_url_pkg_array+=("$_url_pkg")
else
_pkg_array+=("$_pkg")
fi
fi
fi
done
# Install from package name (with gpg check)
if [[ ${#_pkg_array[@]} -ge 1 ]]; then
echo "Installing:" "${_pkg_array[@]}"
if [[ -n $_debug ]]; then
if ! _pkg_install "${_pkg_array[@]}"; then
err "Failed to install required package"
exit 1
fi
elif ! _pkg_install "${_pkg_array[@]}" > /dev/null 2>&1; then
err "Failed to install dependency."
_printHelpAndExit 1
fi
fi
# Install from package url (without gpg check)
if [[ ${#_url_pkg_array[@]} -ge 1 ]]; then
echo "Installing:" "${_url_pkg_array[@]}"
if [[ -n $_debug ]]; then
if ! _pkg_install_nogpg "${_url_pkg_array[@]}"; then
err "Failed to install required package from url"
exit 1
fi
elif ! _pkg_install_nogpg "${_url_pkg_array[@]}" > /dev/null 2>&1; then
err "Failed to install required package from url"
_printHelpAndExit 1
fi
fi
}
#######################################
# Handles OS-specific package name tweaks and source urls
# Arguments:
# A package name
# Globals:
# _pkg
# _url_pkg
#######################################
_packageQuirks() {
_runDebug "${FUNCNAME[0]}" "$@"
unset _url_pkg
if [[ "$1" == "rpm-build" && "$ID" =~ ^(ubuntu|debian)$ ]]; then
_pkg="rpm"
elif [[ "$1" == "createrepo_c" && "$ID" =~ ^(ubuntu|debian)$ ]]; 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" =~ ^(ubuntu|debian)$ ]]; then
_pkg="tigervnc-standalone-server"
else
_pkg="$1"
fi
}
#######################################
# Get our MC working version from input argument or scraping Interact
# Requires:
# _boardurl
# _installPackage
# Globals:
# _mcversion (i.e. "26.0.12")
# _mversion (i.e. "26")
#######################################
_setVersion() {
_runDebug "${FUNCNAME[0]}"
if [[ -z "$_mcversion" ]]; 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
else
echo "$_mcversion"
fi
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() {
_runDebug "${FUNCNAME[0]}"
# Check for bad service name
#
_checkServices() {
for _service in "${_services[@]}"; do
if ! _inArray "$_service" "${_available_services[@]}"; then
echo "Incorrect service type provided!"
_printHelpAndExit 1
fi
done
}
_checkMCInstalled() {
if [[ "${_services[*]}" =~ ^(mediacenter|mediaserver)$ ]]; then
if [[ -z $_repoinstall && -z $_rpminstall ]]; then
if [[ -x $(command -v "mediacenter$_mversion") ]]; then
err "You are attempting to install a service that relies on mediacenter$_mversion but --repo-install/--rpmbuild-install are not set and mediacenter$_mversion is not present"
_printHelpAndExit 1
fi
fi
fi
}
# Disable sanity checks for now to simplify debugging
_checkServices
_checkMCInstalled
}
#######################################
# Installs JRiver Media Center from a repository
# Returns:
# 0 if JRiver Media Center installed sucessfully
#######################################
_installMCFromRepo() {
_runDebug "${FUNCNAME[0]}"
echo "Installing latest JRiver Media Center from repo..."
# 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'
local _mcpkg="MediaCenter"
elif [[ "$ID" =~ ^(ubuntu|debian)$ ]]; then
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/ jessie main
EOF'
local _mcpkg="mediacenter$_mversion"
fi
# Update packages and install JRiver Media Center
if [[ -n $_debug ]]; then
_pkg_update && \
_pkg_install "$_mcpkg"
else
_pkg_update > /dev/null 2>&1 && \
_pkg_install "$_mcpkg" > /dev/null 2>&1
fi
# shellcheck disable=SC2181
# Rationale: More compact to check this once
if [[ $? -eq 0 ]]; then
echo "JRiver Media Center installed successfully!"
return 0
else
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() {
_runDebug "${FUNCNAME[0]}"
local _debfilename="$_outputdir/SOURCES/MediaCenter-${_mcversion}-amd64.deb"
# 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 [[ -n $_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() {
_runDebug "${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'
else
local _build_requires=''
fi
if [[ "$ID" != "centos" ]]; then
local _requires='Requires: pangox-compat >= 0.0.2'
else
local _requires='Requires: libXScrnSaver'
fi
# Create spec file
bash -c "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
Requires: xdg-utils
Requires: libgomp >= 4.9
Requires: gstreamer1 >= 1.4.4
Requires: gstreamer1-plugins-base >= 1.4.4
Requires: nss >= 3.26
Requires: nspr >= 4.12
Requires: ca-certificates
Requires: python3
Recommends: vorbis-tools >= 1.4.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/
%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}
/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" && -z "$_force" ]]; then
echo "$_mcrpm already exists! Skipping build step..."
return 0 # this is fine
else
# Run rpmbuild
echo "Building version $_mcversion, please wait..."
if [[ -n $_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
fi
fi
}
#######################################
# 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() {
_runDebug "${FUNCNAME[0]}"
_installPackage createrepo_c
# If the webroot does not exist, create it
if [[ ! -d "$_createrepo_webroot" ]]; then
if ! _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 ! _cp_cmd "$1" "$_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!"
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
# them on Debian/Ubuntu
# Returns:
# 0 if symlinking is unecessary or successful, 1 if not
#######################################
_symlinkCerts() {
_runDebug "${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
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() {
_runDebug "${FUNCNAME[0]}"
local _mjr
# Allow user to drop an mjr file next to installJRMC
if [[ -z $_restorefile ]]; then
for _mjr in "$_basedir"/*.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
fi
}
#######################################
# Open the default JRiver Media Center ports using the system firewall tool
# Requires:
# ID
# _bash_cmd
# _firewall_cmd
# Returns:
# 0 if ports opened sucessfully, 1 if not
#######################################
_openFirewall() {
_runDebug "${FUNCNAME[0]}"
if [[ "$ID" =~ ^(fedora|centos)$ ]] && [[ -x $(command -v firewall-cmd) ]]; then
if ! firewall-cmd --get-services | grep -q jriver; then
if [[ -n $_debug ]]; then
_firewall_cmd --permanent --new-service=jriver
_firewall_cmd --permanent --service=jriver --set-description="JRiver Media Center Media Server"
_firewall_cmd --permanent --service=jriver --set-short="jriver"
_firewall_cmd --permanent --service=jriver --add-port=52100-52200/tcp
_firewall_cmd --permanent --service=jriver --add-port=1900/udp
_firewall_cmd --reload
else
_firewall_cmd --permanent --new-service=jriver > /dev/null 2>&1
_firewall_cmd --permanent --service=jriver --set-description="JRiver Media Center Media Server" > /dev/null 2>&1
_firewall_cmd --permanent --service=jriver --set-short="jriver" > /dev/null 2>&1
_firewall_cmd --permanent --service=jriver --add-port=52100-52200/tcp > /dev/null 2>&1
_firewall_cmd --permanent --service=jriver --add-port=1900/udp > /dev/null 2>&1
_firewall_cmd --reload > /dev/null 2>&1
fi
fi
elif [[ "$ID" =~ ^(ubuntu|debian)$ ]] && [[ -x $(command -v ufw) ]]; then
if [[ ! -f "/etc/ufw/applications.d/jriver.service" ]]; then
_bash_cmd "cat <<-EOF > /etc/ufw/applications.d/jriver.service
[jriver]
title=JRiver Media Center
description=Allows JRiver Media Server access
ports=52100:52200/tcp|1900/udp
EOF"
fi
if [[ -n $_debug ]]; then
_firewall_cmd allow jriver
else
_firewall_cmd allow jriver > /dev/null 2>&1
fi
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() {
_runDebug "${FUNCNAME[0]}"
_vncpassfile="$HOME/.vnc/jrmc_passwd"
[[ ! -d "${_vncpassfile%/*}" ]] && mkdir -p "${_vncpassfile%/*}"
if [[ -f "$_vncpassfile" ]]; then
if [[ -z $_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 [[ -n $_vncpass ]]; then
if ! x11vnc -storepasswd "$_vncpass" "$_vncpassfile"; then
err "Could not create VNC password file"
return 1
fi
else
_novncauth="true"
fi
}
#######################################
# Create the vncserver password file
# Returns:
# 0 if password created sucessfully, 1 if not
#######################################
_setVNCPass() {
_runDebug "${FUNCNAME[0]}"
_vncpassfile="$HOME/.vnc/jrmc_passwd"
[[ ! -d "${_vncpassfile%/*}" ]] && mkdir -p "${_vncpassfile%/*}"
if [[ -f "$_vncpassfile" ]]; then
if [[ -z $_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 [[ -n $_vncpass ]]; then
if ! echo "$_vncpass" | vncpasswd -f > "$_vncpassfile"; then
err "Could not create VNC password file"
return 1
fi
else
_novncauth="true"
fi
}
#######################################
# Create associated service variables based on service name
# Arguments:
# Requires exactly one argument, the name of the service to parse
#######################################
_servicePrep() {
if [[ "$_user" == "root" ]]; then
_service_fname="/usr/lib/systemd/system/jriver-${1}.service"
_timer_fname="/usr/lib/systemd/system/jriver-${1}.timer"
_service_name="jriver-${1}.service"
_timer_name="jriver-${1}}.timer"
_user_specifier=""
else
_service_fname="/usr/lib/systemd/system/jriver-${1}@.service"
_timer_fname="/usr/lib/systemd/system/jriver-${1}@.timer"
_service_name="jriver-${1}@$_user.service"
_timer_name="jriver-${1}@$_user.timer"
_user_specifier="User=%I"
fi
}
#######################################
# SERVICES
#######################################
_serviceMediaserver() {
_runDebug "${FUNCNAME[0]}"
[[ -z $_display ]] && _display="${DISPLAY:-":0"}"
_bash_cmd "cat <<-EOF > $_service_fname
[Unit]
Description=JRiver Media Center $_mversion Media Server
After=graphical.target
[Service]
$_user_specifier
Type=simple
Environment=DISPLAY=$_display
Environment=XAUTHORITY=$XAUTHORITY
ExecStart=/usr/bin/mediacenter$_mversion /MediaServer
Restart=always
RestartSec=10
KillSignal=SIGHUP
TimeoutStopSec=30
[Install]
WantedBy=graphical.target
EOF"
_systemctl_reload && _systemctl_enable "$_service_name"
}
_serviceMediacenter() {
_runDebug "${FUNCNAME[0]}"
[[ -z $_display ]] && _display="${DISPLAY:-":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"
}
_serviceVNC() {
_runDebug "${FUNCNAME[0]}"
_installPackage tigervnc-server
_setVNCPass
if [[ -n $_novncauth ]]; then
_exec_start_cmd="/usr/bin/vncserver $_display -geometry 1440x900 -alwaysshared -fg -SecurityTypes None -xstartup /usr/bin/mediacenter$_mversion"
else
_exec_start_cmd="/usr/bin/vncserver $_display -geometry 1440x900 -alwaysshared -fg -rfbauth $HOME/.vnc/jrmc_passwd -xstartup /usr/bin/mediacenter$_mversion"
fi
if [[ -z $_display ]]; then
# If we are running on existing X server then increment DISPLAY by one
if [[ -n $DISPLAY ]]; then
_display=$(( ${DISPLAY#:} + 1 ))
_display=":$_display"
else
_display=":0"
fi
fi
local _port=$(( ${_display#:} + 5900 ))
_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 $_display > /dev/null 2>&1 || :'
ExecStart=$_exec_start_cmd
ExecStop=/usr/bin/vncserver -kill $_display
[Install]
WantedBy=multi-user.target
EOF"
_systemctl_reload && _systemctl_enable "$_service_name"
echo "vncserver service should be running on localhost:$_port"
echo "You can diagnose issues using \"sudo systemctl status $_service_name\""
}
_serviceX11VNC() {
_runDebug "${FUNCNAME[0]}"
_installPackage x11vnc
_setX11VNCPass
if [[ -n $_novncauth ]]; then
_exec_start_cmd="/usr/bin/x11vnc -display $_display -noscr -geometry 1920x1080 -auth guess -forever -bg -nopw"
else
_exec_start_cmd="/usr/bin/x11vnc -display $_display -noscr -geometry 1920x1080 -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"
}
_serviceCreaterepo() {
_runDebug "${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_enable "$_timer_name"
}
#######################################
# CONTAINERS
#######################################
_containerCreaterepo() {
:
}
_containerVNC() {
:
}
_uninstall() {
_runDebug "${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
[[ -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"
if [[ -x $(command -v firewall-cmd) ]]; then
echo "Removing firewall rules"
_firewall_cmd --permanent --remove-service=jriver
_firewall_cmd --permanent --delete-service=jriver
_firewall_cmd --reload
elif [[ -x $(command -v ufw) ]]; then
echo "Removing firewall rules"
_firewall_cmd delete allow jriver
[[ -f "/etc/ufw/applications.d/jriver.service" ]] \
&& _rm_cmd /etc/ufw/applications.d/jriver.service
fi
echo "Uninstalling Media Center"
if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
_pkg_remove MediaCenter
elif [[ "$ID" =~ ^(ubuntu|debian)$ ]]; 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"
}
__main() {
# Check user
_checkUser
# Parse input
_parseInput "$@"
# Build some OS-specific commands based on the selected OS
_buildCommands
# Set version to install/uninstall
_setVersion
# Sanity checks
_sanityChecks
# Uninstall and exit
if [[ -n $_uninstall ]]; then
_uninstall
return $?
fi
# Install MC using package manager
if [[ -n $_repoinstall ]]; then
_installPackage rpmfusion-free-release epel-release
_installMCFromRepo
_symlinkCerts
_restoreLicense
_openFirewall
fi
# Build RPM from source DEB
if [[ -n $_rpmbuild ]]; then
_acquireDeb
_buildRPM
fi
# Run createrepo
if [[ -n $_createrepo ]]; then
_runCreateRepo "$_mcrpm"
fi
# Install the rpm
if [[ -n $_rpminstall ]]; then
if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
_installPackage rpmfusion-free-release epel-release
_installPackage --noquery "$_mcrpm"
_symlinkCerts
_restoreLicense
_openFirewall
fi
fi
# Install services
for _service in "${_services[@]}"; do
_servicePrep "$_service"
case "$_service" in
createrepo)
_serviceCreaterepo
;;
x11vnc)
_serviceX11VNC
;;
mediaserver)
_serviceMediaserver
;;
mediacenter)
_serviceMediacenter
;;
mediacenter-vncserver)
_serviceVNC
;;
*)
esac
done
# Install containers
for _container in "${_containers[@]}"; do
case "$_container" in
createrepo)
_containerCreaterepo
;;
mediacenter-vncserver)
_containerVNC
;;
*)
esac
done
}
}
# 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