#!/usr/bin/env bash # This script will install JRiver Media Center and associated services on most major distros # # Copyright (c) 2021-2022 Bryan C. Roessler # This software is released under the Apache License. # https://www.apache.org/licenses/LICENSE-2.0 # # See installJRMC --help or printHelp() below # # TODO (v2) # 1. Raspberry Pi OS support # 2. Interactive installation (ncurses?) # 3. Additional containerization (createrepo and rpmbuild) # 4. Tests # # BUGS # 1. No createrepo on Mint shopt -s extglob declare -g SCRIPTVERSION="1.0b16" declare -g OUTPUTDIR="$PWD/output" declare -g CREATEREPO_WEBROOT="/var/www/jriver" declare -g USER="${SUDO_USER:-$USER}" declare -g HOME; HOME=$(getent passwd "$USER" | cut -d: -f6) printHelp() { debug "Running: ${FUNCNAME[0]}" cat <<- 'EOF' USAGE: installJRMC [[OPTION] [VALUE]]... If no options (besides -d) are provided, the script will default to '--install repo'. OPTIONS --install, -i repo|local repo: Install MC from repository, updates are handled by the system package manager local: Build and install MC package locally --build[=suse|fedora|centos] Build RPM from source DEB but do not install Optionally, specify a target distro for cross-building (ex. --build=suse, note the '=') --compat Build/install MC locally without minimum library specifiers --mcversion VERSION Specify the MC version, ex. "29.0.18" (Default: latest) --outputdir PATH Generate rpmbuild output in this directory (Default: ./output) --restorefile RESTOREFILE Restore file location for automatic license 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 --service-type user|system Starts services at boot (system) or at user login (user) (Default: boot) --container, -c CONTAINER (TODO: Under construction) See CONTAINERS section below for a list of possible services to install --createrepo[=suse|fedora|centos] Build rpm, copy to webroot, and run createrepo. Use in conjunction with --build=TARGET for crossbuilding repos Optionally, specify a target distro for non-native repo (ex. --createrepo=fedora, note the '=') --createrepo-webroot PATH Specify the webroot directory to install the repo (Default: /var/www/jriver) --createrepo-user USER Specify the web server user if it differs from $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, remove services, and remove firewall rules (does not remove library files) SERVICES jriver-mediaserver Enable and start a mediaserver systemd service (requires an existing X server) (user) jriver-mediacenter Enable and start a mediacenter systemd service (requires an existing X server) (user) jriver-x11vnc Enable and start x11vnc for the local desktop (requires an existing X server) (user) Usually combined with jriver-mediaserver or jriver-mediacenter services --vncpass and --display are optional (see below) jriver-xvnc Enable and start a new Xvnc session running JRiver Media Center (system) --vncpass PASSWORD Set vnc password for x11vnc/Xvnc access. If no password is set, the script will either use existing password stored in $HOME/.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 (system) CONTAINERS (TODO: Under construction) mediacenter-xvnc createrepo EOF } # Helpers debug() { (( DEBUG )) && [[ $# -gt 0 ]] && echo "Debug: $*"; } err() { echo "Error: $*" >&2; } askOk() { declare response read -r -p "$* [y/N]: " response [[ "${response,,}" =~ ^(yes|y)$ ]] return } ####################################### # Parses user input and sets sensible defaults ####################################### parseInput() { debug "Running: ${FUNCNAME[0]}" declare -g BUILD_SWITCH REPO_INSTALL_SWITCH COMPAT_SWITCH LOCAL_INSTALL_SWITCH CREATEREPO_SWITCH UNINSTALL_SWITCH declare -g OUTPUTDIR RESTOREFILE BETAPASS SERVICE_TYPE VNCPASS USER_DISPLAY CREATEREPO_WEBROOT declare -ga SERVICES CONTAINERS declare long_opts short_opts # Allow some environment variables to override and set sane fallbacks declare -g TARGET=${TARGET:-$ID} declare -g CREATEREPO_USER="${CREATEREPO_USER:-$USER}" if [[ $# -eq 0 ]] || [[ $# -eq 1 && "$1" =~ ^(--debug|-d)$ ]]; then REPO_INSTALL_SWITCH=1 elif [[ $# -eq 1 && "$1" =~ ^(--compat)$ ]]; then BUILD_SWITCH=1 LOCAL_INSTALL_SWITCH=1 fi long_opts="install:,build::,outputdir:,mcversion:,restorefile:,betapass:," long_opts+="service-type:,service:,version,debug,help,uninstall,createrepo::," long_opts+="createrepo-webroot:,createrepo-user:,vncpass:,display:,container:,tests,compat" short_opts="+i:vb::dhus:c:" if _input=$(getopt -o $short_opts -l $long_opts -- "$@"); then eval set -- "$_input" while true; do case "$1" in --install|-i) shift case "$1" in local|rpm) BUILD_SWITCH=1 LOCAL_INSTALL_SWITCH=1 ;; repo) REPO_INSTALL_SWITCH=1 ;; esac ;; --build|-b) BUILD_SWITCH=1 shift && TARGET="$1" ;; --outputdir) shift && OUTPUTDIR="$1" ;; --mcversion) shift && MCVERSION="$1" ;; --restorefile) shift && RESTOREFILE="$1" ;; --betapass) shift && BETAPASS="$1" ;; --service-type) shift && SERVICE_TYPE="$1" ;; --service|-s) shift && SERVICES+=("$1") ;; --createrepo) BUILD_SWITCH=1 CREATEREPO_SWITCH=1 shift && TARGET="$1" ;; --createrepo-webroot) shift && CREATEREPO_WEBROOT="$1" ;; --createrepo-user) shift && CREATEREPO_USER="$1" ;; --vncpass) shift && VNCPASS="$1" ;; --display) shift && USER_DISPLAY="$1" ;; --compat) COMPAT_SWITCH=1 ;; --container|-c) shift && CONTAINERS+=("$1") ;; --version|-v) echo "Version: $SCRIPTVERSION" exit 0 ;; --debug|-d) echo "Debugging on" echo "installJRMC version: $SCRIPTVERSION" DEBUG=1 ;; --help|-h) printHelp && exit $? ;; --uninstall|-u) UNINSTALL_SWITCH=1 ;; --tests) echo "Running tests, all other options are skipped" tests ;; --) shift break ;; esac shift done else err "Incorrect options provided" printHelp && exit 1 fi (( DEBUG )) || echo "Use --debug for verbose output" } ####################################### # Uses several methods to determine the latest JRiver MC version # TODO but how to determine build distro `$BASE=buster`? ####################################### getVersion() { debug "Running: ${FUNCNAME[0]}" declare -g MCVERSION VERSION_SOURCE MVERSION MCPKG BASE="buster" # For container method #declare -g BASE_NEXT="bullseye" # TODO possibly use for fallback to smooth upgrades declare boardurl="https://yabb.jriver.com/interact/index.php/board,74.0.html" # MC28 (Buster), for fallback webscrape # User input if [[ -v MCVERSION && "$MCVERSION" =~ ([0-9]+.[0-9]+.[0-9]+) ]]; then VERSION_SOURCE="user input" # Containerized package manager elif installPackage --silent buildah && cnt=$(buildah from debian:$BASE) &>/dev/null && buildah run "$cnt" -- bash -c \ "echo 'deb [trusted=no arch=amd64,i386,armhf,arm64] http://dist.jriver.com/latest/mediacenter/ $BASE main' > /etc/apt/sources.list 2>&1" && buildah run "$cnt" -- bash -c \ "apt update --allow-insecure-repositories &>/dev/null" && MCVERSION=$(buildah run "$cnt" -- apt-cache policy mediacenter?? | grep Candidate | awk '{print $2}' | sort -V | tail -n1) && [[ "$MCVERSION" =~ ([0-9]+.[0-9]+.[0-9]+) ]] && VERSION_SOURCE="containerized package manager"; then buildah rm "$cnt" &>/dev/null # Webscrape elif installPackage wget && MCVERSION=$(wget -qO- "$boardurl" | grep -o "[0-9][0-9]\.[0-9]\.[0-9]\+" | head -n 1) && [[ "$MCVERSION" =~ ([0-9]+.[0-9]+.[0-9]+) ]]; then VERSION_SOURCE="webscrape" # Hardcoded else MCVERSION="29.0.18" VERSION_SOURCE="hardcoded version" err "Warning! Using hardcoded version number" fi echo "Using MC version $MCVERSION determined by $VERSION_SOURCE" [[ "$VERSION_SOURCE" != "user input" ]] && echo "To override, use --mcversion" # Extract major version number MVERSION="${MCVERSION%%.*}" } ####################################### # Installs a package using the system package manager # Arguments: # One or more package names # Options: # --skip-check-installed: Do not check if package is already installed # --nogpgcheck: Disable GPG checks for RPM based distros # --allow-downgrades: Useful for installing compatability versions on DEB based distros # --silent, -s: Do not report errors (useful if package is not strictly required and errors are noisy) ####################################### installPackage() { debug "Running: ${FUNCNAME[0]}" "$@" declare -a pkg_array install_flags declare pkg skip_check_installed silent _return pkg_install_cmd if _input=$(getopt -o +s -l skip-check-installed,allow-downgrades,nogpgcheck,silent -- "$@"); then eval set -- "$_input" while true; do case "$1" in --skip-check-installed) skip_check_installed=1 ;; --allow-downgrades) [[ "$ID" =~ ^(debian|ubuntu)$ ]] && install_flags+=(--allow-downgrades) ;; --nogpgcheck) if [[ "$ID" =~ ^(fedora|centos)$ ]]; then install_flags+=(--nogpgcheck) elif [[ "$ID" == "suse" ]]; then install_flags+=(--allow-unsigned-rpm) fi ;; --silent|-s) silent=1 ;; --) shift break ;; esac shift done else err "Incorrect options provided" exit 1 fi # Aliases if [[ "$ID" =~ ^(debian|ubuntu)$ ]]; then declare -A 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 for pkg in "$@"; do if [[ ! -v skip_check_installed && -v PKG_ALIASES[$pkg] ]]; then pkg=${PKG_ALIASES[$pkg]} fi # Check if already installed if (( skip_check_installed )) || ! (hash $pkg &>/dev/null || pkg_query "$pkg" &>/dev/null); then pkg_array+=("$pkg") fi done # Install packages from package array if [[ ${#pkg_array[@]} -ge 1 ]]; then pkg_install_cmd="pkg_install ${install_flags[*]} ${pkg_array[*]}" debug "$pkg_install_cmd" || pkg_install_cmd+=" &>/dev/null" if ! eval "$pkg_install_cmd"; then (( silent )) || err "Failed to install ${pkg_array[*]}. Attempting to continue" return 1 fi fi return 0 } ####################################### # Adds the JRiver repository files ####################################### addRepo() { debug "Running: ${FUNCNAME[0]}" if [[ "$ID" == "suse" ]]; then echo "A SUSE repository is not yet available" echo "Use --install local to locally install a SUSE RPM" exit 1 fi echo "Adding JRiver repository to package manager" if [[ "$ID" =~ ^(fedora|centos)$ ]]; then declare sources_dir="/etc/yum.repos.d/" sudo bash -c "cat <<- EOF > $sources_dir/jriver.repo [jriver] name=JRiver Media Center repo by BryanC baseurl=https://repos.bryanroessler.com/jriver gpgcheck=0 EOF" elif [[ "$ID" =~ ^(debian|ubuntu)$ ]]; then declare sources_dir="/etc/apt/sources.list.d" [[ ! -d $sources_dir ]] && sudo mkdir -p "$sources_dir" sudo rm -rf "$sources_dir"/mediacenter*.list installPackage wget sudo bash -c "cat <<- EOF > $sources_dir/jriver.list deb [trusted=yes arch=amd64,i386,armhf,arm64] http://dist.jriver.com/latest/mediacenter/ $BASE main EOF" #wget -q "http://dist.jriver.com/mediacenter@jriver.com.gpg.key" -O- | sudo apt-key add - &>/dev/null wget -qO- "http://dist.jriver.com/mediacenter@jriver.com.gpg.key" | sudo tee /etc/apt/trusted.gpg.d/jriver.asc elif [[ "$ID" == "suse" ]]; then sudo zypper addrepo --no-gpgcheck "https://repos.bryanroessler.com/jriver" jriver &>/dev/null elif [[ "$ID" == "arch" ]]; then sudo bash -c "cat <<- EOF > EOF" fi } ####################################### # Installs JRiver Media Center from a repository ####################################### installMCFromRepo() { debug "Running: ${FUNCNAME[0]}" addRepo # Update package list pkg_update_cmd="pkg_update" debug "$pkg_update_cmd" || pkg_update_cmd+=" &>/dev/null" if ! eval "$pkg_update_cmd"; then err "Package update failed!" exit 1 fi echo "Installing JRiver Media Center using package manager" pkg_install_cmd="installPackage --skip-check-installed --nogpgcheck $MCPKG" debug "$pkg_install_cmd" || pkg_install_cmd+=" &>/dev/null" eval "$pkg_install_cmd" } ####################################### # Acquires the source DEB package from JRiver's servers ####################################### acquireDeb() { debug "Running: ${FUNCNAME[0]}" declare -g MCDEB="$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 "$MCDEB" ]]; then echo "Using local source DEB: $MCDEB" return 0 fi if [[ -v BETAPASS ]]; then echo "Checking beta repo for DEB package" if wget -q -O "$MCDEB" \ "https://files.jriver.com/mediacenter/channels/v$MVERSION/beta/$BETAPASS/MediaCenter-$MCVERSION-amd64.deb"; then echo "Found!" fi elif echo "Checking latest repo for DEB package" && wget -q -O "$MCDEB" \ "https://files.jriver.com/mediacenter/channels/v$MVERSION/latest/MediaCenter-$MCVERSION-amd64.deb"; then echo "Found!" elif echo "Checking test repo for DEB package" && wget -q -O "$MCDEB" \ "https://files.jriver.com/mediacenter/test/MediaCenter-$MCVERSION-amd64.deb"; then echo "Found!" else err "Cannot find DEB file" exit 1 fi if [[ -f "$MCDEB" ]]; then echo "Downloaded MC $MCVERSION DEB to $MCDEB" else err "Downloaded DEB file missing or corrupted" exit 1 fi } ####################################### # Installs Media Center DEB package and optional compatability fixes ####################################### installMCDEB() { debug "Running: ${FUNCNAME[0]}" declare pkg_install_cmd="installPackage --skip-check-installed --nogpgcheck" if (( COMPAT_SWITCH )); then declare extract_dir && extract_dir="$(mktemp -d)" pushd "$extract_dir" &>/dev/null || return ar x "$MCDEB" tar -xJf "control.tar.xz" # Remove minimum version specifiers from control file sed -i 's/ ([^)]*)//g' "control" sed -i 's/([^)]*)//g' "control" # TODO MC DEB package error [[ "$ID" == "ubuntu" && "${VERSION_ID%.*}" -le 16 ]] && sed -i 's/libva2/libva1/g' "control" tar -cJf "control.tar.xz" "control" "postinst" declare -g MCDEB="${MCDEB/.deb/.compat.deb}" ar rcs "$MCDEB" "debian-binary" "control.tar.xz" "data.tar.xz" popd &>/dev/null || return rm -rf "$extract_dir" pkg_install_cmd+=" --allow-downgrades" fi pkg_install_cmd+=" $MCDEB" debug "$pkg_install_cmd" || pkg_install_cmd+=" &>/dev/null" eval "$pkg_install_cmd" } ####################################### # Creates a SPEC file and builds the RPM from the source DEB using rpmbuild ####################################### buildRPM() { debug "Running: ${FUNCNAME[0]}" declare i rpmbuild_cmd declare -a requires recommends declare -A dupes # skip rebuilding the rpm if it already exists if [[ -f "$MCRPM" ]]; then echo "$MCRPM already exists. Skipping build step" return 0 fi [[ ! -d "$OUTPUTDIR/SPECS" ]] && mkdir -p "$OUTPUTDIR/SPECS" # Load deb dependencies into array IFS=',' read -ra requires <<< "$(dpkg-deb -f "$MCDEB" Depends)" IFS=',' read -ra recommends <<< "$(dpkg-deb -f "$MCDEB" Recommends)" # Clean up formatting requires=("${requires[@]%%|*}") requires=("${requires[@]/?:/}") requires=("${requires[@]# }") requires=("${requires[@]% }") requires=("${requires[@]//\(/}") requires=("${requires[@]//)/}") recommends=("${recommends[@]%%|*}") recommends=("${recommends[@]/?:/}") recommends=("${recommends[@]# }") recommends=("${recommends[@]% }") recommends=("${recommends[@]//\(/}") recommends=("${recommends[@]//)/}") # Translate package names case "$TARGET" in fedora|centos) requires=("${requires[@]/libc6/glibc}") requires=("${requires[@]/libasound2/alsa-lib}") requires=("${requires[@]/libuuid1/libuuid}") requires=("${requires[@]/libx11-6/libX11}") requires=("${requires[@]/libxext6/libXext}") requires=("${requires[@]/libxcb1/libxcb}") requires=("${requires[@]/libxdmcp6/libXdmcp}") requires=("${requires[@]/libstdc++6/libstdc++}") requires=("${requires[@]/libgtk-3-0/gtk3}") requires=("${requires[@]/libgl1/mesa-libGL}") requires=("${requires[@]/libpango-1.0-0/pango}") requires=("${requires[@]/libpangoft2-1.0-0/pango}") requires=("${requires[@]/libpangox-1.0-0/pango}") requires=("${requires[@]/libpangoxft-1.0-0/pango}") requires=("${requires[@]/libnss3/nss}") requires=("${requires[@]/libnspr4/nspr}") requires=("${requires[@]/libgomp1/libgomp}") requires=("${requires[@]/libfribidi0/fribidi}") requires=("${requires[@]/libfontconfig1/fontconfig}") requires=("${requires[@]/libfreetype6/freetype}") requires=("${requires[@]/libharfbuzz0b/harfbuzz}") requires=("${requires[@]/libgbm1/mesa-libgbm}") requires=("${requires[@]/libva2/libva}") requires=("${requires[@]/libepoxy0/libepoxy}") requires=("${requires[@]/liblcms2-2/lcms2}") requires=("${requires[@]/libvulkan1/vulkan-loader}") requires=("${requires[@]/libepoxy0/libepoxy}") requires=("${requires[@]/python/python3}") ;; suse) requires=("${requires[@]/libc6/glibc}") requires=("${requires[@]/libasound2/alsa-lib}") requires=("${requires[@]/libx11-6/libX11-6}") requires=("${requires[@]/libxext6/libXext6}") requires=("${requires[@]/libxdmcp6/libXdmcp6}") requires=("${requires[@]/libgtk-3-0/gtk3}") requires=("${requires[@]/libgl1/Mesa-libGL1}") requires=("${requires[@]/libpango-1.0-0/pango}") requires=("${requires[@]/libpangoft2-1.0-0/pango}") requires=("${requires[@]/libpangox-1.0-0/pango}") requires=("${requires[@]/libpangoxft-1.0-0/pango}") requires=("${requires[@]/libnss3/mozilla-nss}") requires=("${requires[@]/libnspr4/mozilla-nspr}") requires=("${requires[@]/libfribidi0/fribidi}") requires=("${requires[@]/libfontconfig1/fontconfig}") requires=("${requires[@]/libfreetype6*/freetype}") # Remove minimum version specifier requires=("${requires[@]/libharfbuzz0b/libharfbuzz0}") for i in "${!requires[@]}"; do [[ "${requires[$i]}" == "mesa-vulkan-drivers" ]] && unset -v 'requires[i]' done recommends+=(libvulkan_intel) recommends+=(libvulkan_radeon) ;; esac # Remove duplicates for i in "${requires[@]}"; do if [[ ! -v dupes[${i%% *}] ]]; then tmp+=("$i") fi dupes["${i%% *}"]=1 done requires=("${tmp[@]}") # Convert array to newline delim'd string (for heredoc) printf -v requires "Requires: %s\n" "${requires[@]}" printf -v recommends "Recommends: %s\n" "${recommends[@]}" # Strip last newline requires="${requires%?}" recommends="${recommends%?}" if (( COMPAT_SWITCH )); then # Strip minimum versions requires=$(echo "$requires" | awk -F" " 'NF == 4 {print $1 " " $2} NF != 4 {print $0}') 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 BuildArch: x86_64 %define _rpmfilename %%{ARCH}/%%{NAME}-%%{version}.%%{ARCH}.rpm AutoReq: 0 $requires $recommends Provides: mediacenter$MVERSION License: Copyright 1998-2022, 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 # Run rpmbuild echo "Building RPM for MC $MCVERSION, this may take awhile" rpmbuild_cmd="rpmbuild --define=\"%_topdir $OUTPUTDIR\" --define=\"%_libdir /usr/lib\" -bb" rpmbuild_cmd+=" $OUTPUTDIR/SPECS/mediacenter.spec" debug "$rpmbuild_cmd" || rpmbuild_cmd+=" &>/dev/null" if eval "$rpmbuild_cmd" && [[ -f "$MCRPM" ]] ; then echo "Build successful. The RPM file is located at: $MCRPM" else err "Build failed" # For automation, let's remove the source DEB and reaquire it on next run # after failure in case it is corrupted or buggy [[ -f "$MCDEB" ]] && echo "Removing source DEB" && rm -f "$MCDEB" exit 1 fi } installMCArch() { debug "Running: ${FUNCNAME[0]}" echo "Arch install under construction" } ####################################### # Copy the RPM to createrepo-webroot and runs createrepo as the createrepo-user ####################################### runCreaterepo() { debug "Running: ${FUNCNAME[0]}" declare cr_cmd cr_cp_cmd cr_mkdir_cmd cr_chown_cmd installPackage createrepo_c # If the webroot does not exist, create it if [[ ! -d "$CREATEREPO_WEBROOT" ]]; then cr_mkdir_cmd="sudo -u $CREATEREPO_USER mkdir -p $CREATEREPO_WEBROOT" debug "$cr_mkdir_cmd" || cr_mkdir_cmd+=" &>/dev/null" if ! eval "$cr_mkdir_cmd"; then cr_mkdir_cmd="sudo mkdir -p $CREATEREPO_WEBROOT" debug "$cr_mkdir_cmd" || cr_mkdir_cmd+=" &>/dev/null" cr_chown_cmd="sudo chown -R $CREATEREPO_USER:$CREATEREPO_USER $CREATEREPO_WEBROOT" debug "$cr_chown_cmd" || cr_chown_cmd+=" &>/dev/null" if ! ( eval "$cr_mkdir_cmd" && eval "$cr_chown_cmd" ); then err "Could not create the createrepo-webroot path!" err "Make sure that the webroot $CREATEREPO_WEBROOT is writeable by user $CREATEREPO_USER" err "Or change the repo ownership with --createrepo-user" return 1 fi fi fi # Copy built rpms to webroot cr_cp_cmd="sudo cp -nf $MCRPM $CREATEREPO_WEBROOT" cr_chown_cmd="sudo chown -R $CREATEREPO_USER:$CREATEREPO_USER $CREATEREPO_WEBROOT" debug "$cr_cp_cmd" || cr_cp_cmd+=" &>/dev/null" debug "$cr_chown_cmd" || cr_cp_cmd+=" &>/dev/null" if ! ( eval "$cr_cp_cmd" && eval "$cr_chown_cmd" ); then err "Could not copy $MCRPM to $CREATEREPO_WEBROOT" return 1 fi # Run createrepo cr_cmd="sudo -u $CREATEREPO_USER createrepo -q $CREATEREPO_WEBROOT" [[ -d "$CREATEREPO_WEBROOT/repodata" ]] && cr_cmd+=" --update" debug "$cr_cmd" || cr_cmd+=" &>/dev/null" if ! eval "$cr_cmd"; then cr_cmd="sudo createrepo -q $CREATEREPO_WEBROOT" [[ -d "$CREATEREPO_WEBROOT/repodata" ]] && cr_cmd+=" --update" cr_chown_cmd="sudo chown -R $CREATEREPO_USER:$CREATEREPO_USER $CREATEREPO_WEBROOT" debug "$cr_cmd" || cr_cmd+=" &>/dev/null" debug "$cr_chown_cmd" || cr_cp_cmd+=" &>/dev/null" if ! ( eval "$cr_cmd" && eval "$cr_chown_cmd"); then err "Createrepo failed" return 1 fi fi echo "Successfully updated repo" } ####################################### # Symlink certificates if they do not exist in default location ####################################### symlinkCerts() { debug "Running: ${FUNCNAME[0]}" declare mc_cert_link="/usr/lib/jriver/Media\ Center\ $MVERSION/ca-certificates.crt" declare target_cert ln_cmd target_cert=$(readlink -f "$mc_cert_link") [[ -f $target_cert ]] && return 0 if [[ -f /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem ]]; then ln_cmd="sudo ln -fs /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem $mc_cert_link" # For RHEL elif [[ -f /var/lib/ca-certificates/ca-bundle.pem ]]; then ln_cmd="sudo ln -fs /var/lib/ca-certificates/ca-bundle.pem $mc_cert_link" # For SUSE fi debug "$ln_cmd" || ln_cmd+=" &>/dev/null" if ! eval "$ln_cmd"; then err "Symlinking certificates failed" return 1 fi } ####################################### # Restore the mjr license file if it is next to installJRMC or RESTOREFILE is set ####################################### restoreLicense() { debug "Running: ${FUNCNAME[0]}" declare mjrfile # Allow user to put the mjr file next to installJRMC if [[ ! -v RESTOREFILE ]]; then for mjrfile in "$PWD"/*.mjr; do [[ $mjrfile -nt $RESTOREFILE ]] && RESTOREFILE="$mjrfile" done 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: # Pre-defined service to enable ####################################### openFirewall() { debug "Running: ${FUNCNAME[0]}" "$@" # Create OS-specific port rules based on argument (service) name declare -a f_ports # for firewall-cmd declare u_ports # for ufw declare -a n_ports # for nftables declare port if [[ "$1" == "jriver-mediacenter" ]]; then f_ports=(52100-52200/tcp 1900/udp) u_ports="52100:52200/tcp|1900/udp" n_ports=("tcp dport 52100-52200 accept" "udp dport 1900 accept") elif [[ "$1" =~ ^(jriver-x11vnc|jriver-xvnc)$ ]]; then f_ports=("$PORT"/tcp 1900/udp) u_ports="$PORT/tcp|1900/udp" n_ports=("tcp dport $PORT accept" "udp dport 1900 accept") fi # Open the ports if [[ "$ID" =~ ^(fedora|centos|suse)$ ]]; then hash firewall-cmd 2>/dev/null || installPackage firewalld if ! firewall_cmd --get-services | grep -q "$1"; then firewall_cmd --permanent --new-service="$1" &>/dev/null firewall_cmd --permanent --service="$1" --set-description="$1 installed by installJRMC" &>/dev/null firewall_cmd --permanent --service="$1" --set-short="$1" &>/dev/null for port in "${f_ports[@]}"; do firewall_cmd --permanent --service="$1" --add-port="$port" &>/dev/null done firewall_cmd --add-service "$1" --permanent &>/dev/null firewall_cmd --reload &>/dev/null fi elif [[ "$ID" =~ ^(debian|ubuntu)$ ]]; then # Debian ufw package state is broken on fresh installations hash ufw 2>/dev/null || installPackage ufw if [[ ! -f "/etc/ufw/applications.d/$1" ]]; then sudo bash -c "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" &>/dev/null firewall_cmd allow "$1" &>/dev/null elif [[ "$ID" == "arch" ]]; then sysctl -w net.ipv4.ip_forward = 1 sudo nft create table inet "jriver" sudo nft create chain inet "jriver" "$1" '{ type filter hook input priority 0; policy accept; }' for port in "${n_ports[@]}"; do sudo nft add rule inet jriver "$1" handle tcp dport "$port" done fi # shellcheck disable=SC2181 # More concise if [[ $? -ne 0 ]]; then err "Firewall ports could not be opened" return 1 fi } ####################################### # Create the xvnc or x11vnc password file # Arguments: # Service type (xvnc, x11vnc) ####################################### setVNCPass() { debug "Running: ${FUNCNAME[0]}" declare vncpassfile="$HOME/.vnc/jrmc_passwd" declare vnc_pass_cmd [[ ! -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 [[ $1 == "xvnc" ]]; then vnc_pass_cmd="echo $VNCPASS | vncpasswd -f > $vncpassfile" elif [[ $1 == "x11vnc" ]]; then vnc_pass_cmd="x11vnc -storepasswd $VNCPASS $vncpassfile" fi if ! eval "$vnc_pass_cmd"; then err "Could not create VNC password file" return 1 fi else declare -g NOVNCAUTH=1 fi } ####################################### # Set display and port variables ####################################### setDisplay() { debug "Running: ${FUNCNAME[0]}" declare -g DISPLAY DISPLAYNUM NEXT_DISPLAY NEXT_DISPLAYNUM # Check USER_DISPLAY, else environment DISPLAY, else set to :0 by default DISPLAY="${USER_DISPLAY:-${DISPLAY:-0}}" DISPLAYNUM="${DISPLAY#*:}" # strip prefix DISPLAYNUM="${DISPLAYNUM%%.*}" # strip suffix NEXT_DISPLAYNUM=$(( DISPLAYNUM + 1 )) NEXT_DISPLAY=":$NEXT_DISPLAYNUM" } ####################################### # Create associated service variables based on service name # Arguments # Pre-defined service name ####################################### setServiceVars() { debug "Running: ${FUNCNAME[0]}" declare -g SERVICE_NAME SERVICE_FNAME TIMER_NAME TIMER_FNAME USER_STRING GRAPHICAL_TARGET declare -g SERVICE_TYPE="${SERVICE_TYPE:-system}" declare service_dir="/usr/lib/systemd/$SERVICE_TYPE" if [[ "$USER" == "root" && "$SERVICE_TYPE" == "user" ]]; then err "Trying to install user service as root" err "Use --service-type service and/or execute installJRMC as non-root user" return 1 fi if [[ "$SERVICE_TYPE" == "system" ]]; then systemctl_reload_cmd(){ sudo systemctl daemon-reload; } systemctl_enable_cmd(){ sudo systemctl enable --now "$@"; } systemctl_disable_cmd(){ sudo systemctl disable --now "$@"; } systemctl_is_enabled_cmd(){ sudo systemctl is-enabled -q "$@"; } systemctl_is_active_cmd(){ sudo systemctl is-active -q "$@"; } GRAPHICAL_TARGET="graphical.target" elif [[ "$SERVICE_TYPE" == "user" ]]; then systemctl_reload_cmd(){ systemctl --user daemon-reload; } systemctl_enable_cmd(){ systemctl --user enable --now "$@"; } systemctl_disable_cmd(){ systemctl --user disable --now "$@"; } systemctl_is_enabled_cmd(){ systemctl --user is-enabled -q "$@"; } systemctl_is_active(){ sudo systemctl is-active -q "$@"; } GRAPHICAL_TARGET="default.target" fi [[ ! -d "$service_dir" ]] && sudo mkdir -p "$service_dir" if [[ "$SERVICE_TYPE" == "system" && "$USER" != "root" ]]; then SERVICE_FNAME="$service_dir/${1}@.service" TIMER_FNAME="$service_dir/${1}@.timer" SERVICE_NAME="${1}@$USER.service" TIMER_NAME="${1}@$USER.timer" USER_STRING="User=%I" else SERVICE_NAME="${1}.service" TIMER_NAME="${1}.timer" SERVICE_FNAME="$service_dir/${SERVICE_NAME}" TIMER_FNAME="$service_dir/${TIMER_NAME}" USER_STRING="" fi } ####################################### # Starts and enables (at startup) a JRiver Media Center service # Arguments: # Passes arguments as startup options to /usr/bin/mediacenter?? ####################################### service_jriver-mediacenter() { debug "Running: ${FUNCNAME[0]}" setServiceVars "${FUNCNAME[0]##*_}" sudo bash -c "cat <<- EOF > $SERVICE_FNAME [Unit] Description=JRiver Media Center $MVERSION After=$GRAPHICAL_TARGET [Service] $USER_STRING 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_cmd && systemctl_enable_cmd "$SERVICE_NAME" && openFirewall "jriver-mediacenter" } ####################################### # Starts and enables (at startup) a JRiver Media Server service ####################################### service_jriver-mediaserver() { debug "Running: ${FUNCNAME[0]}" setServiceVars "${FUNCNAME[0]##*_}" service_jriver-mediacenter "/MediaServer" } ####################################### # Starts and enables (at startup) JRiver Media Center in a new Xvnc session ####################################### service_jriver-xvnc() { debug "Running: ${FUNCNAME[0]}" setServiceVars "${FUNCNAME[0]##*_}" setDisplay declare start_cmd declare -g PORT=$(( NEXT_DISPLAYNUM + 5900 )) installPackage tigervnc-server setVNCPass xvnc if (( NOVNCAUTH )); then start_cmd="/usr/bin/vncserver $NEXT_DISPLAY -geometry 1440x900 -alwaysshared -name jriver$NEXT_DISPLAY -SecurityTypes None -autokill -xstartup /usr/bin/mediacenter$MVERSION" else start_cmd="/usr/bin/vncserver $NEXT_DISPLAY -geometry 1440x900 -alwaysshared -rfbauth $HOME/.vnc/jrmc_passwd -autokill -xstartup /usr/bin/mediacenter$MVERSION" fi sudo bash -c "cat <<- EOF > $SERVICE_FNAME [Unit] Description=Remote desktop service (VNC) After=multi-user.target [Service] Type=forking $USER_STRING ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill $NEXT_DISPLAY &>/dev/null || :' ExecStart=$start_cmd ExecStop=/usr/bin/vncserver -kill $NEXT_DISPLAY Restart=always [Install] WantedBy=multi-user.target EOF" systemctl_reload_cmd && systemctl_enable_cmd "$SERVICE_NAME" && echo "Xvnc running on localhost:$PORT" && openFirewall "jriver-xvnc" && openFirewall "jriver-mediacenter" } ####################################### # Starts and enables (at startup) x11vnc screen sharing for the local desktop ####################################### service_jriver-x11vnc() { debug "Running: ${FUNCNAME[0]}" setServiceVars "${FUNCNAME[0]##*_}" setDisplay declare start_cmd declare -g PORT=$(( DISPLAYNUM + 5900 )) installPackage x11vnc setVNCPass x11vnc # 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 .Xauthority file is missing, generate a dummy for x11vnc -auth guess if [[ ! -f "$HOME/.Xauthority" ]]; then [[ "$XDG_SESSION_TYPE" == "wayland" ]] && ask_ok "Unsupported Wayland session detected for x11vnc, continue?" || return 1 touch "$HOME/.Xauthority" xauth generate "$DISPLAY" . trusted xauth add "$HOST$DISPLAY" . "$(xxd -l 16 -p /dev/urandom)" fi if (( NOVNCAUTH )); then start_cmd="/usr/bin/x11vnc -display $DISPLAY -noscr -auth guess -forever -bg -nopw" else start_cmd="/usr/bin/x11vnc -display $DISPLAY -noscr -auth guess -forever -bg -rfbauth $HOME/.vnc/jrmc_passwd" fi sudo bash -c "cat <<-EOF > $SERVICE_FNAME [Unit] Description=x11vnc After=$GRAPHICAL_TARGET [Service] $USER_STRING Type=forking Environment=DISPLAY=$DISPLAY ExecStart=$start_cmd Restart=always RestartSec=10 [Install] WantedBy=$GRAPHICAL_TARGET EOF" systemctl_reload_cmd && systemctl_enable_cmd "$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]}" if [[ "$CREATEREPO_USER" != "$USER" ]]; then USER="root" SERVICE_TYPE="system" setServiceVars "${FUNCNAME[0]##*_}" else setServiceVars "${FUNCNAME[0]##*_}" fi sudo bash -c "cat <<-EOF > $SERVICE_FNAME [Unit] Description=Builds JRiver Media Center RPM file, moves it to the repo dir, and runs createrepo [Service] $USER_STRING ExecStart=$PWD/installJRMC --outputdir $OUTPUTDIR --createrepo=$TARGET --createrepo-webroot $CREATEREPO_WEBROOT --createrepo-user $CREATEREPO_USER [Install] WantedBy=multi-user.target EOF" sudo bash -c "cat <<-EOF > $TIMER_FNAME [Unit] Description=Run JRiver MC rpmbuild hourly [Timer] OnCalendar=hourly Persistent=true [Install] WantedBy=timers.target EOF" systemctl_reload_cmd && systemctl_enable_cmd "$TIMER_NAME" } ####################################### # CONTAINERS ####################################### # container_jriver-createrepo() { # : # } # container_jriver-xvnc() { # : # } # container_jriver-mediacenter() { # installPackage buildah podman # # Eventually try to switch to Debian # # if ! CNT=$(buildah from debian:$BASE); then # # echo "Bad base image for container $CNAME, skipping" # # continue # # fi # if ! CNT=$(buildah from jlesage/baseimage-gui:debian-10-v3.5.7); then # echo "Bad base image for container $CNAME, skipping" # continue # fi # buildah run "$CNT" add-pkg gnupg2 libxss1 wmctrl xdotool ca-certificates inotify-tools libgbm1 ffmpeg # # #BASEIMAGE=jlesage/baseimage-gui:debian-10-v3.5.7 # # JRIVER_RELEASE=28 # # JRIVER_TAG=stable # # ARCH=amd64 # # REBUILD_MIN=22 # # REBUILD_MAX=120 # # # JRiver Version tag (latest, stable or beta) # # ARG jriver_tag # # # JRiver Release Version (25, 26 etc.) # # ARG jriver_release # # # Image Version of the build # # ARG image_version # # # .deb download URL, if set to "repository" the JRiver repository will be used # # ARG deb_url # # RUN add-pkg gnupg2 libxss1 wmctrl xdotool ca-certificates inotify-tools libgbm1 ffmpeg # # Install JRiver # RUN \ # add-pkg --virtual build-dependencies wget && # # Install from Repository # if [ "${deb_url}" = "repository" ]; then \ # echo "Installing JRiver from repository ${jriver_release}:${jriver_tag}" && # wget -q "http://dist.jriver.com/mediacenter@jriver.com.gpg.key" -O- | apt-key add - && # wget http://dist.jriver.com/${jriver_tag}/mediacenter/mediacenter${jriver_release}.list -O /etc/apt/sources.list.d/mediacenter${jriver_release}.list && # apt update && # add-pkg mediacenter${jriver_release}; \ # # Install from .deb URL # else \ # echo "Installing JRiver from URL: ${deb_url}" && # wget -q -O "jrivermc.deb" ${deb_url} && # add-pkg "./jrivermc.deb"; \ # fi && # # Cleanup # del-pkg build-dependencies && # rm -rf /tmp/* /tmp/.[!.]* # # Add rootfs # COPY rootfs/ / # VOLUME ["/config"] # # Application Icon # RUN \ # APP_ICON_URL=https://gitlab.com/shiomax/jrivermc-docker/raw/master/assets/Application.png && # install_app_icon.sh "$APP_ICON_URL" # # Various configuration vars # ENV KEEP_APP_RUNNING=1 \ # DISPLAY_WIDTH=1280 \ # DISPLAY_HEIGHT=768 \ # APP_NAME="JRiver MediaCenter ${jriver_release}" \ # MAXIMIZE_POPUPS=0 \ # S6_KILL_GRACETIME=8000 # # Modify startapp.sh and rc.xml with JRiver version # RUN sed-patch s/%%MC_VERSION%%/${jriver_release}/g \ # /startapp.sh && # sed-patch s/%%MC_VERSION%%/${jriver_release}/g \ # /etc/xdg/openbox/rc.xml # EXPOSE 5800 5900 52100 52101 52199 1900/udp # # Metadata. # LABEL \ # org.label-schema.name="jrivermc${jriver_release}" \ # org.label-schema.description="Docker image for JRiver Media Center ${jriver_release}" \ # org.label-schema.version="${image_version}" \ # org.label-schema.vcs-url="https://gitlab.com/shiomax/jrivermc-docker" \ # org.label-schema.schema-version="1.0" # installPackage buildah podman # cnt=$(buildah from docker.io/jlesage/baseimage-gui:debian-10) # podman_create_cmd=(podman create --name "$CNAME") # buildah_config_cmd=(buildah config \ # --author bryanroessler@gmail.com \ # --label maintainer="$MAINTAINER" \ # --env TZ="$TZ" \ # --workingdir /app \ # --cmd mediacenter"$MVERSION") # mkcdirs() { # declare dir # for dir in "$@"; do # if [[ ! -d "$dir" ]]; then # if ! mkdir -p "$dir"; then # err "Could not create directory $dir, check your permissions" # fi # fi # if ! chcon -t container_file_t -R "$dir"; then # err "Could not set container_file_t attribute for $dir, check your permissions" # fi # done # } # mkcdirs "$HOME/.jriver" # podman_create_cmd+=(-v "$HOME/.jriver:/root/.jriver") # podman_create_cmd+=(-v "$DOWNLOAD_ROOT:/downloads:z") # podman_create_cmd+=(-v "$MONITOR_ROOT/nzbs:/nzbs") # podman_create_cmd+=(-p "${CONTAINER[HOST_PORT]}:${CONTAINER[CONTAINER_PORT]}") # brc() { buildah run "$1" "${@:2}" || return 1; } # brc add-pkg gnupg2 libxss1 wmctrl xdotool ca-certificates inotify-tools libgbm1 # brc add-pkg --virtual .build-deps wget # brc sh -s <<- EOF # wget -q "http://dist.jriver.com/mediacenter@jriver.com.gpg.key" -O- | apt-key add - &>/dev/null # EOF # brc wget "http://dist.jriver.com/latest/mediacenter/mediacenter$MVERSION.list" -O "/etc/apt/sources.list.d/mediacenter$MVERSION.list" # brc apt update -y -q0 # brc add-pkg "mediacenter$MVERSION" # brc del-pkg .build-deps # } ####################################### # Perform OS detection and use compatability modes if necessary ####################################### getOS() { debug "Running: ${FUNCNAME[0]}" declare -g ID MGR if [[ -e "/etc/os-release" ]]; then source "/etc/os-release" else err "/etc/os-release not found" err "Your OS is unsupported" printHelp && exit 1 fi debug "Detected host platform: $ID $VERSION_ID" # normalize ID case "$ID" in fedora|arch|debian|centos) ;; rhel) ID="centos" ;; linuxmint|neon|*ubuntu*) ID="ubuntu" ;; *suse*) ID="suse" ;; *) echo "Autodetecting distro, this may be unreliable and --compat may also be required" if hash dnf &>/dev/null; then ID="fedora" MGR="dnf" elif hash yum &>/dev/null; then ID="centos" MGR="yum" COMPAT_SWITCH=1 elif hash apt &>/dev/null; then ID="ubuntu" elif hash pacman &>/dev/null; then ID="arch" else err "OS detection failed!" exit 1 fi esac # Set package manager for RPM distros case "$ID" in centos|fedora) if hash dnf &>/dev/null; then MGR="dnf" elif hash yum &>/dev/null; then MGR="yum" fi ;; esac debug "Using host platform: $ID $VERSION_ID" } ####################################### # Detects if MC is installed on btrfs and disables CoW ####################################### disableCoW() { debug "Running: ${FUNCNAME[0]}" declare dir declare mc_system_path="/usr/lib/jriver" declare mc_user_path="$HOME/.jriver" for dir in "$mc_system_path" "$mc_user_path"; do ! [[ -d "$dir" ]] && return if [[ $(stat -f -c %T "$dir") == "btrfs" ]] && ! lsattr -d "$dir" | cut -f1 -d" " | grep -q C; then echo "Disabling CoW for $dir" sudo chattr +C "$dir" fi done } ####################################### # Migrate major versions ####################################### migrateLibrary() { debug "Running: ${FUNCNAME[0]}" declare mc_user_path="$HOME/.jriver" declare current_config_path="$mc_user_path/Media Center $MVERSION" declare previous_config_path="$mc_user_path/Media Center $(( MVERSION - 1 ))" if [[ ! -d "$current_config_path" ]] && [[ -d "$previous_config_path" ]] && mkdir -p "$current_config_path"; then echo "Migrating $previous_config_path to $current_config_path" cp -a "$previous_config_path"/* "$current_config_path" &>/dev/null fi } ####################################### # Completely uninstalls MC, services, and firewall rules ####################################### uninstall() { debug "Running: ${FUNCNAME[0]}" declare service unit f i if ! askOk "Do you really want to uninstall JRiver Media Center"; then echo "Uninstall canceled" exit 0 fi echo "Stopping and removing all Media Center services" for service in $(compgen -A "function" "service"); do service="${service##service_}" for i in user system; do SERVICE_TYPE="$i" setServiceVars "$service"; for unit in "$SERVICE_NAME" "$TIMER_NAME"; do if systemctl_is_active_cmd "$unit" &>/dev/null || systemctl_is_enabled_cmd "$unit" &>/dev/null; then debug "Disabling $unit" systemctl_disable_cmd "$unit" fi done for f in "$SERVICE_FNAME" "$TIMER_FNAME"; do [[ -f "$f" ]] && debug "Removing $f" && sudo rm -f "$f" done systemctl_reload_cmd done for f in /etc/systemd/system/jriver-*; do sudo rm -f "$f" done done echo "Removing repo files" sudo rm -rf \ "/etc/yum.repos.d/jriver.repo" \ /etc/apt/sources.list.d/{jriver,mediacenter}*.list # also remove legacy repo files if [[ "$ID" == "suse" ]]; then sudo zypper rr jriver &>/dev/null fi echo "Removing firewall rules" if hash firewall-cmd 2>/dev/null; then if [[ -v debug ]]; then debug "firewall_cmd --permanent --remove-service=jriver" firewall_cmd --permanent --remove-service=jriver debug "firewall_cmd --permanent --delete-service=jriver" firewall_cmd --permanent --delete-service=jriver debug "firewall_cmd --reload" firewall_cmd --reload else firewall_cmd --permanent --remove-service=jriver &>/dev/null firewall_cmd --permanent --delete-service=jriver &>/dev/null firewall_cmd --reload &>/dev/null fi elif hash ufw 2>/dev/null; then firewall_cmd="firewall_cmd delete allow jriver" debug "$firewall_cmd" || firewall_cmd+=" &>/dev/null" eval "$firewall_cmd" [[ -f "/etc/ufw/applications.d/jriver" ]] && sudo rm -f /etc/ufw/applications.d/jriver elif hash nft 2>/dev/null; then sudo nft delete table inet jriver fi echo "Uninstalling JRiver Media Center package" mc_pkg_rm_cmd="pkg_remove $MCPKG" debug "$mc_pkg_rm_cmd" || mc_pkg_rm_cmd+=" &>/dev/null" if eval "$mc_pkg_rm_cmd"; then echo "JRiver Media Center has been completely uninstalled" echo "To remove your library files, run: rm -rf $HOME/.jriver" elif [[ $? -eq 100 ]]; then err "JRiver Media Center package '$MCPKG' is not present" err "and was not uninstalled" else err "Could not remove Media Center package" fi } tests() { # To test on Mint/16.04: sudo apt install -y spice-vdagent ca-certificates git; export GIT_SSL_NO_VERIFY=1 exit $? } main() { debug "Running: ${FUNCNAME[0]}" getOS # Distro-specific commands if [[ "$ID" =~ ^(fedora|centos)$ ]]; then pkg_install(){ sudo "$MGR" install -y "$@"; } pkg_remove(){ sudo "$MGR" remove -y "$@"; } pkg_update(){ sudo "$MGR" makecache; } pkg_query(){ rpm -q "$@"; } firewall_cmd(){ sudo firewall-cmd "$@"; } elif [[ "$ID" =~ ^(debian|ubuntu)$ ]]; then pkg_install(){ sudo apt-get install -y -q0 "$@"; } pkg_remove(){ sudo apt-get remove --auto-remove -y -q0 "$@"; } pkg_update(){ sudo apt-get update -y -q0; } pkg_query(){ dpkg -s "$@"; } firewall_cmd(){ sudo ufw "$@"; } elif [[ "$ID" == "suse" ]]; then pkg_install(){ sudo zypper --non-interactive -q install --force --no-confirm "$@"; } pkg_remove(){ sudo zypper --non-interactive -q remove --clean-deps "$@"; } pkg_update(){ sudo zypper --non-interactive -q refresh jriver; } pkg_query(){ rpm -q "$@"; } firewall_cmd(){ sudo firewall-cmd "$@"; } elif [[ "$ID" == "arch" ]]; then pkg_install(){ sudo pacman -Sy --noconfirm "$@"; } pkg_remove(){ sudo pacman -Rs --noconfirm "$@"; } pkg_update(){ sudo pacman -Syy ; } pkg_query(){ sudo pacman -Qs "$@"; } firewall_cmd(){ sudo nft -A INPUT "$@"; } fi parseInput "$@" getVersion # Set target package name if [[ "$ID" =~ ^(fedora|centos|suse)$ ]]; then MCPKG="MediaCenter" [[ "$VERSION_SOURCE" == "user input" ]] && MCPKG="$MCPKG-$MCVERSION" elif [[ "$ID" =~ ^(debian|ubuntu)$ ]]; then MCPKG="mediacenter$MVERSION" [[ "$VERSION_SOURCE" == "user input" ]] && MCPKG="$MCPKG=$MCVERSION" fi declare -g MCRPM="$OUTPUTDIR/RPMS/x86_64/MediaCenter-$MCVERSION.x86_64.rpm" if (( UNINSTALL_SWITCH )); then uninstall exit fi # Some distros need external repos installed for MC libraries if [[ "$ID" == "ubuntu" ]]; then if ! grep ^deb /etc/apt/sources.list|grep -q universe; then echo "Adding universe repository" sudo add-apt-repository universe fi elif [[ "$ID" =~ ^(centos)$ ]] && ! hash dpkg &>/dev/null; then echo "Adding EPEL repository" installPackage epel-release fi if (( REPO_INSTALL_SWITCH )); then if installMCFromRepo; then echo "JRiver Media Center installed successfully from repo" symlinkCerts migrateLibrary restoreLicense openFirewall "jriver-mediacenter" else err "JRiver Media Center installation from repo failed" exit 1 fi fi if (( BUILD_SWITCH )); then installPackage "wget" acquireDeb if [[ "$TARGET" =~ (centos|fedora|suse) ]]; then installPackage "dpkg" "rpm-build" buildRPM fi fi if (( LOCAL_INSTALL_SWITCH )); then if ([[ "$TARGET" =~ (debian|ubuntu) ]] && installMCDEB) || ([[ "$TARGET" =~ (fedora|centos|suse) ]] && installPackage --skip-check-installed --nogpgcheck "$MCRPM") || ([[ "$TARGET" == "arch" ]] && installMCArch); then echo "JRiver Media Center installed successfully from local package" else err "JRiver Media Center local package installation failed" exit 1 fi symlinkCerts migrateLibrary restoreLicense openFirewall "jriver-mediacenter" fi if (( CREATEREPO_SWITCH )); then runCreaterepo fi if [[ "${#SERVICES[@]}" -gt 0 ]]; then declare service for service in "${SERVICES[@]}"; do 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 fi disableCoW # 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 } # Quickly turn debugging on (catch for real with getopt in parseInput()) [[ " $* " =~ ( --debug | -d ) ]] && echo "First Debugging on!" && DEBUG=1 main "$@"