installJRMC 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588
  1. #!/usr/bin/env bash
  2. # This script will install JRiver Media Center and associated services
  3. # on Fedora, CentOS, Debian, and Ubuntu
  4. #
  5. # Copyright (c) 2021 Bryan C. Roessler
  6. # This software is released under the Apache License.
  7. # https://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # See installJRMC --help or printHelp() below
  10. #
  11. # TODO (v2)
  12. # 1. Raspberry Pi OS support
  13. # 2. Interactive installation (ncurses?)
  14. # 3. Additional containerization (createrepo and rpmbuild)
  15. # 4. Tests
  16. #
  17. # BUGS
  18. # 1. No createrepo on Mint
  19. shopt -s extglob
  20. declare -g SCRIPTVERSION="1.0b6"
  21. declare -g OUTPUTDIR="$PWD/output"
  22. declare -g CREATEREPO_WEBROOT="/var/www/jriver"
  23. declare -g USER; USER="${USER:-$(id -un)}"
  24. printHelp() {
  25. debug "Running: ${FUNCNAME[0]}"
  26. cat <<- 'EOF'
  27. USAGE:
  28. installJRMC [[OPTION] [VALUE]]...
  29. If no options (besides -d) are provided, the script will default to '--install repo'.
  30. OPTIONS
  31. --install, -i repo|rpm|deb
  32. repo: Install MC from repository, updates are handled by the system package manager
  33. rpm: Build and install RPM locally (RPM-based distros only)
  34. deb: Download and install offcial MC package locally (useful with --compat flag for older distros)
  35. --build=[suse|fedora|centos]
  36. Build RPM from source DEB but do not install
  37. Specify cross-build target with optional argument, note '=' (ex. --build=suse)
  38. --compat
  39. Build/install MC without minimum library specifiers
  40. --mcversion VERSION
  41. Specify the MC version, ex. "28.0.94" (Default: latest)
  42. --outputdir PATH
  43. Generate rpmbuild output in this directory (Default: ./output)
  44. --restorefile RESTOREFILE
  45. Restore file location for automatic license registration (Default: skip registration)
  46. --betapass PASSWORD
  47. Enter beta team password for access to beta builds
  48. --service, -s SERVICE
  49. See SERVICES section below for a list of possible services to install
  50. --service-type user|system
  51. Starts services at boot (system) or at user login (user) (Default: boot)
  52. --container, -c CONTAINER (TODO: Under construction)
  53. See CONTAINERS section below for a list of possible services to install
  54. --createrepo
  55. Build rpm, copy to webroot, and run createrepo. Use in conjunction with --build=TARGET for crossbuilding repos
  56. --createrepo-webroot PATH
  57. Specify the webroot directory to install the repo (Default: /var/www/jriver)
  58. --createrepo-user USER
  59. Specify the web server user if it differs from $USER
  60. --version, -v
  61. Print this script version and exit
  62. --debug, -d
  63. Print debug output
  64. --help, -h
  65. Print help dialog and exit
  66. --uninstall, -u
  67. Uninstall JRiver MC, remove services, and remove firewall rules (does not remove library files)
  68. SERVICES
  69. jriver-mediaserver
  70. Enable and start a mediaserver systemd service (requires an existing X server) (user)
  71. jriver-mediacenter
  72. Enable and start a mediacenter systemd service (requires an existing X server) (user)
  73. jriver-x11vnc
  74. Enable and start x11vnc for the local desktop (requires an existing X server) (user)
  75. Usually combined with jriver-mediaserver or jriver-mediacenter services
  76. --vncpass and --display are optional (see below)
  77. jriver-xvnc
  78. Enable and start a new Xvnc session running JRiver Media Center (system)
  79. --vncpass PASSWORD
  80. Set vnc password for x11vnc/Xvnc access. If no password is set, the script
  81. will either use existing password stored in ~/.vnc/jrmc_passwd or use no password
  82. --display DISPLAY
  83. Display to start x11vnc/Xvnc (Default: The current display (x11vnc) or the
  84. current display incremented by 1 (Xvnc))
  85. jriver-createrepo
  86. Install hourly service to build latest MC RPM and run createrepo (system)
  87. CONTAINERS (TODO: Under construction)
  88. mediacenter-xvnc
  89. createrepo
  90. EOF
  91. }
  92. # Helpers
  93. debug() { (( DEBUG )) && [[ $# -gt 0 ]] && echo "Debug: $*"; }
  94. err() { echo "Error: $*" >&2; }
  95. askOk() {
  96. declare response
  97. read -r -p "$* [y/N]: " response
  98. [[ "${response,,}" =~ ^(yes|y)$ ]]
  99. return
  100. }
  101. #######################################
  102. # Parse /etc/os-release and provide a compatability layer for unrecognzied distros
  103. #######################################
  104. getOS() {
  105. debug "Running: ${FUNCNAME[0]}"
  106. declare -g ID
  107. if [[ -e "/etc/os-release" ]]; then
  108. source "/etc/os-release"
  109. else
  110. err "/etc/os-release not found"
  111. err "Your OS is unsupported"
  112. printHelp && exit 1
  113. fi
  114. debug "Platform: $ID $VERSION_ID"
  115. case "$ID" in
  116. centos|fedora|debian|ubuntu)
  117. return 0
  118. ;;
  119. linuxmint|neon)
  120. ID="ubuntu"
  121. ;;
  122. *suse*)
  123. ID="suse"
  124. ;;
  125. *)
  126. echo "Attempting to autodetect RPM/DEB distro, this may be unreliable"
  127. if hash dnf &>/dev/null || hash yum &>/dev/null; then
  128. ID="fedora"
  129. elif hash apt &>/dev/null; then
  130. ID="ubuntu"
  131. fi
  132. ;;
  133. esac
  134. debug "Using compatability platform: $ID"
  135. }
  136. parseInput() {
  137. debug "Running: ${FUNCNAME[0]}"
  138. declare -g BUILD_SWITCH REPO_INSTALL_SWITCH COMPAT_SWITCH
  139. declare -g CREATEREPO_SWITCH UNINSTALL_SWITCH DEB_INSTALL_SWITCH
  140. declare -g TARGET OUTPUTDIR MCVERSION RESTOREFILE BETAPASS SERVICE_TYPE
  141. declare -g VNCPASS USER_DISPLAY CREATEREPO_WEBROOT CREATEREPO_USER
  142. declare -ga SERVICES CONTAINERS
  143. declare long_opts short_opts
  144. if [[ $# -eq 0 ]] || [[ $# -eq 1 && "$1" =~ ^(--debug|-d)$ ]]; then
  145. REPO_INSTALL_SWITCH=1
  146. elif [[ $# -eq 1 && "$1" =~ ^(--compat)$ ]]; then
  147. TARGET="$ID"
  148. BUILD_SWITCH=1
  149. # separate ordering is probably more reliable
  150. if [[ "$ID" =~ (ubuntu|debian) ]]; then
  151. DEB_INSTALL_SWITCH=1
  152. elif [[ "$ID" =~ (fedora|centos|suse) ]]; then
  153. RPM_INSTALL_SWITCH=1
  154. fi
  155. fi
  156. long_opts="install:,build::,outputdir:,mcversion:,restorefile:,betapass:,"
  157. long_opts+="service-type:,service:,version,debug,help,uninstall,createrepo,"
  158. long_opts+="createrepo-webroot:,createrepo-user:,vncpass:,display:,container:,tests,compat"
  159. short_opts="+i:vb::dhus:c:"
  160. if _input=$(getopt -o $short_opts -l $long_opts -- "$@"); then
  161. eval set -- "$_input"
  162. while true; do
  163. case "$1" in
  164. --install|-i)
  165. shift
  166. case "$1" in
  167. rpm)
  168. BUILD_SWITCH=1
  169. RPM_INSTALL_SWITCH=1
  170. ;;
  171. deb)
  172. BUILD_SWITCH=1
  173. DEB_INSTALL_SWITCH=1
  174. ;;
  175. repo)
  176. REPO_INSTALL_SWITCH=1
  177. ;;
  178. esac
  179. ;;
  180. --build|-b)
  181. BUILD_SWITCH=1
  182. shift && TARGET="$1"
  183. ;;
  184. --outputdir)
  185. shift && OUTPUTDIR="$1"
  186. ;;
  187. --mcversion)
  188. shift && MCVERSION="$1"
  189. ;;
  190. --restorefile)
  191. shift && RESTOREFILE="$1"
  192. ;;
  193. --betapass)
  194. shift && BETAPASS="$1"
  195. ;;
  196. --service-type)
  197. shift && SERVICE_TYPE="$1"
  198. ;;
  199. --service|-s)
  200. shift && SERVICES+=("$1")
  201. ;;
  202. --createrepo)
  203. BUILD_SWITCH=1
  204. CREATEREPO_SWITCH=1
  205. ;;
  206. --createrepo-webroot)
  207. shift && CREATEREPO_WEBROOT="$1"
  208. ;;
  209. --createrepo-user)
  210. shift && CREATEREPO_USER="$1"
  211. ;;
  212. --vncpass)
  213. shift && VNCPASS="$1"
  214. ;;
  215. --display)
  216. shift && USER_DISPLAY="$1"
  217. ;;
  218. --compat)
  219. COMPAT_SWITCH=1
  220. ;;
  221. --container|-c)
  222. shift && CONTAINERS+=("$1")
  223. ;;
  224. --version|-v)
  225. echo "Version: $SCRIPTVERSION"
  226. exit 0
  227. ;;
  228. --debug|-d)
  229. echo "Debugging on"
  230. echo "installJRMC version: $SCRIPTVERSION"
  231. DEBUG=1
  232. ;;
  233. --help|-h)
  234. printHelp && exit $?
  235. ;;
  236. --uninstall|-u)
  237. UNINSTALL_SWITCH=1
  238. ;;
  239. --tests)
  240. echo "Running tests, all other options are skipped"
  241. tests
  242. ;;
  243. --)
  244. shift
  245. break
  246. ;;
  247. esac
  248. shift
  249. done
  250. else
  251. err "Incorrect options provided"
  252. printHelp && exit 1
  253. fi
  254. ! debug && echo "Use --debug for verbose output"
  255. }
  256. #######################################
  257. # Use several methods to determine the latest JRiver MC version
  258. #######################################
  259. getLatestVersion() {
  260. debug "Running: ${FUNCNAME[0]}"
  261. declare -g MCVERSION BASE="buster" # For container method
  262. #declare -g BASE_NEXT="bullseye" # TODO possibly use for fallback to smooth upgrades
  263. declare boardurl="https://yabb.jriver.com/interact/index.php/board,71.0.html" # MC28 (Buster), for fallback webscrape
  264. # Containerized package manager
  265. # TODO but how to determine build distro ($BASE=buster)?
  266. if installPackage --silent buildah &&
  267. cnt=$(buildah from debian:$BASE) &>/dev/null &&
  268. buildah run "$cnt" -- bash -c \
  269. "echo 'deb [trusted=no arch=amd64,i386,armhf,arm64] http://dist.jriver.com/latest/mediacenter/ $BASE main' > /etc/apt/sources.list 2>&1" &&
  270. buildah run "$cnt" -- bash -c \
  271. "apt-get update --allow-insecure-repositories &>/dev/null" &&
  272. MCVERSION=$(buildah run "$cnt" -- apt-cache policy mediacenter?? | grep Candidate | awk '{print $2}' | sort -V | tail -n1) &&
  273. [[ "$MCVERSION" =~ ([0-9]+.[0-9]+.[0-9]+) ]] &&
  274. VERSION_SOURCE="containerized package manager"; then
  275. buildah rm "$cnt" &>/dev/null
  276. # Webscrape
  277. elif installPackage wget && MCVERSION=$(wget -qO- "$boardurl" | grep -o "[0-9][0-9]\.[0-9]\.[0-9]\+" | head -n 1); then
  278. VERSION_SOURCE="webscrape"
  279. else
  280. MCVERSION="28.0.100"
  281. VERSION_SOURCE="hardcoded version"
  282. err "Warning! Using hardcoded version number"
  283. fi
  284. }
  285. #######################################
  286. # Installs a package using the system package manager
  287. # Arguments:
  288. # One or more package names
  289. # Options:
  290. # --skip-check-installed: Do not check if package is already installed
  291. # --nogpgcheck: Disable GPG checks for RPM based distros
  292. # --allow-downgrades: Useful for installing compatability versions on DEB based distros
  293. # --silent, -s: Do not report errors (useful if package is not strictly required and errors are noisy)
  294. #######################################
  295. installPackage() {
  296. debug "Running: ${FUNCNAME[0]}" "$@"
  297. declare -a pkg_array install_flags
  298. declare pkg skip_check_installed silent _return pkg_install_cmd
  299. if _input=$(getopt -o +s -l skip-check-installed,allow-downgrades,nogpgcheck,silent -- "$@"); then
  300. eval set -- "$_input"
  301. while true; do
  302. case "$1" in
  303. --skip-check-installed)
  304. skip_check_installed=1
  305. ;;
  306. --allow-downgrades)
  307. [[ "$ID" =~ (debian|ubuntu) ]] && install_flags+=(--allow-downgrades)
  308. ;;
  309. --nogpgcheck)
  310. if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
  311. install_flags+=(--nogpgcheck)
  312. elif [[ "$ID" == "suse" ]]; then
  313. install_flags+=(--allow-unsigned-rpm)
  314. fi
  315. ;;
  316. --silent|-s)
  317. silent=1
  318. ;;
  319. --)
  320. shift
  321. break
  322. ;;
  323. esac
  324. shift
  325. done
  326. else
  327. err "Incorrect options provided"
  328. exit 1
  329. fi
  330. # Aliases
  331. if [[ "$ID" =~ ^(debian|ubuntu)$ ]]; then
  332. declare -A PKG_ALIASES
  333. PKG_ALIASES["xorg-x11-utils"]="xorg-x11"
  334. PKG_ALIASES["rpm-build"]="rpm"
  335. PKG_ALIASES["createrepo_c"]="createrepo"
  336. PKG_ALIASES["tigervnc-server"]="tigervnc-standalone-server"
  337. fi
  338. for pkg in "$@"; do
  339. if [[ ! -v skip_check_installed && -v PKG_ALIASES[$pkg] ]]; then
  340. pkg=${PKG_ALIASES[$pkg]}
  341. fi
  342. # Check if already installed
  343. if (( skip_check_installed )) || ! (hash $pkg &>/dev/null || pkg_query "$pkg" &>/dev/null); then
  344. pkg_array+=("$pkg")
  345. fi
  346. done
  347. # Install packages from package array
  348. if [[ ${#pkg_array[@]} -ge 1 ]]; then
  349. pkg_install_cmd="pkg_install ${install_flags[*]} ${pkg_array[*]}"
  350. debug "$pkg_install_cmd" || pkg_install_cmd+=" &>/dev/null"
  351. if ! eval "$pkg_install_cmd"; then
  352. (( silent )) || err "Failed to install ${pkg_array[*]}. Attempting to continue"
  353. return 1
  354. fi
  355. fi
  356. return 0
  357. }
  358. #######################################
  359. # Installs a package using the system package manager
  360. # Arguments:
  361. # One or more package names
  362. # Options:
  363. # --skip-check-installed: Do not check if package is already installed
  364. # --nogpgcheck: Disable GPG checks for RPM based distros
  365. # --allow-downgrades: Useful for installing compatability versions on DEB based distros
  366. # --silent, -s: Do not report errors (useful if package is not strictly required and errors are noisy)
  367. #######################################
  368. installMCDEB() {
  369. debug "Running: ${FUNCNAME[0]}"
  370. aquireDeb
  371. declare mcdeb="$MCDEB"
  372. declare pkg_install_cmd="installPackage --skip-check-installed --nogpgcheck"
  373. if (( COMPAT_SWITCH )); then
  374. declare extract_dir && extract_dir="$(mktemp -d)"
  375. mcdeb="${MCDEB/.deb/.compat.deb}"
  376. pushd "$extract_dir" &>/dev/null || return
  377. ar x "$MCDEB"
  378. tar -xJf "control.tar.xz"
  379. # Remove minimum version specifiers from control file
  380. sed -i 's/ ([^)]*)//g' "control"
  381. sed -i 's/([^)]*)//g' "control" # TODO MC DEB package error
  382. tar -cJf "control.tar.xz" "control" "postinst"
  383. ar rcs "$mcdeb" "debian-binary" "control.tar.xz" "data.tar.xz"
  384. popd &>/dev/null || return
  385. rm -rf "$extract_dir"
  386. pkg_install_cmd+=" --allow-downgrades"
  387. fi
  388. pkg_install_cmd+=" $mcdeb"
  389. debug "$pkg_install_cmd" || pkg_install_cmd+=" &>/dev/null"
  390. eval "$pkg_install_cmd"
  391. }
  392. #######################################
  393. # Add the JRiver repository files
  394. #######################################
  395. addRepo() {
  396. debug "Running: ${FUNCNAME[0]}"
  397. echo "Adding JRiver repository to package manager"
  398. if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
  399. declare sources_dir="/etc/yum.repos.d/"
  400. sudo bash -c "cat <<- EOF > $sources_dir/jriver.repo
  401. [jriver]
  402. name=JRiver Media Center repo by BryanC
  403. baseurl=https://repos.bryanroessler.com/jriver
  404. gpgcheck=0
  405. EOF"
  406. elif [[ "$ID" =~ ^(debian|ubuntu)$ ]]; then
  407. installPackage wget
  408. declare sources_dir="/etc/apt/sources.list.d"
  409. [[ ! -d $sources_dir ]] && sudo mkdir -p "$sources_dir"
  410. sudo rm -rf "$sources_dir"/mediacenter*.list
  411. sudo bash -c "cat <<- EOF > $sources_dir/jriver.list
  412. deb [trusted=yes arch=amd64,i386,armhf,arm64] http://dist.jriver.com/latest/mediacenter/ $BASE main
  413. EOF"
  414. wget -q "http://dist.jriver.com/mediacenter@jriver.com.gpg.key" -O- | sudo apt-key add - &>/dev/null
  415. elif [[ "$ID" == "suse" ]]; then
  416. sudo zypper addrepo --no-gpgcheck "https://repos.bryanroessler.com/jriver" jriver &>/dev/null
  417. fi
  418. }
  419. #######################################
  420. # Installs JRiver Media Center from a repository
  421. #######################################
  422. installMCFromRepo() {
  423. debug "Running: ${FUNCNAME[0]}"
  424. addRepo
  425. # Update package list
  426. pkg_update_cmd="pkg_update"
  427. debug "$pkg_update_cmd" || pkg_update_cmd+=" &>/dev/null"
  428. if ! eval "$pkg_update_cmd"; then
  429. err "Package update failed!"
  430. exit 1
  431. fi
  432. echo "Installing JRiver Media Center using your package manager"
  433. pkg_install_cmd="installPackage --skip-check-installed --nogpgcheck $MCPKG"
  434. debug "$pkg_install_cmd" || pkg_install_cmd+=" &>/dev/null"
  435. eval "$pkg_install_cmd"
  436. }
  437. #######################################
  438. # Acquire the source DEB package from JRiver's servers
  439. #######################################
  440. acquireDeb() {
  441. debug "Running: ${FUNCNAME[0]}"
  442. declare -g MCDEB="$OUTPUTDIR/SOURCES/MediaCenter-$MCVERSION-amd64.deb"
  443. # If necessary, create SOURCES dir
  444. [[ ! -d "$OUTPUTDIR/SOURCES" ]] && mkdir -p "$OUTPUTDIR/SOURCES"
  445. # If deb file already exists, skip download
  446. if [[ -f "$MCDEB" ]]; then
  447. echo "Using local source DEB: $MCDEB"
  448. return 0
  449. fi
  450. if [[ -v BETAPASS ]]; then
  451. echo "Checking beta repo for DEB package"
  452. if wget -q -O "$MCDEB" \
  453. "https://files.jriver.com/mediacenter/channels/v$MVERSION/beta/$BETAPASS/MediaCenter-$MCVERSION-amd64.deb"; then
  454. echo "Found!"
  455. fi
  456. elif echo "Checking test repo for DEB package" && wget -q -O "$MCDEB" \
  457. "https://files.jriver.com/mediacenter/test/MediaCenter-$MCVERSION-amd64.deb"; then
  458. echo "Found!"
  459. # Else check latest repo
  460. elif echo "Checking latest repo for DEB package" && wget -q -O "$MCDEB" \
  461. "https://files.jriver.com/mediacenter/channels/v$MVERSION/latest/MediaCenter-$MCVERSION-amd64.deb"; then
  462. echo "Found!"
  463. else
  464. err "Cannot find DEB file"
  465. exit 1
  466. fi
  467. if [[ -f "$MCDEB" ]]; then
  468. echo "Downloaded MC $MCVERSION DEB to: $MCDEB"
  469. else
  470. err "Downloaded DEB file missing or corrupted"
  471. exit 1
  472. fi
  473. }
  474. #######################################
  475. # Creates a SPEC file and builds the RPM from the source DEB using rpmbuild
  476. #######################################
  477. buildRPM() {
  478. debug "Running: ${FUNCNAME[0]}"
  479. declare id i rpmbuild_cmd
  480. declare -a requires recommends
  481. declare -A dupes
  482. # skip rebuilding the rpm if it already exists
  483. if [[ -f "$MCRPM" ]]; then
  484. echo "$MCRPM already exists. Skipping build step"
  485. return 0
  486. fi
  487. [[ ! -d "$OUTPUTDIR/SPECS" ]] && mkdir -p "$OUTPUTDIR/SPECS"
  488. if [[ ! "$id" =~ (fedora|centos|suse) ]]; then
  489. err "The current RPM build target $id is not supported, manually specify with --target"
  490. err "The DEB file is located at $MCDEB"
  491. return 1
  492. fi
  493. # Load deb dependencies into array
  494. IFS=',' read -ra requires <<< "$(dpkg-deb -f "$MCDEB" Depends)"
  495. IFS=',' read -ra recommends <<< "$(dpkg-deb -f "$MCDEB" Recommends)"
  496. # Clean up formatting
  497. requires=("${requires[@]%%|*}")
  498. requires=("${requires[@]/?:/}")
  499. requires=("${requires[@]# }")
  500. requires=("${requires[@]% }")
  501. requires=("${requires[@]//\(/}")
  502. requires=("${requires[@]//)/}")
  503. recommends=("${recommends[@]%%|*}")
  504. recommends=("${recommends[@]/?:/}")
  505. recommends=("${recommends[@]# }")
  506. recommends=("${recommends[@]% }")
  507. recommends=("${recommends[@]//\(/}")
  508. recommends=("${recommends[@]//)/}")
  509. # Translate package names
  510. case "$id" in
  511. fedora|centos)
  512. requires=("${requires[@]/libc6/glibc}")
  513. requires=("${requires[@]/libasound2/alsa-lib}")
  514. requires=("${requires[@]/libuuid1/libuuid}")
  515. requires=("${requires[@]/libx11-6/libX11}")
  516. requires=("${requires[@]/libxext6/libXext}")
  517. requires=("${requires[@]/libxcb1/libxcb}")
  518. requires=("${requires[@]/libxdmcp6/libXdmcp}")
  519. requires=("${requires[@]/libstdc++6/libstdc++}")
  520. requires=("${requires[@]/libgtk-3-0/gtk3}")
  521. requires=("${requires[@]/libgl1/mesa-libGL}")
  522. requires=("${requires[@]/libpango-1.0-0/pango}")
  523. requires=("${requires[@]/libpangoft2-1.0-0/pango}")
  524. requires=("${requires[@]/libpangox-1.0-0/pango}")
  525. requires=("${requires[@]/libpangoxft-1.0-0/pango}")
  526. requires=("${requires[@]/libnss3/nss}")
  527. requires=("${requires[@]/libnspr4/nspr}")
  528. requires=("${requires[@]/libgomp1/libgomp}")
  529. requires=("${requires[@]/libfribidi0/fribidi}")
  530. requires=("${requires[@]/libfontconfig1/fontconfig}")
  531. requires=("${requires[@]/libfreetype6/freetype}")
  532. requires=("${requires[@]/libharfbuzz0b/harfbuzz}")
  533. requires=("${requires[@]/libgbm1/mesa-libgbm}")
  534. requires=("${requires[@]/libva2/libva}")
  535. requires=("${requires[@]/libepoxy0/libepoxy}")
  536. requires=("${requires[@]/liblcms2-2/lcms2}")
  537. requires=("${requires[@]/libvulkan1/vulkan-loader}")
  538. requires=("${requires[@]/libepoxy0/libepoxy}")
  539. ;;
  540. suse)
  541. requires=("${requires[@]/libc6/glibc}")
  542. requires=("${requires[@]/libasound2/alsa-lib}")
  543. requires=("${requires[@]/libx11-6/libX11-6}")
  544. requires=("${requires[@]/libxext6/libXext6}")
  545. requires=("${requires[@]/libxdmcp6/libXdmcp6}")
  546. requires=("${requires[@]/libgtk-3-0/gtk3}")
  547. requires=("${requires[@]/libgl1/Mesa-libGL1}")
  548. requires=("${requires[@]/libpango-1.0-0/pango}")
  549. requires=("${requires[@]/libpangoft2-1.0-0/pango}")
  550. requires=("${requires[@]/libpangox-1.0-0/pango}")
  551. requires=("${requires[@]/libpangoxft-1.0-0/pango}")
  552. requires=("${requires[@]/libnss3/mozilla-nss}")
  553. requires=("${requires[@]/libnspr4/mozilla-nspr}")
  554. requires=("${requires[@]/libfribidi0/fribidi}")
  555. requires=("${requires[@]/libfontconfig1/fontconfig}")
  556. requires=("${requires[@]/libfreetype6*/freetype}") # Remove minimum version specifier
  557. requires=("${requires[@]/libharfbuzz0b/libharfbuzz0}")
  558. for i in "${!requires[@]}"; do
  559. [[ "${requires[$i]}" == "mesa-vulkan-drivers" ]] && unset -v 'requires[i]'
  560. done
  561. recommends+=(libvulkan_intel)
  562. recommends+=(libvulkan_radeon)
  563. ;;
  564. esac
  565. # Remove duplicates
  566. for i in "${requires[@]}"; do
  567. if [[ ! -v dupes[${i%% *}] ]]; then
  568. tmp+=("$i")
  569. fi
  570. dupes["${i%% *}"]=1
  571. done
  572. requires=("${tmp[@]}")
  573. # Convert array to newline delim'd string (for heredoc)
  574. printf -v requires "Requires: %s\n" "${requires[@]}"
  575. printf -v recommends "Recommends: %s\n" "${recommends[@]}"
  576. # Strip last newline
  577. requires="${requires%?}"
  578. recommends="${recommends%?}"
  579. if (( COMPAT_SWITCH )); then
  580. # Strip minimum versions
  581. requires=$(echo "$requires" | awk -F" " 'NF == 4 {print $1 " " $2} NF != 4 {print $0}')
  582. fi
  583. # Create spec file
  584. cat <<- EOF > "$OUTPUTDIR/SPECS/mediacenter.spec"
  585. Name: MediaCenter
  586. Version: $MCVERSION
  587. Release: 1
  588. Summary: JRiver Media Center
  589. Group: Applications/Media
  590. Source0: http://files.jriver.com/mediacenter/channels/v$MVERSION/latest/MediaCenter-$MCVERSION-amd64.deb
  591. BuildArch: x86_64
  592. %define _rpmfilename %%{ARCH}/%%{NAME}-%%{version}.%%{ARCH}.rpm
  593. AutoReq: 0
  594. $requires
  595. $recommends
  596. Provides: mediacenter$MVERSION
  597. License: Copyright 1998-2022, JRiver, Inc. All rights reserved. Protected by U.S. patents #7076468 and #7062468
  598. URL: http://www.jriver.com/
  599. %define __provides_exclude_from ^%{_libdir}/jriver/.*/.*\\.so.*$
  600. %description
  601. Media Center is more than a world class player.
  602. %global __os_install_post %{nil}
  603. %prep
  604. %build
  605. %install
  606. dpkg -x %{S:0} %{buildroot}
  607. %post -p /sbin/ldconfig
  608. %postun -p /sbin/ldconfig
  609. %files
  610. %{_bindir}/mediacenter$MVERSION
  611. %{_libdir}/jriver
  612. %{_datadir}
  613. %exclude %{_datadir}/applications/media_center_packageinstaller_$MVERSION.desktop
  614. /etc/security/limits.d/*
  615. EOF
  616. # Run rpmbuild
  617. echo "Building RPM for MC $MCVERSION, this may take awhile"
  618. rpmbuild_cmd="rpmbuild --define=\"%_topdir $OUTPUTDIR\" --define=\"%_libdir /usr/lib\" -bb"
  619. rpmbuild_cmd+=" $OUTPUTDIR/SPECS/mediacenter.spec"
  620. debug "$rpmbuild_cmd" || rpmbuild_cmd+=" &>/dev/null"
  621. if eval "$rpmbuild_cmd" && [[ -f "$MCRPM" ]] ; then
  622. echo "Build successful. The RPM file is located at: $MCRPM"
  623. else
  624. err "Build failed"
  625. # For automation, let's remove the source DEB and reaquire it on next run
  626. # after failure in case it is corrupted or buggy
  627. [[ -f "$MCDEB" ]] && echo "Removing source DEB" && rm -f "$MCDEB"
  628. exit 1
  629. fi
  630. }
  631. #######################################
  632. # Copy the RPM to createrepo-webroot and runs createrepo as the createrepo-user
  633. #######################################
  634. runCreaterepo() {
  635. debug "Running: ${FUNCNAME[0]}"
  636. declare cr_cmd cr_cp_cmd cr_mkdir_cmd cr_chown_cmd
  637. declare cr_user="${CREATEREPO_USER:$USER}"
  638. installPackage createrepo_c
  639. # If the webroot does not exist, create it
  640. if [[ ! -d "$CREATEREPO_WEBROOT" ]]; then
  641. cr_mkdir_cmd="sudo -u $cr_user mkdir -p $CREATEREPO_WEBROOT"
  642. debug "$cr_mkdir_cmd" || cr_mkdir_cmd+=" &>/dev/null"
  643. if ! eval "$cr_mkdir_cmd"; then
  644. cr_mkdir_cmd="sudo mkdir -p $CREATEREPO_WEBROOT"
  645. debug "$cr_mkdir_cmd" || cr_mkdir_cmd+=" &>/dev/null"
  646. cr_chown_cmd="sudo chown -R $cr_user:$cr_user $CREATEREPO_WEBROOT"
  647. debug "$cr_chown_cmd" || cr_chown_cmd+=" &>/dev/null"
  648. if ! ( eval "$cr_mkdir_cmd" && eval "$cr_chown_cmd" ); then
  649. err "Could not create the createrepo-webroot path!"
  650. err "Make sure that the webroot $CREATEREPO_WEBROOT is writeable by user $cr_user"
  651. err "Or change the repo ownership with --createrepo-user"
  652. return 1
  653. fi
  654. fi
  655. fi
  656. # Copy built rpms to webroot
  657. cr_cp_cmd="sudo cp -nf $MCRPM $CREATEREPO_WEBROOT"
  658. cr_chown_cmd="sudo chown -R $cr_user:$cr_user $CREATEREPO_WEBROOT"
  659. debug "$cr_cp_cmd" || cr_cp_cmd+=" &>/dev/null"
  660. debug "$cr_chown_cmd" || cr_cp_cmd+=" &>/dev/null"
  661. if ! ( eval "$cr_cp_cmd" && eval "$cr_chown_cmd" ); then
  662. err "Could not copy $MCRPM to $CREATEREPO_WEBROOT"
  663. return 1
  664. fi
  665. # Run createrepo
  666. cr_cmd="sudo -u $cr_user createrepo -q $CREATEREPO_WEBROOT"
  667. [[ -d "$CREATEREPO_WEBROOT/repodata" ]] && cr_cmd+=" --update"
  668. debug "$cr_cmd" || cr_cmd+=" &>/dev/null"
  669. if ! eval "$cr_cmd"; then
  670. cr_cmd="sudo createrepo -q $CREATEREPO_WEBROOT"
  671. [[ -d "$CREATEREPO_WEBROOT/repodata" ]] && cr_cmd+=" --update"
  672. cr_chown_cmd="sudo chown -R $cr_user:$cr_user $CREATEREPO_WEBROOT"
  673. debug "$cr_cmd" || cr_cmd+=" &>/dev/null"
  674. debug "$cr_chown_cmd" || cr_cp_cmd+=" &>/dev/null"
  675. if ! ( eval "$cr_cmd" && eval "$cr_chown_cmd"); then
  676. err "Createrepo failed"
  677. return 1
  678. fi
  679. fi
  680. echo "Successfully updated repo"
  681. }
  682. #######################################
  683. # Symlink certificates where JRiver Media Center expects them to be on Fedora/CentOS
  684. #######################################
  685. symlinkCerts() {
  686. debug "Running: ${FUNCNAME[0]}"
  687. if [[ ! -f /etc/ssl/certs/ca-certificates.crt &&
  688. -f /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem ]]; then
  689. ln_cmd="sudo ln -s /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem /etc/ssl/certs/ca-certificates.crt"
  690. debug "$ln_cmd" || ln_cmd+=" &>/dev/null"
  691. if ! exec "$ln_cmd"; then
  692. err "Symlinking certificates failed"
  693. return 1
  694. fi
  695. fi
  696. }
  697. #######################################
  698. # Automatically restore the mjr license file if it is found next to
  699. # installJRMC or RESTOREFILE is set
  700. #######################################
  701. restoreLicense() {
  702. debug "Running: ${FUNCNAME[0]}"
  703. declare mjrfile
  704. # Allow user to put the mjr file next to installJRMC
  705. if [[ ! -v RESTOREFILE ]]; then
  706. for mjrfile in "$PWD"/*.mjr; do
  707. [[ $mjrfile -nt $RESTOREFILE ]] && RESTOREFILE="$mjrfile"
  708. done
  709. fi
  710. # Restore license
  711. if [[ -f "$RESTOREFILE" ]]; then
  712. if ! "mediacenter$MVERSION" /RestoreFromFile "$RESTOREFILE"; then
  713. err "Automatic license restore failed"
  714. return 1
  715. fi
  716. fi
  717. }
  718. #######################################
  719. # Opens ports using the system firewall tool
  720. # Arguments:
  721. # Pre-defined service to enable
  722. #######################################
  723. openFirewall() {
  724. debug "Running: ${FUNCNAME[0]}" "$@"
  725. # Create OS-specific port rules based on argument (service) name
  726. declare -a f_ports # for firewall-cmd
  727. declare u_ports # for ufw
  728. if [[ "$1" == "jriver" ]]; then
  729. f_ports=(52100-52200/tcp 1900/udp)
  730. u_ports="52100:52200/tcp|1900/udp"
  731. elif [[ "$1" =~ ^(jriver-x11vnc|jriver-xvnc)$ ]]; then
  732. f_ports=("$PORT"/tcp 1900/udp)
  733. u_ports="$PORT/tcp|1900/udp"
  734. fi
  735. # Open the ports
  736. if [[ "$ID" =~ ^(fedora|centos|suse)$ ]]; then
  737. installPackage firewalld
  738. if ! firewall_cmd --get-services | grep -q "$1"; then
  739. firewall_cmd --permanent --new-service="$1" &>/dev/null
  740. firewall_cmd --permanent --service="$1" --set-description="$1 installed by installJRMC" &>/dev/null
  741. firewall_cmd --permanent --service="$1" --set-short="$1" &>/dev/null
  742. for f_port in "${f_ports[@]}"; do
  743. firewall_cmd --permanent --service="$1" --add-port="$f_port" &>/dev/null
  744. done
  745. firewall_cmd --add-service "$1" --permanent &>/dev/null
  746. firewall_cmd --reload &>/dev/null
  747. fi
  748. elif [[ "$ID" =~ ^(debian|ubuntu)$ ]]; then
  749. # Debian ufw package state is broken on fresh installations
  750. installPackage ufw
  751. if [[ ! -f "/etc/ufw/applications.d/$1" ]]; then
  752. sudo bash -c "cat <<- EOF > /etc/ufw/applications.d/$1
  753. [$1]
  754. title=$1
  755. description=$1 installed by installJRMC
  756. ports=$u_ports
  757. EOF"
  758. fi
  759. firewall_cmd app update "$1" &>/dev/null
  760. firewall_cmd allow "$1" &>/dev/null
  761. fi
  762. # shellcheck disable=SC2181 # More concise
  763. if [[ $? -ne 0 ]]; then
  764. err "Firewall ports could not be opened"
  765. return 1
  766. fi
  767. }
  768. #######################################
  769. # Create the x11vnc password file
  770. #######################################
  771. setX11VNCPass() {
  772. debug "Running: ${FUNCNAME[0]}"
  773. declare vncpassfile="$HOME/.vnc/jrmc_passwd"
  774. [[ ! -d "${vncpassfile%/*}" ]] && mkdir -p "${vncpassfile%/*}"
  775. if [[ -f "$vncpassfile" ]]; then
  776. if [[ ! -v VNCPASS ]]; then
  777. err "Refusing to overwrite existing $vncpassfile with an empty password"
  778. err "Remove existing $vncpassfile or set --vncpass to use an empty password"
  779. exit 1
  780. else
  781. rm -f "$vncpassfile"
  782. fi
  783. fi
  784. if [[ -v VNCPASS ]]; then
  785. if ! x11vnc -storepasswd "$VNCPASS" "$vncpassfile"; then
  786. err "Could not create VNC password file"
  787. return 1
  788. fi
  789. else
  790. declare -g NOVNCAUTH=1
  791. fi
  792. }
  793. #######################################
  794. # Create the Xvnc password file
  795. #######################################
  796. setVNCPass() {
  797. debug "Running: ${FUNCNAME[0]}"
  798. declare vncpassfile="$HOME/.vnc/jrmc_passwd"
  799. [[ ! -d "${vncpassfile%/*}" ]] && mkdir -p "${vncpassfile%/*}"
  800. if [[ -f "$vncpassfile" ]]; then
  801. if [[ ! -v VNCPASS ]]; then
  802. err "Refusing to overwrite existing $vncpassfile with an empty password"
  803. err "Remove existing $vncpassfile or set --vncpass to use an empty password"
  804. exit 1
  805. else
  806. rm -f "$vncpassfile"
  807. fi
  808. fi
  809. if [[ -v VNCPASS ]]; then
  810. if ! echo "$VNCPASS" | vncpasswd -f > "$vncpassfile"; then
  811. err "Could not create VNC password file"
  812. return 1
  813. fi
  814. else
  815. declare -g NOVNCAUTH=1
  816. fi
  817. }
  818. #######################################
  819. # Set display and port variables
  820. #######################################
  821. setDisplay() {
  822. debug "Running: ${FUNCNAME[0]}"
  823. declare -g DISPLAY DISPLAYNUM NEXT_DISPLAY NEXT_DISPLAYNUM
  824. # Check USER_DISPLAY, else environment DISPLAY, else set to :0 by default
  825. DISPLAY="${USER_DISPLAY:-${DISPLAY:-0}}"
  826. DISPLAYNUM="${DISPLAY#*:}" # strip prefix
  827. DISPLAYNUM="${DISPLAYNUM%%.*}" # strip suffix
  828. NEXT_DISPLAYNUM=$(( DISPLAYNUM + 1 ))
  829. NEXT_DISPLAY=":$NEXT_DISPLAYNUM"
  830. }
  831. #######################################
  832. # Create associated service variables based on service name
  833. # Arguments
  834. # Pre-defined service to enable
  835. #######################################
  836. setServiceVars() {
  837. debug "Running: ${FUNCNAME[0]}"
  838. declare -g SERVICE_NAME SERVICE_FNAME TIMER_NAME TIMER_FNAME USER_STRING
  839. declare -g SERVICE_TYPE="${SERVICE_TYPE:-system}"
  840. declare service_dir="/usr/lib/systemd/$SERVICE_TYPE"
  841. if [[ "$USER" == "root" && "$SERVICE_TYPE" == "user" ]]; then
  842. err "Trying to install user service as root"
  843. err "Use --service-type service and/or execute installJRMC as non-root user"
  844. return 1
  845. fi
  846. if [[ "$SERVICE_TYPE" == "system" ]]; then
  847. systemctl_reload_cmd(){ sudo systemctl daemon-reload; }
  848. systemctl_enable_cmd(){ sudo systemctl enable --now "$@"; }
  849. systemctl_disable_cmd(){ sudo systemctl disable --now "$@"; }
  850. systemctl_is_enabled_cmd(){ sudo systemctl is-enabled -q "$@"; }
  851. systemctl_is_active_cmd(){ sudo systemctl is-active -q "$@"; }
  852. elif [[ "$SERVICE_TYPE" == "user" ]]; then
  853. systemctl_reload_cmd(){ systemctl --user daemon-reload; }
  854. systemctl_enable_cmd(){ systemctl --user enable --now "$@"; }
  855. systemctl_disable_cmd(){ systemctl --user disable --now "$@"; }
  856. systemctl_is_enabled_cmd(){ systemctl --user is-enabled -q "$@"; }
  857. systemctl_is_active(){ sudo systemctl is-active -q "$@"; }
  858. fi
  859. [[ ! -d "$service_dir" ]] && sudo mkdir -p "$service_dir"
  860. if [[ "$SERVICE_TYPE" == "system" && "$USER" != "root" ]]; then
  861. SERVICE_FNAME="$service_dir/${1}@.service"
  862. TIMER_FNAME="$service_dir/${1}@.timer"
  863. SERVICE_NAME="${1}@$USER.service"
  864. TIMER_NAME="${1}@$USER.timer"
  865. USER_STRING="User=%I"
  866. else
  867. SERVICE_NAME="${1}.service"
  868. TIMER_NAME="${1}.timer"
  869. SERVICE_FNAME="$service_dir/${SERVICE_NAME}"
  870. TIMER_FNAME="$service_dir/${TIMER_NAME}"
  871. USER_STRING=""
  872. fi
  873. }
  874. #######################################
  875. # Starts and enables (at startup) a JRiver Media Center service
  876. # Arguments:
  877. # Passes arguments as startup options to /usr/bin/mediacenter??
  878. #######################################
  879. service_jriver-mediacenter() {
  880. debug "Running: ${FUNCNAME[0]}"
  881. setServiceVars "${FUNCNAME[0]##*_}"
  882. sudo bash -c "cat <<- EOF > $SERVICE_FNAME
  883. [Unit]
  884. Description=JRiver Media Center $MVERSION
  885. After=graphical.target
  886. [Service]
  887. $USER_STRING
  888. Type=simple
  889. Environment=DISPLAY=$DISPLAY
  890. Environment=XAUTHORITY=$XAUTHORITY
  891. ExecStart=/usr/bin/mediacenter$MVERSION $*
  892. Restart=always
  893. RestartSec=10
  894. KillSignal=SIGHUP
  895. TimeoutStopSec=30
  896. [Install]
  897. WantedBy=graphical.target
  898. EOF"
  899. systemctl_reload_cmd &&
  900. systemctl_enable_cmd "$SERVICE_NAME" &&
  901. openFirewall "jriver"
  902. }
  903. #######################################
  904. # Starts and enables (at startup) a JRiver Media Server service
  905. #######################################
  906. service_jriver-mediaserver() {
  907. debug "Running: ${FUNCNAME[0]}"
  908. setServiceVars "${FUNCNAME[0]##*_}"
  909. service_jriver-mediacenter "/MediaServer"
  910. }
  911. #######################################
  912. # Starts and enables (at startup) JRiver Media Center in a new Xvnc session
  913. #######################################
  914. service_jriver-xvnc() {
  915. debug "Running: ${FUNCNAME[0]}"
  916. setServiceVars "${FUNCNAME[0]##*_}"
  917. setDisplay
  918. declare start_cmd
  919. declare -g PORT=$(( NEXT_DISPLAYNUM + 5900 ))
  920. installPackage tigervnc-server
  921. setVNCPass
  922. if (( NOVNCAUTH )); then
  923. start_cmd="/usr/bin/vncserver $NEXT_DISPLAY -geometry 1440x900 -alwaysshared -name jriver$NEXT_DISPLAY -SecurityTypes None -autokill -xstartup /usr/bin/mediacenter$MVERSION"
  924. else
  925. start_cmd="/usr/bin/vncserver $NEXT_DISPLAY -geometry 1440x900 -alwaysshared -rfbauth $HOME/.vnc/jrmc_passwd -autokill -xstartup /usr/bin/mediacenter$MVERSION"
  926. fi
  927. sudo bash -c "cat <<- EOF > $SERVICE_FNAME
  928. [Unit]
  929. Description=Remote desktop service (VNC)
  930. After=multi-user.target
  931. [Service]
  932. Type=simple
  933. $USER_STRING
  934. ExecStartPre=/bin/sh -c '/usr/bin/vncserver -kill $NEXT_DISPLAY &>/dev/null || :'
  935. ExecStart=$start_cmd
  936. ExecStop=/usr/bin/vncserver -kill $NEXT_DISPLAY
  937. Restart=always
  938. [Install]
  939. WantedBy=multi-user.target
  940. EOF"
  941. debug "DONE"
  942. systemctl_reload_cmd &&
  943. systemctl_enable_cmd "$SERVICE_NAME" &&
  944. echo "Xvnc running on localhost:$PORT" &&
  945. openFirewall "jriver-xvnc" &&
  946. openFirewall "jriver"
  947. }
  948. #######################################
  949. # Starts and enables (at startup) x11vnc screen sharing for the local desktop
  950. #######################################
  951. service_jriver-x11vnc() {
  952. debug "Running: ${FUNCNAME[0]}"
  953. setServiceVars "${FUNCNAME[0]##*_}"
  954. setDisplay
  955. declare start_cmd
  956. declare -g PORT=$(( DISPLAYNUM + 5900 ))
  957. installPackage x11vnc
  958. setX11VNCPass
  959. # Get current desktop resolution
  960. # TODO: may need to break this out into its own function and get smarter at identifying multi-monitors
  961. # _getResolution() {
  962. # debug "Running: ${FUNCNAME[0]}"
  963. # installPackage xorg-x11-utils
  964. # _res=$(xdpyinfo | grep dimensions | awk '{print $2}')
  965. # }
  966. # _getResolution
  967. if (( NOVNCAUTH )); then
  968. start_cmd="/usr/bin/x11vnc -display $DISPLAY -noscr -auth guess -forever -bg -nopw"
  969. else
  970. start_cmd="/usr/bin/x11vnc -display $DISPLAY -noscr -auth guess -forever -bg -rfbauth $HOME/.vnc/jrmc_passwd"
  971. fi
  972. sudo bash -c "cat <<-EOF > $SERVICE_FNAME
  973. [Unit]
  974. Description=x11vnc
  975. After=graphical.target
  976. [Service]
  977. $USER_STRING
  978. Type=forking
  979. Environment=DISPLAY=$DISPLAY
  980. ExecStart=$start_cmd
  981. Restart=always
  982. RestartSec=10
  983. [Install]
  984. WantedBy=graphical.target
  985. EOF"
  986. systemctl_reload_cmd &&
  987. systemctl_enable_cmd "$SERVICE_NAME" &&
  988. echo "x11vnc running on localhost:$PORT" &&
  989. openFirewall "jriver-x11vnc"
  990. }
  991. #######################################
  992. # Starts and enables (at startup) an hourly service to build the latest version of JRiver Media
  993. # Center RPM from the source DEB and create/update an RPM repository
  994. #######################################
  995. service_jriver-createrepo() {
  996. debug "Running: ${FUNCNAME[0]}"
  997. declare id="${TARGET:-$ID}"
  998. declare cr_user="${CREATEREPO_USER:$USER}"
  999. if [[ "$USER" != "$cr_user" ]]; then
  1000. USER="root" SERVICE_TYPE="system" setServiceVars "${FUNCNAME[0]##*_}"
  1001. else
  1002. setServiceVars "${FUNCNAME[0]##*_}"
  1003. fi
  1004. sudo bash -c "cat <<-EOF > $SERVICE_FNAME
  1005. [Unit]
  1006. Description=Builds JRiver Media Center RPM file, moves it to the repo dir, and runs createrepo
  1007. [Service]
  1008. $USER_STRING
  1009. ExecStart=$PWD/installJRMC --target $id --outputdir $OUTPUTDIR --createrepo --createrepo-webroot $CREATEREPO_WEBROOT --createrepo-user $cr_user
  1010. [Install]
  1011. WantedBy=multi-user.target
  1012. EOF"
  1013. sudo bash -c "cat <<-EOF > $TIMER_FNAME
  1014. [Unit]
  1015. Description=Run JRiver MC rpmbuild hourly
  1016. [Timer]
  1017. OnCalendar=hourly
  1018. Persistent=true
  1019. [Install]
  1020. WantedBy=timers.target
  1021. EOF"
  1022. systemctl_reload_cmd &&
  1023. systemctl_enable_cmd "$TIMER_NAME"
  1024. }
  1025. #######################################
  1026. # CONTAINERS
  1027. #######################################
  1028. # container_jriver-createrepo() {
  1029. # :
  1030. # }
  1031. # container_jriver-xvnc() {
  1032. # :
  1033. # }
  1034. # container_jriver-mediacenter() {
  1035. # installPackage buildah podman
  1036. # # Eventually try to switch to Debian
  1037. # # if ! CNT=$(buildah from debian:$BASE); then
  1038. # # echo "Bad base image for container $CNAME, skipping"
  1039. # # continue
  1040. # # fi
  1041. # if ! CNT=$(buildah from jlesage/baseimage-gui:debian-10-v3.5.7); then
  1042. # echo "Bad base image for container $CNAME, skipping"
  1043. # continue
  1044. # fi
  1045. # buildah run "$CNT" add-pkg gnupg2 libxss1 wmctrl xdotool ca-certificates inotify-tools libgbm1 ffmpeg
  1046. # # #BASEIMAGE=jlesage/baseimage-gui:debian-10-v3.5.7
  1047. # # JRIVER_RELEASE=28
  1048. # # JRIVER_TAG=stable
  1049. # # ARCH=amd64
  1050. # # REBUILD_MIN=22
  1051. # # REBUILD_MAX=120
  1052. # # # JRiver Version tag (latest, stable or beta)
  1053. # # ARG jriver_tag
  1054. # # # JRiver Release Version (25, 26 etc.)
  1055. # # ARG jriver_release
  1056. # # # Image Version of the build
  1057. # # ARG image_version
  1058. # # # .deb download URL, if set to "repository" the JRiver repository will be used
  1059. # # ARG deb_url
  1060. # # RUN add-pkg gnupg2 libxss1 wmctrl xdotool ca-certificates inotify-tools libgbm1 ffmpeg
  1061. # # Install JRiver
  1062. # RUN \
  1063. # add-pkg --virtual build-dependencies wget &&
  1064. # # Install from Repository
  1065. # if [ "${deb_url}" = "repository" ]; then \
  1066. # echo "Installing JRiver from repository ${jriver_release}:${jriver_tag}" &&
  1067. # wget -q "http://dist.jriver.com/mediacenter@jriver.com.gpg.key" -O- | apt-key add - &&
  1068. # wget http://dist.jriver.com/${jriver_tag}/mediacenter/mediacenter${jriver_release}.list -O /etc/apt/sources.list.d/mediacenter${jriver_release}.list &&
  1069. # apt-get update &&
  1070. # add-pkg mediacenter${jriver_release}; \
  1071. # # Install from .deb URL
  1072. # else \
  1073. # echo "Installing JRiver from URL: ${deb_url}" &&
  1074. # wget -q -O "jrivermc.deb" ${deb_url} &&
  1075. # add-pkg "./jrivermc.deb"; \
  1076. # fi &&
  1077. # # Cleanup
  1078. # del-pkg build-dependencies &&
  1079. # rm -rf /tmp/* /tmp/.[!.]*
  1080. # # Add rootfs
  1081. # COPY rootfs/ /
  1082. # VOLUME ["/config"]
  1083. # # Application Icon
  1084. # RUN \
  1085. # APP_ICON_URL=https://gitlab.com/shiomax/jrivermc-docker/raw/master/assets/Application.png &&
  1086. # install_app_icon.sh "$APP_ICON_URL"
  1087. # # Various configuration vars
  1088. # ENV KEEP_APP_RUNNING=1 \
  1089. # DISPLAY_WIDTH=1280 \
  1090. # DISPLAY_HEIGHT=768 \
  1091. # APP_NAME="JRiver MediaCenter ${jriver_release}" \
  1092. # MAXIMIZE_POPUPS=0 \
  1093. # S6_KILL_GRACETIME=8000
  1094. # # Modify startapp.sh and rc.xml with JRiver version
  1095. # RUN sed-patch s/%%MC_VERSION%%/${jriver_release}/g \
  1096. # /startapp.sh &&
  1097. # sed-patch s/%%MC_VERSION%%/${jriver_release}/g \
  1098. # /etc/xdg/openbox/rc.xml
  1099. # EXPOSE 5800 5900 52100 52101 52199 1900/udp
  1100. # # Metadata.
  1101. # LABEL \
  1102. # org.label-schema.name="jrivermc${jriver_release}" \
  1103. # org.label-schema.description="Docker image for JRiver Media Center ${jriver_release}" \
  1104. # org.label-schema.version="${image_version}" \
  1105. # org.label-schema.vcs-url="https://gitlab.com/shiomax/jrivermc-docker" \
  1106. # org.label-schema.schema-version="1.0"
  1107. # installPackage buildah podman
  1108. # cnt=$(buildah from docker.io/jlesage/baseimage-gui:debian-10)
  1109. # podman_create_cmd=(podman create --name "$CNAME")
  1110. # buildah_config_cmd=(buildah config \
  1111. # --author bryanroessler@gmail.com \
  1112. # --label maintainer="$MAINTAINER" \
  1113. # --env TZ="$TZ" \
  1114. # --workingdir /app \
  1115. # --cmd mediacenter"$MVERSION")
  1116. # mkcdirs() {
  1117. # declare dir
  1118. # for dir in "$@"; do
  1119. # if [[ ! -d "$dir" ]]; then
  1120. # if ! mkdir -p "$dir"; then
  1121. # err "Could not create directory $dir, check your permissions"
  1122. # fi
  1123. # fi
  1124. # if ! chcon -t container_file_t -R "$dir"; then
  1125. # err "Could not set container_file_t attribute for $dir, check your permissions"
  1126. # fi
  1127. # done
  1128. # }
  1129. # mkcdirs "$HOME/.jriver"
  1130. # podman_create_cmd+=(-v "$HOME/.jriver:/root/.jriver")
  1131. # podman_create_cmd+=(-v "$DOWNLOAD_ROOT:/downloads:z")
  1132. # podman_create_cmd+=(-v "$MONITOR_ROOT/nzbs:/nzbs")
  1133. # podman_create_cmd+=(-p "${CONTAINER[HOST_PORT]}:${CONTAINER[CONTAINER_PORT]}")
  1134. # brc() { buildah run "$1" "${@:2}" || return 1; }
  1135. # brc add-pkg gnupg2 libxss1 wmctrl xdotool ca-certificates inotify-tools libgbm1
  1136. # brc add-pkg --virtual .build-deps wget
  1137. # brc sh -s <<- EOF
  1138. # wget -q "http://dist.jriver.com/mediacenter@jriver.com.gpg.key" -O- | apt-key add - &>/dev/null
  1139. # EOF
  1140. # brc wget "http://dist.jriver.com/latest/mediacenter/mediacenter$MVERSION.list" -O "/etc/apt/sources.list.d/mediacenter$MVERSION.list"
  1141. # brc apt-get update -y -q0
  1142. # brc add-pkg "mediacenter$MVERSION"
  1143. # brc del-pkg .build-deps
  1144. # }
  1145. uninstall() {
  1146. debug "Running: ${FUNCNAME[0]}"
  1147. declare service unit f
  1148. if ! askOk "Do you really want to uninstall JRiver Media Center"; then
  1149. echo "Uninstall canceled"
  1150. exit 0
  1151. fi
  1152. echo "Stopping and removing all Media Center services"
  1153. for service in $(compgen -A "function" "service"); do
  1154. service="${service##service_}"
  1155. SERVICE_TYPE=system setServiceVars "$service";
  1156. for unit in "$SERVICE_NAME" "$TIMER_NAME"; do
  1157. if systemctl_is_active_cmd "$unit" &>/dev/null ||
  1158. systemctl_is_enabled_cmd "$unit" &>/dev/null; then
  1159. debug "Disabling $unit"
  1160. systemctl_disable_cmd "$unit"
  1161. fi
  1162. done
  1163. for f in "$SERVICE_FNAME" "$TIMER_FNAME"; do
  1164. [[ -f "$f" ]] && debug "Removing $f" && sudo rm -f "$f"
  1165. done
  1166. SERVICE_TYPE=user setServiceVars "$service";
  1167. for unit in "$SERVICE_NAME" "$TIMER_NAME"; do
  1168. if systemctl_is_active_cmd "$unit" &>/dev/null ||
  1169. systemctl_is_enabled_cmd "$unit" &>/dev/null; then
  1170. debug "Disabling $unit"
  1171. systemctl_disable_cmd "$unit"
  1172. fi
  1173. done
  1174. for f in "$SERVICE_FNAME" "$TIMER_FNAME"; do
  1175. [[ -f "$f" ]] && debug "Removing $f" && sudo rm -f "$f"
  1176. done
  1177. systemctl_reload_cmd
  1178. done
  1179. echo "Removing repo files"
  1180. sudo rm -rf \
  1181. "/etc/yum.repos.d/jriver.repo" \
  1182. /etc/apt/sources.list.d/{jriver,mediacenter}*.list # also remove legacy repo files
  1183. if [[ "$ID" == "suse" ]]; then
  1184. sudo zypper rr jriver &>/dev/null
  1185. fi
  1186. echo "Removing firewall rules"
  1187. if hash firewall-cmd 2>/dev/null; then
  1188. if [[ -v debug ]]; then
  1189. debug "firewall_cmd --permanent --remove-service=jriver"
  1190. firewall_cmd --permanent --remove-service=jriver
  1191. debug "firewall_cmd --permanent --delete-service=jriver"
  1192. firewall_cmd --permanent --delete-service=jriver
  1193. debug "firewall_cmd --reload"
  1194. firewall_cmd --reload
  1195. else
  1196. firewall_cmd --permanent --remove-service=jriver &>/dev/null
  1197. firewall_cmd --permanent --delete-service=jriver &>/dev/null
  1198. firewall_cmd --reload &>/dev/null
  1199. fi
  1200. elif hash ufw 2>/dev/null; then
  1201. firewall_cmd="firewall_cmd delete allow jriver"
  1202. debug "$firewall_cmd" || firewall_cmd+=" &>/dev/null"
  1203. eval "$firewall_cmd"
  1204. [[ -f "/etc/ufw/applications.d/jriver" ]] &&
  1205. sudo rm -f /etc/ufw/applications.d/jriver
  1206. fi
  1207. echo "Uninstalling Media Center package"
  1208. mc_pkg_rm_cmd="pkg_remove $MCPKG"
  1209. debug "$mc_pkg_rm_cmd" || mc_pkg_rm_cmd+=" &>/dev/null"
  1210. if eval "$mc_pkg_rm_cmd"; then
  1211. echo "JRiver Media Center has been completely uninstalled"
  1212. echo "To remove your library files, run: rm -rf $HOME/.jriver"
  1213. echo "To remove your rpmbuild output files, run: rm -rf $OUTPUTDIR"
  1214. exit 0
  1215. else
  1216. exit $?
  1217. fi
  1218. }
  1219. tests() {
  1220. # To test on Mint: sudo apt-get install -y spice-vdagent ca-certificates git; export GIT_SSL_NO_VERIFY=1
  1221. exit $?
  1222. }
  1223. main() {
  1224. debug "Running: ${FUNCNAME[0]}"
  1225. declare -g VERSION_SOURCE MCVERSION MVERSION MCPKG
  1226. getOS
  1227. # Some distros need external repos installed for MC libraries
  1228. if [[ "$ID" =~ (ubuntu) ]]; then
  1229. echo "Adding universe repository"
  1230. if ! grep ^deb /etc/apt/sources.list|grep -q universe; then
  1231. sudo add-apt-repository universe
  1232. fi
  1233. elif [[ "$ID" == "centos" ]]; then
  1234. echo "Adding EPEL repository"
  1235. installPackage epel-release
  1236. fi
  1237. # Distro-specific commands
  1238. if [[ "$ID" =~ ^(fedora|centos)$ ]]; then
  1239. pkg_install(){ sudo dnf install -y "$@"; }
  1240. pkg_remove(){ sudo dnf remove -y "$@"; }
  1241. pkg_update(){ sudo dnf makecache; }
  1242. pkg_query(){ rpm -q "$@"; }
  1243. firewall_cmd(){ sudo firewall-cmd "$@"; }
  1244. elif [[ "$ID" =~ ^(debian|ubuntu)$ ]]; then
  1245. pkg_install(){ sudo apt-get install -y -q0 "$@"; }
  1246. pkg_remove(){ sudo apt-get remove --auto-remove -y -q0 "$@"; }
  1247. pkg_update(){ sudo apt-get update -y -q0; }
  1248. pkg_query(){ dpkg -s "$@"; }
  1249. firewall_cmd(){ sudo ufw "$@"; }
  1250. elif [[ "$ID" == "suse" ]]; then
  1251. pkg_install(){ sudo zypper --non-interactive -q install --force --no-confirm "$@"; }
  1252. pkg_remove(){ sudo zypper --non-interactive -q remove --clean-deps "$@"; }
  1253. pkg_update(){ sudo zypper --non-interactive -q refresh jriver; }
  1254. pkg_query(){ rpm -q "$@"; }
  1255. firewall_cmd(){ sudo firewall-cmd "$@"; }
  1256. fi
  1257. parseInput "$@"
  1258. # Select MC version to work with
  1259. if [[ -v MCVERSION ]]; then
  1260. VERSION_SOURCE="user input"
  1261. else
  1262. getLatestVersion
  1263. fi
  1264. [[ ! "$MCVERSION" =~ ([0-9]+.[0-9]+.[0-9]+) ]] && err "Invalid version number" && exit 1
  1265. echo "Using MC version $MCVERSION determined by $VERSION_SOURCE"
  1266. [[ "$VERSION_SOURCE" != "user input" ]] && echo "To override, use --mcversion"
  1267. # Extract major version number
  1268. MVERSION="${MCVERSION%%.*}"
  1269. # Set target package name
  1270. if [[ "$ID" =~ ^(fedora|centos|suse)$ ]]; then
  1271. MCPKG="MediaCenter"
  1272. [[ "$VERSION_SOURCE" == "user input" ]] && MCPKG="$MCPKG-$MCVERSION"
  1273. elif [[ "$ID" =~ ^(debian|ubuntu)$ ]]; then
  1274. MCPKG="mediacenter$MVERSION"
  1275. [[ "$VERSION_SOURCE" == "user input" ]] && MCPKG="$MCPKG=$MCVERSION"
  1276. fi
  1277. declare -g MCRPM="$OUTPUTDIR/RPMS/x86_64/MediaCenter-$MCVERSION.x86_64.rpm"
  1278. if (( UNINSTALL_SWITCH )); then
  1279. uninstall
  1280. exit $?
  1281. fi
  1282. if (( REPO_INSTALL_SWITCH )); then
  1283. if [[ "$ID" == "suse" ]]; then
  1284. echo "A SUSE repository is not yet available"
  1285. echo "Use --install rpm to build and install a SUSE RPM instead"
  1286. exit 1
  1287. elif installMCFromRepo; then
  1288. echo "JRiver Media Center installed successfully from repo"
  1289. symlinkCerts
  1290. restoreLicense
  1291. openFirewall "jriver"
  1292. else
  1293. err "JRiver Media Center installation from repo failed"
  1294. exit 1
  1295. fi
  1296. fi
  1297. if (( BUILD_SWITCH )); then
  1298. installPackage "wget" "dpkg" "rpm-build"
  1299. acquireDeb
  1300. TARGET="${TARGET:-$ID}"
  1301. if [[ "$TARGET" =~ ^(fedora|centos|suse) ]]; then
  1302. buildRPM
  1303. fi
  1304. fi
  1305. if (( DEB_INSTALL_SWITCH )); then
  1306. if installMCDEB; then
  1307. echo "JRiver Media Center installed successfully from local deb"
  1308. else
  1309. err "JRiver Media Center installation from local deb failed"
  1310. exit 1
  1311. fi
  1312. symlinkCerts
  1313. restoreLicense
  1314. openFirewall "jriver"
  1315. fi
  1316. if (( RPM_INSTALL_SWITCH )); then
  1317. #rpm --upgrade "$MCRPM" # TODO, maybe universalize for RPM distros
  1318. if installPackage --skip-check-installed --nogpgcheck "$MCRPM"; then
  1319. echo "JRiver Media Center installed successfully from local RPM"
  1320. else
  1321. err "JRiver Media Center installation from local RPM failed"
  1322. exit 1
  1323. fi
  1324. symlinkCerts
  1325. restoreLicense
  1326. openFirewall "jriver"
  1327. fi
  1328. if (( CREATEREPO_SWITCH )); then
  1329. runCreaterepo
  1330. exit $?
  1331. fi
  1332. if [[ "${#SERVICES[@]}" -gt 0 ]]; then
  1333. declare service
  1334. for service in "${SERVICES[@]}"; do
  1335. if ! "service_$service"; then
  1336. if [[ $? -eq 127 ]]; then
  1337. err "Service $service does not exist, check your service name"
  1338. else
  1339. err "Failed to create service: $service"
  1340. fi
  1341. fi
  1342. done
  1343. fi
  1344. # for _container in "${CONTAINERS[@]}"; do
  1345. # if ! "_container_$_container"; then
  1346. # if [[ $? -eq 127 ]]; then
  1347. # err "Container $_container does not exist, check your container name"
  1348. # else
  1349. # err "Failed to create container: $_container"
  1350. # fi
  1351. # fi
  1352. # done
  1353. }
  1354. main "$@"