diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index e6dfcbb64..97fa9dff6 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,15 +1,15 @@
repos:
- repo: https://github.com/maxwinterstein/shfmt-py
- rev: v3.4.3.1
+ rev: v3.7.0.1
hooks:
- id: shfmt
args: ["-w", "-ci", "-sr", "-i", "4"]
- repo: https://github.com/shellcheck-py/shellcheck-py
- rev: v0.9.0.5
+ rev: v0.9.0.6
hooks:
- id: shellcheck
args: ["--severity=error"]
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.4.0 # Use the ref you want to point at
+ rev: v4.5.0 # Use the ref you want to point at
hooks:
- id: check-executables-have-shebangs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1887f400b..d8470d869 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,105 @@
# Changelog
+## [3.12.0]
+
+## June 22, 2024
+
+### New:
+- Ubuntu Noble support
+
+### Fixed:
+- Libtorrent will use boost 1.85 on bookworm and newer distros
+- Libtorrent version string grep
+- Install rsyslog explicitly for fail2ban
+- qbittorrent: add qt6-base-private-dev depedency
+
+## [3.11.1]
+
+## March 12, 2024
+
+### SECURITY:
+ - Pyload has been removed from installation due to a Remote Code Execution vulnerability (CVE-2023-0297). Existing users will be encouraged to uninstall the software with every box update. This is a major issue, please remove. You've been warned!
+
+### Fixed:
+ - curl: scripts may use the wrong path (/usr/bin/curl) if curl has been previously primed during execution of the scripts and which caches its path. Clear the hash table for curl after we compile it ourselves to prevent odd errors.
+
+## [3.11.0]
+
+## Feb 17, 2024
+
+### New:
+- Sonarr v4 support :tada:
+
+### Changed:
+- nginx: stop version emission
+- boost: more robust mirror fallback mechanisms
+- curl: upgrade to 8.4
+- box: package descriptions have been updated
+- node: bump to 20.x LTS
+
+### Fixed:
+- rutorrent: country flags
+- autobrr: issue with package selection during install
+- navidrome: fails to download on arm64
+- netdata: install/remove url
+- nzbhydra: java variable resolution
+- nzbhydra: use python wrapper for launching
+- nzbhydra: upgrader issues
+- rtorrent: build flag issues
+- rtorrent: remove piece boundary fix
+- rtorrent: pin xmlrpc to rev 3212
+- fpm: fix dotenv dependency issue in focal/buster
+- nginx: fancyindex installation (note, it should fix existing installs if you haven't touched anything)
+
+
+## [3.10.0]
+
+## November 6, 2023
+
+## SECURITY
+
+> [!WARNING]
+> All btsync/rslsync users are encouraged to check their installations to ensure they have a Web UI password set. You can do so from the Settings > Web UI. This issue should be resolved moving forward. New installations should once more prompt username/password generation on first setup.
+
+- btsync/rslsync: we were made aware that new installs of resilio haven't been prompting users to create passwords. To be clear, this is a regression, as previous behavior prompted the user to create a password on first setup. It was identified the the "Skip EULA" config option was causing this behavior and has been removed. An update script will run to remove this option from existing configs, but it may not trigger password creation.
+
+### Changed:
+- rtorrent: stickz commited a bunch of performance related patches. Enjoy!
+- qbittorrent: builds for 4.6 have been enabled but not thoroughly tested. Feel free to report any issues
+
+### Fixed
+- qbittorrent: overzealous grep will continue to warn you of "misconfigurations" despite having the desired bind config set.
+- npm: swapped from script to repo method of initializing npm and nodejs
+- calibre-web: don't set proxy_bind (fixes issue with ipv6)
+
+## [3.9.2]
+
+## September 16, 2023
+
+### Meta/Development:
+- Update pre-commit.ci integrations
+- Update contributing.md
+- Remove feathub link from issue template
+
+### Changed:
+- nginx: dhparam generation will now happen asyncronously
+- tautulli: now uses a venv, updated buster to use pyenv
+- rtorrent: xmlrpc will now track super-stable
+- rtorrent: added PGO build option
+
+### Fixed:
+- curl: regression with gcc12 on jammy
+- curl: fix potential unzip issue
+- qbit: expand qt6 deps (packages were split)
+- qbit: fix deps for focal
+- qbit: don't bind to `*` if nginx is installed. Warn existing users of this (mis)config
+- arrs: allow access for /feed/calendar via nginx
+- nginx: maintained update code
+- nginx: fix package errors during remove
+- pyload: fix pycurl install
+- rtorrent: various fixes
+- jfago: will no longer run as root
+
## [3.9.1]
## July 16, 2023
diff --git a/README.md b/README.md
index 55baed7bf..ff474f653 100644
--- a/README.md
+++ b/README.md
@@ -2,14 +2,14 @@
[](https://www.codefactor.io/repository/github/liaralabs/swizzin) [](https://discord.gg/sKjs9UM)   
-# 3.9.1 Stable
+# 3.12.0 Stable
[website](https://swizzin.ltd) \| [docs](https://swizzin.ltd/getting-started) \| [discord](https://discord.gg/bDFqAUF)
Please use [Discord](https://discord.gg/bDFqAUF) for all community functions, and [GitHub discussions](https://github.com/swizzin/swizzin/discussions) for feature requests and to raise issues.
## What is swizzin?
-Swizzin is a light, modular seedbox solution that can be installed on Debian 10/11/12 or Ubuntu 20.04/22.04. The QuickBox package repo has been ported over for your installing pleasure, including the panel -- if you so choose!
+Swizzin is a light, modular seedbox solution that can be installed on Debian 10/11/12 or Ubuntu 20.04/22.04/24.04. The QuickBox package repo has been ported over for your installing pleasure, including the panel -- if you so choose!
Box has been revamped to reduce and consolidate the amount of commands you need to remember to manage your seedbox. More on this below. In addition to that, additional add-on packages can be installed during installation. No need to wait until the installer finishes! Now with unattended installs!
@@ -71,7 +71,7 @@ bash <(curl -sL git.io/swizzin) --env /path/to/your/env/file/here.env
Long-term support branches only:
- Debian 10/11/12
-- Ubuntu 20.04/22.04
+- Ubuntu 20.04/22.04/24.04
## Support and Help
diff --git a/scripts/box b/scripts/box
index 79a884bc2..2ac6c74b6 100755
--- a/scripts/box
+++ b/scripts/box
@@ -138,7 +138,7 @@ function _update() {
#Checking for EOL releases
case "$(_os_codename)" in
- "focal" | "buster" | "bullseye" | "jammy" | "bookworm")
+ "focal" | "buster" | "bullseye" | "jammy" | "bookworm" | "noble")
echo_log_only "OS supported"
;;
*)
diff --git a/scripts/install/btsync.sh b/scripts/install/btsync.sh
index 9924d8518..ce76104e9 100755
--- a/scripts/install/btsync.sh
+++ b/scripts/install/btsync.sh
@@ -42,7 +42,6 @@ function _installBTSync5() {
"listening_port" : 0,
"storage_path" : "/home/${MASTER}/.config/resilio-sync/",
"pid_file" : "/var/run/resilio-sync/sync.pid",
- "agree_to_EULA": "yes",
"webui" :
{
diff --git a/scripts/install/jfago.sh b/scripts/install/jfago.sh
index ea9d0f77e..279da5064 100755
--- a/scripts/install/jfago.sh
+++ b/scripts/install/jfago.sh
@@ -23,19 +23,26 @@ else
echo_info "jfago will run on port 8056"
fi
+# Create jfago user
+useradd -r jfago -s /usr/sbin/nologin > /dev/null 2>&1
+
# Create systemd service
echo_progress_start "Setting up systemd service"
jfagobinary=$(which jfa-go)
-cat > "/etc/systemd/system/jfago.service" << ADC
+mkdir -p /opt/jfago/config/
+chown jfago: /opt/jfago -R
+
+cat > /etc/systemd/system/jfago.service << EOF
[Unit]
Description=An account management system for Jellyfin.
-
+After=network.target
[Service]
-ExecStart=$jfagobinary -config /root/.config/jfa-go/config.ini -data /root/.config/jfa-go/
+ExecStart=${jfagobinary} -config /opt/jfago/config/config.ini -data /opt/jfago/config/
+User=jfago
[Install]
WantedBy=multi-user.target
-ADC
+EOF
systemctl daemon-reload -q
echo_progress_done "Service installed"
@@ -45,10 +52,10 @@ echo_progress_start "Enabling and starting jfago to create config file"
systemctl -q enable jfago --now
echo_progress_done
-crudini --set /root/.config/jfa-go/config.ini ui url_base /jfa-go
+crudini --set /opt/jfago/config/config.ini ui url_base /jfa-go
# This file is created after installation to prevent reinstalling. You will need to remove the app first which deletes this file.
touch /install/.jfago.lock
echo_success "jfago installed but not configured"
-echo_info "Edit /root/.config/jfa-go/config.ini to configure and then restart the service with systemctl restart jfago"
+echo_info "Edit /opt/jfago/config/config.ini to configure and then restart the service with systemctl restart jfago"
exit
diff --git a/scripts/install/netdata.sh b/scripts/install/netdata.sh
index b02ceb6be..28abd56de 100755
--- a/scripts/install/netdata.sh
+++ b/scripts/install/netdata.sh
@@ -3,7 +3,7 @@
# Author: liara
echo_progress_start "Running netdata install script"
-bash <(curl -Ss https://my-netdata.io/kickstart.sh) --non-interactive >> $log 2>&1
+bash <(curl -Ss https://get.netdata.cloud/kickstart.sh) --non-interactive >> $log 2>&1
echo_progress_done
if [[ -f /install/.nginx.lock ]]; then
diff --git a/scripts/install/nginx.sh b/scripts/install/nginx.sh
index 01f312aba..6eb837ea8 100755
--- a/scripts/install/nginx.sh
+++ b/scripts/install/nginx.sh
@@ -47,11 +47,35 @@ case $codename in
;;
esac
-APT="nginx libnginx-mod-http-fancyindex subversion ssl-cert php-fpm libfcgi0ldbl php-cli php-dev php-xml php-curl php-xmlrpc php-json php-mbstring php-opcache php-zip ${geoip} ${mcrypt}"
+# Prepare the /etc/nginx/ssl/ for openssl dhparm generation
+mkdir -p /etc/nginx/ssl/
+chmod 700 /etc/nginx/ssl
+cd /etc/nginx/ssl
+
+# Create temp.log for openssl dhparm generation to prevent a race condition with logging
+. /etc/swizzin/sources/functions/utils
+templog="/root/logs/temp.log"
+rm_if_exists $templog
+touch $templog
+# Start openssl dhparam as a background task using temp.log
+openssl dhparam -out dhparam.pem 2048 >> $templog 2>&1 &
+
+# Install packages for nginx in the foreground
+APT="nginx libnginx-mod-http-fancyindex subversion ssl-cert php-fpm libfcgi0ldbl php-cli php-dev php-xml php-curl php-xmlrpc php-json php-mbstring php-opcache php-zip ${geoip} ${mcrypt}"
apt_install $APT
-mkdir -p /srv
+# Wait for the background task of openssl dhparm generation to finish
+wait
+
+# Append the results of temp.log to swizzin.log and remove temp.log
+echo_log_only "Begin of OpenSSL dhparm results"
+cat $templog >> $log 2>&1
+echo_log_only "End of OpenSSL dhparm results"
+rm_if_exists $templog
+
+# Began configuring nginx in the foreground
+mkdir -p /srv
cd /etc/php
phpv=$(ls -d */ | cut -d/ -f1)
echo_progress_start "Making adjustments to PHP"
@@ -88,6 +112,7 @@ server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
+ server_tokens off;
location /.well-known {
alias /srv/.well-known;
@@ -121,15 +146,9 @@ server {
}
NGC
-mkdir -p /etc/nginx/ssl/
mkdir -p /etc/nginx/snippets/
mkdir -p /etc/nginx/apps/
-chmod 700 /etc/nginx/ssl
-
-cd /etc/nginx/ssl
-openssl dhparam -out dhparam.pem 2048 >> $log 2>&1
-
cat > /etc/nginx/snippets/ssl-params.conf << SSC
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
@@ -179,7 +198,10 @@ PROX
echo_progress_done "Config installed"
echo_progress_start "Installing fancyindex"
-svn export https://github.com/Naereen/Nginx-Fancyindex-Theme/trunk/Nginx-Fancyindex-Theme-dark /srv/fancyindex >> $log 2>&1
+git clone https://github.com/Naereen/Nginx-Fancyindex-Theme/ /tmp/fancyindex >> $log 2>&1
+mv /tmp/fancyindex/Nginx-Fancyindex-Theme-dark /srv/fancyindex >> $log 2>&1
+rm -rf /tmp/fancyindex
+
cat > /etc/nginx/snippets/fancyindex.conf << FIC
fancyindex on;
fancyindex_localtime on;
diff --git a/scripts/install/nzbhydra.sh b/scripts/install/nzbhydra.sh
index 8b9f7f66b..283ab4dc4 100755
--- a/scripts/install/nzbhydra.sh
+++ b/scripts/install/nzbhydra.sh
@@ -20,7 +20,7 @@ fi
username=$(_get_master_username)
-case $(os_codename) in
+case $(_os_codename) in
bullseye)
java=openjdk-17-jdk-headless
;;
@@ -28,7 +28,7 @@ case $(os_codename) in
java=default-jre-headless
;;
esac
-LIST='unzip $java'
+LIST="unzip $java"
apt_install $LIST
echo_progress_start "Installing NZBHydra ${latestversion}"
@@ -41,7 +41,7 @@ wget -O nzbhydra2.zip ${latest} >> ${log} 2>&1
unzip nzbhydra2.zip >> ${log} 2>&1
rm -f nzbhydra2.zip
-chmod +x nzbhydra2
+chmod +x nzbhydra2 nzbhydra2wrapperPy3.py
chown -R ${username}: /opt/nzbhydra2
echo_progress_done
@@ -73,7 +73,7 @@ WorkingDirectory=/opt/nzbhydra2
# NZBHydra stores its data in a "data" subfolder of its installation path
# To change that set the --datafolder parameter:
# --datafolder /path-to/datafolder
-ExecStart=/opt/nzbhydra2/nzbhydra2 --nobrowser --datafolder /home/${username}/.config/nzbhydra2 --nopidfile
+ExecStart=/opt/nzbhydra2/nzbhydra2wrapperPy3.py --nobrowser --datafolder /home/${username}/.config/nzbhydra2 --nopidfile
Restart=always
diff --git a/scripts/install/pyload.sh b/scripts/install/pyload.sh
deleted file mode 100755
index 96f8533a6..000000000
--- a/scripts/install/pyload.sh
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/bin/bash
-#
-# [swizzin :: Install pyLoad package]
-#
-# Swizzin by liara
-#
-# swizzin Copyright (C) 2020 swizzin.ltd
-# Licensed under GNU General Public License v3.0 GPL-3 (in short)
-#
-# You may copy, distribute and modify the software as long as you track
-# changes/dates in source files. Any modifications to our software
-# including (via compiler) GPL-licensed code must also be made available
-# under the GPL along with build & install instructions.
-#
-codename=$(lsb_release -cs)
-user=$(cut -d: -f1 < /root/.master.info)
-password=$(cut -d: -f2 < /root/.master.info)
-SALT=$(shuf -zr -n5 -i 0-9 | tr -d '\0')
-SALTWORD=${SALT}${password}
-SALTWORDHASH=$(echo -n ${SALTWORD} | shasum -a 1 | awk '{print $1}')
-HASH=${SALT}${SALTWORDHASH}
-#shellcheck source=sources/functions/pyenv
-. /etc/swizzin/sources/functions/pyenv
-
-if [[ $codename = "buster" ]]; then
- LIST='tesseract-ocr gocr rhino python2.7-dev python-pip python-virtualenv virtualenv libcurl4-openssl-dev sqlite3'
-else
- LIST='tesseract-ocr gocr rhino libcurl4-openssl-dev python2.7-dev sqlite3'
-fi
-
-if [[ $(_os_arch) =~ "arm" ]]; then
- LIST+=' libffi-dev'
-fi
-
-apt_install $LIST
-
-if [[ ! $codename = "buster" ]]; then
- python_getpip
-fi
-
-python2_venv ${user} pyload
-
-echo_progress_start "Installing python dependencies"
-PIP='wheel setuptools<45 pycurl pycrypto tesseract pillow pyOpenSSL js2py feedparser beautifulsoup'
-/opt/.venv/pyload/bin/pip install $PIP >> "${log}" 2>&1
-chown -R ${user}: /opt/.venv/pyload
-echo_progress_done
-
-echo_progress_start "Cloning pyLoad"
-git clone --branch "stable" https://github.com/pyload/pyload.git /opt/pyload >> "${log}" 2>&1
-echo_progress_done
-
-echo_progress_start "Configuring pyLoad"
-echo "/opt/pyload" > /opt/pyload/module/config/configdir
-
-cat > /opt/pyload/pyload.conf << PYCONF
-version: 1
-
-download - "Download":
- int chunks : "Max connections for one download" = 3
- str interface : "Download interface to bind (ip or Name)" = None
- bool ipv6 : "Allow IPv6" = False
- bool limit_speed : "Limit Download Speed" = False
- int max_downloads : "Max Parallel Downloads" = 3
- int max_speed : "Max Download Speed in kb/s" = -1
- bool skip_existing : "Skip already existing files" = False
-
-downloadTime - "Download Time":
- time end : "End" = 0:00
- time start : "Start" = 0:00
-
-general - "General":
- bool checksum : "Use Checksum" = False
- bool debug_mode : "Debug Mode" = False
- folder download_folder : "Download Folder" = /home/${user}/Downloads
- bool folder_per_package : "Create folder for each package" = True
- en;de;fr;it;es;nl;sv;ru;pl;cs;sr;pt_BR language : "Language" = en
- int min_free_space : "Min Free Space (MB)" = 200
- int renice : "CPU Priority" = 0
-
-log - "Log":
- bool file_log : "File Log" = True
- int log_count : "Count" = 5
- folder log_folder : "Folder" = Logs
- bool log_rotate : "Log Rotate" = True
- int log_size : "Size in kb" = 100
-
-permission - "Permissions":
- bool change_dl : "Change Group and User of Downloads" = False
- bool change_file : "Change file mode of downloads" = False
- bool change_group : "Change group of running process" = False
- bool change_user : "Change user of running process" = False
- str file : "Filemode for Downloads" = 0644
- str folder : "Folder Permission mode" = 0755
- str group : "Groupname" = users
- str user : "Username" = user
-
-proxy - "Proxy":
- str address : "Address" = "localhost"
- password password : "Password" = None
- int port : "Port" = 7070
- bool proxy : "Use Proxy" = False
- http;socks4;socks5 type : "Protocol" = http
- str username : "Username" = None
-
-reconnect - "Reconnect":
- bool activated : "Use Reconnect" = False
- time endTime : "End" = 0:00
- str method : "Method" = None
- time startTime : "Start" = 0:00
-
-remote - "Remote":
- bool activated : "Activated" = False
- ip listenaddr : "Adress" = 0.0.0.0
- bool nolocalauth : "No authentication on local connections" = True
- int port : "Port" = 7227
-
-ssl - "SSL":
- bool activated : "Activated" = False
- file cert : "SSL Certificate" = ssl.crt
- file key : "SSL Key" = ssl.key
-
-webinterface - "Webinterface":
- bool activated : "Activated" = True
- bool basicauth : "Use basic auth" = False
- ip host : "IP" = 0.0.0.0
- bool https : "Use HTTPS" = False
- int port : "Port" = 8000
- str prefix : "Path Prefix" =
- builtin;threaded;fastcgi;lightweight server : "Server" = builtin
- modern;pyplex;classic template : "Template" = modern
-PYCONF
-
-echo_progress_done
-
-echo_progress_start "Initalizing database"
-read < <(
- /opt/.venv/pyload/bin/python2 /opt/pyload/pyLoadCore.py > /dev/null 2>&1 &
- echo $!
-)
-PID=$REPLY
-sleep 10
-#kill -9 $PID
-while kill -0 $PID > /dev/null 2>&1; do
- sleep 1
- kill $PID > /dev/null 2>&1
-done
-
-if [ -f "/opt/pyload/files.db" ]; then
- sqlite3 /opt/pyload/files.db "\
- INSERT INTO users('name', 'password') \
- VALUES('${user}','${HASH}');\
- "
- echo_progress_done
-else
- echo_error "Something went wrong with user setup -- you will be unable to login"
- #TODO maybe exit then?
-fi
-
-chown -R ${user}: /opt/pyload
-mkdir -p /home/${user}/Downloads
-chown ${user}: /home/${user}/Downloads
-
-echo_progress_start "Insatlling systemd service"
-cat > /etc/systemd/system/pyload.service << PYSD
-[Unit]
-Description=pyLoad
-After=network.target
-
-[Service]
-User=${user}
-ExecStart=/opt/.venv/pyload/bin/python2 /opt/pyload/pyLoadCore.py --config=/opt/pyload
-WorkingDirectory=/opt/pyload
-
-[Install]
-WantedBy=multi-user.target
-PYSD
-echo_progress_done
-
-if [[ -f /install/.nginx.lock ]]; then
- echo_progress_start "Configuring nginx"
- bash /usr/local/bin/swizzin/nginx/pyload.sh
- systemctl reload nginx
- echo_progress_done
-fi
-echo_progress_start "Enabling and starting pyLoad services"
-systemctl enable -q --now pyload.service 2>&1 | tee -a $log
-echo_progress_done
-
-echo_success "PyLoad installed"
-touch /install/.pyload.lock
diff --git a/scripts/install/sonarr.sh b/scripts/install/sonarr.sh
index c4353b4d6..fa2a00133 100755
--- a/scripts/install/sonarr.sh
+++ b/scripts/install/sonarr.sh
@@ -1,251 +1,128 @@
#!/bin/bash
-# Sonarr v3 installer
-# Flying sauasges for swizzin 2020
+# Sonarr Installer
+# GPLv3 applies
#shellcheck source=sources/functions/utils
. /etc/swizzin/sources/functions/utils
-[[ -z $sonarroldowner ]] && sonarroldowner=$(_get_master_username)
-
-if [[ -z $sonarrv3owner ]]; then
- sonarrv3owner=$(_get_master_username)
+app_name="sonarr"
+if [ -z "$SONARR_OWNER" ]; then
+ if ! SONARR_OWNER="$(swizdb get "$app_name/owner")"; then
+ SONARR_OWNER="$(_get_master_username)"
+ swizdb set "$app_name/owner" "$SONARR_OWNER"
+ fi
+else
+ echo_info "Setting ${app_name^} owner = $SONARR_OWNER"
+ swizdb set "$app_name/owner" "$SONARR_OWNER"
fi
-sonarrv3confdir="/home/$sonarrv3owner/.config/Sonarr"
+user="$SONARR_OWNER"
+swiz_configdir="/home/$user/.config"
+app_configdir="$swiz_configdir/${app_name^}"
+app_group="$user"
+app_port="8989"
+app_reqs=("curl" "sqlite3")
+app_servicefile="$app_name.service"
+app_dir="/opt/${app_name^}"
+app_binary="${app_name^}"
+app_lockname="${app_name//-/}"
+
+if [ ! -d "$swiz_configdir" ]; then
+ mkdir -p "$swiz_configdir"
+fi
+chown "$user":"$user" "$swiz_configdir"
-#Handles existing v2 instances
-_sonarrold_flow() {
- v2present=false
- if [[ -f /install/.sonarrold.lock ]]; then
- v2present=true
- fi
- if dpkg -l | grep nzbdrone > /dev/null 2>&1; then
- v2present=true
+_install() {
+ if [ ! -d "$app_configdir" ]; then
+ mkdir -p "$app_configdir"
fi
+ chown -R "$user":"$user" "$app_configdir"
- if [[ $v2present == "true" ]]; then
- echo_warn "Sonarr v2 is detected. Continuing will migrate your current v2 installation. This will stop and remove sonarr v2 You can read more about the migration at https://swizzin.ltd/applications/sonarrv3#migrating-from-v2. An additional copy of the backup will be made into /root/swizzin/backups/sonarrold.bak/"
- if ! ask "Do you want to continue?" N; then
- exit 0
- fi
-
- if ask "Would you like to trigger a Sonarr-side backup?" Y; then
- echo_progress_start "Backing up Sonarr v2"
- if [[ -f /install/.nginx.lock ]]; then
- address="http://127.0.0.1:8989/sonarr/api"
- else
- address="http://127.0.0.1:8989/api"
- fi
-
- [[ -z $sonarroldowner ]] && sonarroldowner=$(_get_master_username)
- if [[ ! -d /home/"${sonarroldowner}"/.config/NzbDrone ]]; then
- echo_error "No Sonarr config folder found for $sonarroldowner. Exiting"
- exit 1
- fi
-
- apikey=$(awk -F '[<>]' '/ApiKey/{print $3}' /home/"${sonarroldowner}"/.config/NzbDrone/config.xml)
- echo_log_only "apikey = $apikey"
-
- #This starts a backup on the current Sonarr instance. The logic below waits until the query returns as "completed"
- response=$(curl -sd '{name: "backup"}' -H "Content-Type: application/json" -X POST ${address}/command?apikey="${apikey}" --insecure)
- echo_log_only "$response"
- id=$(echo "$response" | jq '.id')
- echo_log_only "id=$id"
-
- if [[ -z $id ]]; then
- echo_warn "Failure triggering backup (see logs). Current Sonarr config and previous weekly backups will be backed up up and copied for migration"
- if ! ask "Continue without triggering internal Sonarr backup?" N; then
- exit 1
- fi
- else
- echo_log_only "Sonarr backup Job ID = $id, waiting to finish"
-
- status=""
- counter=0
- while [[ $status =~ ^(queued|started|)$ ]]; do
- sleep 0.2
- status=$(curl -s "${address}/command/$id?apikey=${apikey}" --insecure | jq -r '.status')
- ((counter += 1))
- if [[ $counter -gt 100 ]]; then
- echo_error "Sonarr backup timed out (20s), cancelling installation."
- exit 1
- fi
- done
- if [[ $status = "completed" ]]; then
- echo_progress_done "Backup complete"
- else
- echo_error "Sonarr returned unexpected status ($status). Terminating. Please try again."
- exit 1
- fi
- fi
- fi
-
- mkdir -p /root/swizzin/backups/
- echo_progress_start "Copying files to a backup location"
- cp -R /home/"${sonarroldowner}"/.config/NzbDrone /root/swizzin/backups/sonarrold.bak
- echo_progress_done "Backups copied"
-
- if [[ -d /home/"${sonarrv3owner}"/.config/Sonarr ]]; then
- if ask "$sonarrv3owner already has a sonarrv3 directory. Overwrite?" Y; then
- rm -rf
- cp -R /home/"${sonarroldowner}"/.config/NzbDrone /home/"${sonarrv3owner}"/.config/Sonarr
- else
- echo_info "Leaving v3 dir as is, why did we do any of this..."
- fi
- else
- cp -R /home/"${sonarroldowner}"/.config/NzbDrone /home/"${sonarrv3owner}"/.config/Sonarr
- fi
-
- systemctl stop sonarr@"${sonarroldowner}"
-
- # We don't have the debconf configuration yet so we can't migrate the data.
- # Instead we symlink so postinst knows where it's at.
- if [ -f "/usr/lib/sonarr/nzbdrone-appdata" ]; then
- rm "/usr/lib/sonarr/nzbdrone-appdata"
- else
- mkdir -p "/usr/lib/sonarr"
- fi
-
- echo_progress_start "Removing Sonarr v2"
- # shellcheck source=scripts/remove/sonarrold.sh
- bash /etc/swizzin/scripts/remove/sonarrold.sh
- echo_progress_done
- fi
-}
+ apt_install "${app_reqs[@]}"
+
+ echo_progress_start "Downloading release archive"
-_install_sonarr() {
- #shellcheck source=sources/functions/mono
- . /etc/swizzin/sources/functions/mono
- mono_repo_setup
- mkdir -p "$sonarrv3confdir"
- chown -R "$sonarrv3owner":"$sonarrv3owner" /home/"$sonarrv3owner"/.config
+ urlbase="https://services.sonarr.tv/v1/download/develop/latest?version=4&os=linux"
+ case "$(_os_arch)" in
+ "amd64") dlurl="${urlbase}&arch=x64" ;;
+ "armhf") dlurl="${urlbase}&arch=arm" ;;
+ "arm64") dlurl="${urlbase}&arch=arm64" ;;
+ *)
+ echo_error "Arch not supported"
+ exit 1
+ ;;
+ esac
- echo_log_only "Setting sonarr v3 owner to $sonarrv3owner"
- wget -O /tmp/sonarr.tar.gz "https://services.sonarr.tv/v1/download/main/latest?version=3&os=linux" >> ${log} 2>&1 || {
- echo_error "Sonarr could not be downloaded from sonarr.tv. Exiting"
+ if ! curl "$dlurl" -L -o "/tmp/$app_name.tar.gz" >> "$log" 2>&1; then
+ echo_error "Download failed, exiting"
exit 1
- }
- tar xf /tmp/sonarr.tar.gz -C /opt >> ${log} 2>&1 || {
- echo_error "Failed to extract archive"
+ fi
+ echo_progress_done "Archive downloaded"
+
+ echo_progress_start "Extracting archive"
+ tar xfv "/tmp/$app_name.tar.gz" --directory /opt/ >> "$log" 2>&1 || {
+ echo_error "Failed to extract"
exit 1
}
- rm -f /tmp/sonarr.tar.gz
- chown -R "$sonarrv3owner":"$sonarrv3owner" /opt/Sonarr
-
- LIST='mono-runtime
- ca-certificates-mono
- libmono-system-net-http4.0-cil
- libmono-corlib4.5-cil
- libmono-microsoft-csharp4.0-cil
- libmono-posix4.0-cil
- libmono-system-componentmodel-dataannotations4.0-cil
- libmono-system-configuration-install4.0-cil
- libmono-system-configuration4.0-cil
- libmono-system-core4.0-cil
- libmono-system-data-datasetextensions4.0-cil
- libmono-system-data4.0-cil
- libmono-system-identitymodel4.0-cil
- libmono-system-io-compression4.0-cil
- libmono-system-numerics4.0-cil
- libmono-system-runtime-serialization4.0-cil
- libmono-system-security4.0-cil
- libmono-system-servicemodel4.0a-cil
- libmono-system-serviceprocess4.0-cil
- libmono-system-transactions4.0-cil
- libmono-system-web4.0-cil
- libmono-system-xml-linq4.0-cil
- libmono-system-xml4.0-cil
- libmono-system4.0-cil
- sqlite3
- mediainfo'
-
- apt_install ${LIST}
-
- cat > /etc/systemd/system/sonarr.service << EOSD
-[Unit]
-Description=Sonarr Daemon
-After=network.target
+ rm -rf "/tmp/$app_name.tar.gz"
+ chown -R "${user}": "$app_dir"
+ echo_progress_done "Archive extracted"
+}
-[Service]
-User=${sonarrv3owner}
-Group=${sonarrv3owner}
-UMask=0002
+_nginx() {
+ if [[ -f /install/.nginx.lock ]]; then
+ echo_progress_start "Configuring nginx"
+ bash /etc/swizzin/scripts/nginx/"$app_name".sh
+ systemctl reload nginx
+ echo_progress_done "Nginx configured"
+ else
+ echo_info "$app_name will run on port $app_port"
+ fi
+}
+
+_systemd() {
+ echo_progress_start "Installing Systemd service"
+ cat > "/etc/systemd/system/$app_servicefile" << EOF
+[Unit]
+Description=${app_name^} Daemon
+After=syslog.target network.target
+[Service]
+# Change the user and group variables here.
+User=${user}
+Group=${app_group}
Type=simple
-ExecStart=/usr/bin/mono --debug /opt/Sonarr/Sonarr.exe -nobrowser -data=${sonarrv3confdir}
+# Change the path to ${app_name^} here if it is in a different location for you.
+ExecStart=$app_dir/$app_binary -nobrowser -data=$app_configdir
TimeoutStopSec=20
KillMode=process
Restart=on-failure
-
+# These lines optionally isolate (sandbox) ${app_name^} from the rest of the system.
+# Make sure to add any paths it might use to the list below (space-separated).
+#ReadWritePaths=$app_dir /path/to/media/folder
+#ProtectSystem=strict
+#PrivateDevices=true
+#ProtectHome=true
[Install]
WantedBy=multi-user.target
-EOSD
-
- if [[ ! -f ${sonarrv3confdir}/config.xml ]]; then
- cat > ${sonarrv3confdir}/config.xml << EOSC
-
- info
- False
- 8989
- 9898
-
- *
- None
- BuiltIn
- main
-
-EOSC
- chown -R ${sonarrv3owner}: ${sonarrv3confdir}/config.xml
- fi
- systemctl enable --now sonarr >> ${log} 2>&1
-
- touch /install/.sonarr.lock
-}
-
-# _add2usergroups_sonarrv3 () {
-# if [[ -z $sonarrv3grouplist ]]; then
-# if ask "Do you want to let Sonarr access other users' home directories?" N; then
-# echo "Space separated list of users to give sonarr access to: (e.g. \"user1 user2\")"
-# read -r sonarrv3grouplist
-# fi
-# fi
-# if [[ -n $sonarrv3grouplist ]]; then
-# for u in $sonarrv3grouplist; do
-# echo "Adding ${sonarrv3owner} to $u's group"
-# usermod -a -G "$u" "$sonarrv3owner"
-# chmod g+rwx /home/"$u"
-# done
-# fi
-# }
-
-_nginx_sonarr() {
- if [[ -f /install/.nginx.lock ]]; then
- #TODO what is this sleep here for? See if this can be fixed by doing a check for whatever it needs to
- echo_progress_start "Installing nginx configuration"
- bash /usr/local/bin/swizzin/nginx/sonarr.sh
- systemctl reload nginx >> "$log" 2>&1
- echo_progress_done
- else
- echo_info "Sonarr will run on port 8989"
+EOF
+
+ systemctl -q daemon-reload
+ systemctl enable --now -q "$app_servicefile"
+ sleep 1
+ echo_progress_done "${app_name^} service installed and enabled"
+ # In theory there should be no updating needed, so let's generalize this
+ echo_progress_start "${app_name^} is loading..."
+ if ! timeout 30 bash -c -- "while ! curl -sIL http://127.0.0.1:$app_port >> \"$log\" 2>&1; do sleep 2; done"; then
+ echo_error "The ${app_name^} web server has taken longer than 30 seconds to start."
+ exit 1
fi
+ echo_progress_done "Loading finished"
}
-_sonarrold_flow
-_install_sonarr
-_nginx_sonarr
-
-touch /install/.sonarr.lock
-
-if [[ -f /install/.ombi.lock ]]; then
- echo_info "Please adjust your Ombi setup accordingly"
-fi
-
-if [[ -f /install/.tautulli.lock ]]; then
- echo_info "Please adjust your Tautulli setup accordingly"
-fi
-
-if [[ -f /install/.bazarr.lock ]]; then
- echo_info "Please adjust your Bazarr setup accordingly"
-fi
+_install
+_systemd
+_nginx
-echo_success "Sonarr v3 installed"
+touch "/install/.$app_lockname.lock"
+echo_success "${app_name^} installed"
diff --git a/scripts/install/tautulli.sh b/scripts/install/tautulli.sh
index dc322567a..1ccdb3afc 100755
--- a/scripts/install/tautulli.sh
+++ b/scripts/install/tautulli.sh
@@ -14,9 +14,30 @@
# under the GPL along with build & install instructions.
#
+. /etc/swizzin/sources/functions/pyenv
+
user=$(cut -d: -f1 < /root/.master.info)
-apt_install python3
+systempy3_ver=$(get_candidate_version python3)
+
+if dpkg --compare-versions ${systempy3_ver} lt 3.8.0; then
+ PYENV=True
+else
+ LIST='python3-dev python3-setuptools python3-pip python3-venv'
+ apt_install $LIST
+fi
+
+case ${PYENV} in
+ True)
+ pyenv_install
+ pyenv_install_version 3.11.3
+ pyenv_create_venv 3.11.3 /opt/.venv/tautulli
+ chown -R tautulli: /opt/.venv/tautulli
+ ;;
+ *)
+ python3_venv tautulli tautulli
+ ;;
+esac
cd /opt
echo_progress_start "Cloning latest Tautulli repo"
@@ -36,7 +57,7 @@ Wants=network-online.target
After=network-online.target
[Service]
-ExecStart=/usr/bin/python3 /opt/tautulli/Tautulli.py --quiet --daemon --nolaunch --config /opt/tautulli/config.ini --datadir /opt/tautulli
+ExecStart=/opt/.venv/tautulli/bin/python3 /opt/tautulli/Tautulli.py --quiet --daemon --nolaunch --config /opt/tautulli/config.ini --datadir /opt/tautulli
GuessMainPID=no
Type=forking
User=tautulli
diff --git a/scripts/nginx/calibreweb.sh b/scripts/nginx/calibreweb.sh
index 11f34f793..2d785cb01 100755
--- a/scripts/nginx/calibreweb.sh
+++ b/scripts/nginx/calibreweb.sh
@@ -1,7 +1,6 @@
#!/bin/bash
cat > /etc/nginx/apps/calibreweb.conf << EOF
location /calibreweb {
- proxy_bind \$server_addr;
proxy_pass http://127.0.0.1:8083;
proxy_set_header Host \$http_host;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
diff --git a/scripts/nginx/qbittorrent.sh b/scripts/nginx/qbittorrent.sh
index 120a5d4e0..6a9f663d7 100755
--- a/scripts/nginx/qbittorrent.sh
+++ b/scripts/nginx/qbittorrent.sh
@@ -59,4 +59,14 @@ upstream ${user}.qbittorrent {
server 127.0.0.1:${port};
}
QBTUC
+ if grep -q 'WebUI\\Address=\*' /home/${user}/.config/qBittorrent/qBittorrent.conf; then
+ active=$(systemctl is-active qbittorrent@${user})
+ if [[ $active == "active" ]]; then
+ systemctl stop qbittorrent@${user} >> ${log} 2>&1
+ fi
+ sed -i 's|WebUI\\Address=.*|WebUI\\Address=127.0.0.1|g' /home/${user}/.config/qBittorrent/qBittorrent.conf
+ if [[ $active == "active" ]]; then
+ systemctl start qbittorrent@${user} >> ${log} 2>&1
+ fi
+ fi
done
diff --git a/scripts/nginx/sonarr.sh b/scripts/nginx/sonarr.sh
index 3617773ea..8b1ec332f 100755
--- a/scripts/nginx/sonarr.sh
+++ b/scripts/nginx/sonarr.sh
@@ -2,25 +2,26 @@
# Nginx conf for *Arr
# Flying sausages 2020
# Refactored by Bakerboy448 2021
+# Refactored by Brett 2023
master=$(_get_master_username)
app_name="sonarr"
if ! SONARR_OWNER="$(swizdb get $app_name/owner)"; then
- SONARR_OWNER=$(_get_master_username)
+ SONARR_OWNER=$master
fi
user="$SONARR_OWNER"
app_port="8989"
-app_sslport="8990"
+app_sslport="9898"
app_configdir="/home/$user/.config/${app_name^}"
app_baseurl="$app_name"
app_servicefile="${app_name}.service"
app_branch="main"
cat > /etc/nginx/apps/$app_name.conf << ARRNGINX
-location ^~ /$app_baseurl {
+location /$app_baseurl {
proxy_pass http://127.0.0.1:$app_port;
- proxy_set_header Host \$proxy_host;
+ proxy_set_header Host \$host;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host \$host;
proxy_set_header X-Forwarded-Proto \$scheme;
@@ -28,16 +29,15 @@ location ^~ /$app_baseurl {
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection \$http_connection;
-
auth_basic "What's the password?";
auth_basic_user_file /etc/htpasswd.d/htpasswd.${master};
}
-
# Allow the API External Access via NGINX
-
-location ^~ /$app_baseurl/api {
+location /$app_baseurl/api {
auth_basic off;
proxy_pass http://127.0.0.1:$app_port;
+ # Extend read timeout to allow long "Interactive Searches" to complete
+ proxy_read_timeout 900;
}
# Allow Calendar Feed External Access via NGINX
@@ -74,10 +74,6 @@ cat > "$app_configdir"/config.xml << ARRCONFIG
ARRCONFIG
-if [[ -f /install/.rutorrent.lock ]]; then
- sqlite3 /home/"$user"/.config/Sonarr/sonarr.db "INSERT or REPLACE INTO Config VALUES('6', 'certificatevalidation', 'DisabledForLocalAddresses');"
-fi
-
chown -R "$user":"$user" "$app_configdir"
# Switch app back off if it was dead before; otherwise start it
diff --git a/scripts/remove/jfago.sh b/scripts/remove/jfago.sh
index 01b38b03d..7417df328 100755
--- a/scripts/remove/jfago.sh
+++ b/scripts/remove/jfago.sh
@@ -1,23 +1,26 @@
#!/bin/bash
+. /etc/swizzin/sources/functions/utils
systemctl disable --now jfago -q
-rm -rf /root/.config/jfa-go
+rm_if_exists /root/.config/jfa-go
+rm_if_exists /opt/jfago
+userdel -rf jfago > /dev/null 2>&1
apt_remove jfa-go
-rm -f /usr/share/keyrings/jfa-go-archive-keyring.gpg
-rm -f /etc/apt/sources.list.d/jfa-go.list
+rm_if_exists /usr/share/keyrings/jfa-go-archive-keyring.gpg
+rm_if_exists /etc/apt/sources.list.d/jfa-go.list
apt_update
-rm -f /etc/systemd/system/jfago.service
+rm_if_exists /etc/systemd/system/jfago.service
systemctl daemon-reload -q
if [[ -f /install/.nginx.lock ]]; then
- rm /etc/nginx/apps/jfago.conf
+ rm_if_exists /etc/nginx/apps/jfago.conf
systemctl reload nginx
fi
-rm /install/.jfago.lock
+rm_if_exists /install/.jfago.lock
diff --git a/scripts/remove/netdata.sh b/scripts/remove/netdata.sh
index 681a7faaf..e8c08bfea 100755
--- a/scripts/remove/netdata.sh
+++ b/scripts/remove/netdata.sh
@@ -7,7 +7,7 @@ if [[ -f /usr/libexec/netdata/netdata-uninstaller.sh ]]; then
exit 1
}
else
- bash <(curl -Ssf https://my-netdata.io/kickstart.sh 2>> ${log} || { echo "exit 1"; }) --uninstall --non-interactive >> $log 2>&1 || {
+ bash <(curl -Ssf https://get.netdata.cloud/kickstart.sh 2>> ${log} || { echo "exit 1"; }) --uninstall --non-interactive >> $log 2>&1 || {
echo_error "Netdata remover failed!"
exit 1
}
diff --git a/scripts/remove/nginx.sh b/scripts/remove/nginx.sh
index 0a11916d3..342ef2c2a 100755
--- a/scripts/remove/nginx.sh
+++ b/scripts/remove/nginx.sh
@@ -2,7 +2,8 @@
systemctl stop -q nginx
-APT='nginx-extras nginx libnginx-mod-http-fancyindex ssl-cert php php-cli php-fpm php-dev php-xml php-curl php-xmlrpc php-json php-mcrypt php-opcache php-geoip php-xml php php-cli php-fpm php-dev php-xml php-curl php-xmlrpc php-json php-mcrypt php-opcache'
+[[ $(_os_codename) =~ ^(focal|buster|bullseye)$ ]] && geoip="php-geoip" || geoip=""
+APT="nginx-extras nginx libnginx-mod-http-fancyindex ssl-cert php php-cli php-fpm php-dev php-xml php-curl php-xmlrpc php-json php-opcache ${geoip}"
apt_remove $APT
LIST='nginx-* php7.0-* php-*'
diff --git a/scripts/remove/tautulli.sh b/scripts/remove/tautulli.sh
index ff4b14888..d535a8b64 100755
--- a/scripts/remove/tautulli.sh
+++ b/scripts/remove/tautulli.sh
@@ -2,6 +2,7 @@
systemctl stop -q tautulli
systemctl disable -q tautulli
rm -rf /opt/tautulli
+rm -rf /opt/.venv/tautulli
rm /install/.tautulli.lock
rm -f /etc/nginx/apps/tautulli.conf
systemctl reload nginx
diff --git a/scripts/update/10-dependencies.sh b/scripts/update/10-dependencies.sh
index 33950e9bb..6dc2fe053 100755
--- a/scripts/update/10-dependencies.sh
+++ b/scripts/update/10-dependencies.sh
@@ -46,7 +46,7 @@ if [[ $trigger_apt_update == "true" ]]; then
fi
#space-separated list of required GLOBAL SWIZZIN dependencies (NOT application specific ones)
-dependencies="whiptail git sudo curl wget lsof fail2ban apache2-utils vnstat tcl tcl-dev build-essential dirmngr apt-transport-https bc uuid-runtime jq net-tools gnupg2 cracklib-runtime unzip ccze"
+dependencies="whiptail git sudo curl wget lsof rsyslog fail2ban apache2-utils vnstat tcl tcl-dev build-essential dirmngr apt-transport-https bc uuid-runtime jq net-tools gnupg2 cracklib-runtime unzip ccze"
apt_install "${dependencies[@]}"
diff --git a/scripts/update/btsync.sh b/scripts/update/btsync.sh
index 7d8652413..32b353893 100755
--- a/scripts/update/btsync.sh
+++ b/scripts/update/btsync.sh
@@ -13,7 +13,6 @@ if [[ -f /install/.btsync.lock ]]; then
"listening_port" : 0,
"storage_path" : "/home/${MASTER}/.config/resilio-sync/",
"pid_file" : "/var/run/resilio-sync/sync.pid",
- "agree_to_EULA": "yes",
"webui" :
{
@@ -31,4 +30,14 @@ RSCONF
fi
echo_progress_done
fi
+ if grep -q EULA /etc/resilio-sync/config.json > /dev/null 2>&1; then
+ isActive=$(systemctl is-active resilio-sync)
+ if [[ $isActive == "active" ]]; then
+ systemctl stop resilio-sync
+ fi
+ sed -i '/EULA/d' /etc/resilio-sync/config.json
+ if [[ $isActive == "active" ]]; then
+ systemctl start resilio-sync
+ fi
+ fi
fi
diff --git a/scripts/update/calibreweb.sh b/scripts/update/calibreweb.sh
index b2e2a7819..6433d145a 100755
--- a/scripts/update/calibreweb.sh
+++ b/scripts/update/calibreweb.sh
@@ -16,3 +16,13 @@ if [[ -f /install/.calibreweb.lock ]]; then
echo_progress_done
fi
fi
+
+# Remove the proxy_bind setting from Nginx Conf.
+if [[ -f /etc/nginx/apps/calibreweb.conf ]]; then
+ if grep -q "proxy_bind[ \t]\+\$server_addr;" /etc/nginx/apps/calibreweb.conf ]]; then
+ echo_log_only "Removing proxy_bind from CalibreWeb nginx conf"
+ # Find the proxy_bind line, and remove it
+ sed -i 's/proxy_bind[[:space:]]\+\\\$server_addr;//g' /etc/nginx/apps/calibreweb.conf
+ systemctl reload nginx
+ fi
+fi
diff --git a/scripts/update/jfago.sh b/scripts/update/jfago.sh
new file mode 100755
index 000000000..dcdbebf3b
--- /dev/null
+++ b/scripts/update/jfago.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Updater for jfa-go
+if [[ -f /install/.jfago.lock ]]; then
+ # If installed as root user, move to /opt/jfago
+ if [[ -d /root/.config/jfa-go ]]; then
+ echo_progress_start "jfa-go install is running as root! Moving to unprivileged user."
+ # Store if the service was active before starting
+ isactive=$(systemctl is-active jfago)
+ echo_log_only "jfago was $isactive"
+ [[ $isactive == "active" ]] && systemctl stop jfago -q
+
+ useradd -r jfago -s /usr/sbin/nologin > /dev/null 2>&1
+ mkdir -p /opt/jfago/
+ mv /root/.config/jfa-go/ /opt/jfago/config
+ chown jfago: /opt/jfago -R
+
+ cat > /etc/systemd/system/jfago.service << EOF
+[Unit]
+Description=An account management system for Jellyfin.
+After=network.target
+[Service]
+ExecStart=/usr/local/bin/jfa-go -config /opt/jfago/config/config.ini -data /opt/jfago/config/
+User=jfago
+
+[Install]
+WantedBy=multi-user.target
+EOF
+
+ systemctl daemon-reload
+ [[ $isactive == "active" ]] && systemctl start jfago -q
+ echo_progress_done
+ fi
+fi
diff --git a/scripts/update/nginx.sh b/scripts/update/nginx.sh
index 37ac3773f..18b3dd9dd 100755
--- a/scripts/update/nginx.sh
+++ b/scripts/update/nginx.sh
@@ -1,22 +1,7 @@
#!/bin/bash
function update_nginx() {
- codename=$(lsb_release -cs)
-
- case $codename in
- focal | buster | bullseye)
- mcrypt=
- geoip="php-geoip"
- ;;
- *)
- mcrypt=
- geoip=
-
- ;;
- esac
-
- #Deprecate nginx-extras in favour of installing fancyindex alone
-
+ # Deprecate nginx-extras in favour of installing fancyindex alone
if dpkg -s nginx-extras > /dev/null 2>&1; then
apt_remove nginx-extras
apt_install nginx libnginx-mod-http-fancyindex
@@ -24,32 +9,23 @@ function update_nginx() {
rm $(ls -d /etc/nginx/modules-enabled/*.removed)
systemctl reload nginx
fi
- LIST="php-fpm php-cli php-dev php-xml php-curl php-xmlrpc php-json php-mbstring php-opcache php-xml php-zip ${geoip} ${mcrypt}"
-
- missing=()
- for dep in $LIST; do
- if ! check_installed "$dep"; then
- missing+=("$dep")
- fi
- done
-
- if [[ ${missing[1]} != "" ]]; then
- # echo_inf "Installing the following dependencies: ${missing[*]}" | tee -a $log
- apt_install "${missing[@]}"
- fi
-
+ # Install missing nginx packages
+ [[ $(lsb_release -cs) =~ ^(focal|buster|bullseye)$ ]] && geoip="php-geoip" || geoip=""
+ LIST="php-fpm php-cli php-dev php-xml php-curl php-xmlrpc php-json php-mbstring php-opcache php-xml php-zip ${geoip}"
+ apt_install $LIST
+ # Purge php7.0-fpm on all platforms
cd /etc/php
phpv=$(ls -d */ | cut -d/ -f1)
if [[ $phpv =~ 7\\.1 ]]; then
if [[ $phpv =~ 7\\.0 ]]; then
- apt_remove purge php7.0-fpm
+ apt_remove --purge php7.0-fpm
fi
fi
-
+ # Include php functions and set vars
. /etc/swizzin/sources/functions/php
phpversion=$(php_service_version)
sock="php${phpversion}-fpm"
-
+ # Reconfigure php.ini for php-fpm, enable opcache php module, set environment PATH var for php
for version in $phpv; do
if [[ -f /etc/php/$version/fpm/php.ini ]]; then
echo_progress_start "Updating config for PHP $version"
@@ -75,8 +51,6 @@ function update_nginx() {
echo_progress_done
fi
- phpversion=$(php_service_version)
-
fcgis=($(find /etc/nginx -type f -exec grep -l "fastcgi_pass unix:/run/php/" {} \;))
err=()
for f in ${fcgis[@]}; do
@@ -88,6 +62,12 @@ function update_nginx() {
echo_progress_done
done
+ if [[ ! -d /srv/fancyindex ]]; then
+ git clone https://github.com/Naereen/Nginx-Fancyindex-Theme/ /tmp/fancyindex >> $log 2>&1
+ mv /tmp/fancyindex/Nginx-Fancyindex-Theme-dark /srv/fancyindex >> $log 2>&1
+ rm -rf /tmp/fancyindex
+ fi
+
if grep -q -e "-dark" -e "Nginx-Fancyindex" /srv/fancyindex/header.html; then
echo_progress_start "Updating fancyindex theme"
sed -i 's/href="\/[^\/]*/href="\/fancyindex/g' /srv/fancyindex/header.html
@@ -227,6 +207,13 @@ FIAC
echo_progress_done
fi
+ # Disable emitting nginx version for HTTP protocol
+ if [[ $(grep -c 'server_tokens' /etc/nginx/sites-enabled/default) -lt 2 ]]; then
+ echo_progress_start "Disable emitting nginx version for HTTP protocol"
+ sed '/listen 80 default_server;/a \ \ server_tokens off;' -i /etc/nginx/sites-enabled/default
+ echo_progress_done
+ fi
+
#TODO: This needs an if statement
# fix /etc/nginx/sites-enabled/default to not cause nginx to fail on reloading when there are subdirectories in /etc/nginx/apps like /etc/nginx/apps/authelia
echo_progress_start "Fixing nginx for recursive configs"
diff --git a/scripts/update/pyload.sh b/scripts/update/pyload.sh
index a7939c548..446b2a89e 100755
--- a/scripts/update/pyload.sh
+++ b/scripts/update/pyload.sh
@@ -14,6 +14,7 @@
#
if [[ -f /install/.pyload.lock ]]; then
+ echo_warn "The version of pyload installed is susceptible to remote code execution (CVE-2023-0297). It is strongly recommended you uninstall pyload. No fixes will be forthcoming."
if [[ -f /etc/systemd/system/pyload@.service ]]; then
echo_progress_start "Updating pyLoad to use pyenv"
codename=$(lsb_release -cs)
diff --git a/scripts/update/qbittorrent.sh b/scripts/update/qbittorrent.sh
index ad1a1666d..aad8af722 100755
--- a/scripts/update/qbittorrent.sh
+++ b/scripts/update/qbittorrent.sh
@@ -27,5 +27,11 @@ if [[ -f /install/.qbittorrent.lock ]]; then
systemctl reload nginx
echo_progress_done
fi
+ users=($(_get_user_list))
+ for user in ${users[@]}; do
+ if grep -q 'WebUI\\Address=\*' /home/${user}/.config/qBittorrent/qBittorrent.conf; then
+ echo_warn "qBittorrent WebUI for ${user} is bound to all interfaces and can be accessed without the nginx proxy. The updater will not update this default for you in the event you want to keep it this way. You can fix this yourself in the qBittorrent WebUI: Settings > Web UI > Web User Interface > IP Address: 127.0.0.1. You can suppress this warning by changing your bind address to 0.0.0.0, though this may interfere with ipv6 access. Restart qBittorrent after making the change."
+ fi
+ done
fi
fi
diff --git a/scripts/update/sonarr.sh b/scripts/update/sonarr.sh
index 7d707ef78..7de2a610f 100755
--- a/scripts/update/sonarr.sh
+++ b/scripts/update/sonarr.sh
@@ -1,14 +1,125 @@
#!/bin/bash
-
if [[ -f /install/.sonarr.lock ]]; then
- #Check if mono needs an update
- . /etc/swizzin/sources/functions/mono
- mono_repo_update
- systemctl try-restart sonarr
+ #shellcheck source=sources/functions/utils
+ . /etc/swizzin/sources/functions/sonarr
+
+ #Move sonarr installs to .net
+ if grep -q "ExecStart=/usr/bin/mono" /etc/systemd/system/sonarr.service; then
+ echo_info "Moving Sonarr from mono to .Net"
+ #shellcheck source=sources/functions/utils
+ . /etc/swizzin/sources/functions/utils
+ [[ -z $sonarrOwner ]] && sonarrOwner=$(_get_master_username)
+
+ if [[ $(_sonarr_version) = "mono-v3" ]]; then
+ echo_progress_start "Downloading release files"
+ urlbase="https://services.sonarr.tv/v1/download/main/latest?version=4&os=linux"
+ case "$(_os_arch)" in
+ "amd64") dlurl="${urlbase}&arch=x64" ;;
+ "armhf") dlurl="${urlbase}&arch=arm" ;;
+ "arm64") dlurl="${urlbase}&arch=arm64" ;;
+ *)
+ echo_error "Arch not supported"
+ exit 1
+ ;;
+ esac
+ if ! curl "$dlurl" -L -o /tmp/sonarr.tar.gz >> "$log" 2>&1; then
+ echo_error "Download failed, exiting"
+ exit 1
+ fi
+ echo_progress_done "Release downloaded"
+
+ isactive=$(systemctl is-active sonarr)
+ echo_log_only "Sonarr was $isactive"
+ [[ $isactive == "active" ]] && systemctl stop sonarr -q
+
+ echo_progress_start "Removing old binaries"
+ rm -rf /opt/Sonarr/
+ MONO='mono-runtime
+ ca-certificates-mono
+ libmono-system-net-http4.0-cil
+ libmono-corlib4.5-cil
+ libmono-microsoft-csharp4.0-cil
+ libmono-posix4.0-cil
+ libmono-system-componentmodel-dataannotations4.0-cil
+ libmono-system-configuration-install4.0-cil
+ libmono-system-configuration4.0-cil
+ libmono-system-core4.0-cil
+ libmono-system-data-datasetextensions4.0-cil
+ libmono-system-data4.0-cil
+ libmono-system-identitymodel4.0-cil
+ libmono-system-io-compression4.0-cil
+ libmono-system-numerics4.0-cil
+ libmono-system-runtime-serialization4.0-cil
+ libmono-system-security4.0-cil
+ libmono-system-servicemodel4.0a-cil
+ libmono-system-serviceprocess4.0-cil
+ libmono-system-transactions4.0-cil
+ libmono-system-web4.0-cil
+ libmono-system-xml-linq4.0-cil
+ libmono-system-xml4.0-cil
+ libmono-system4.0-cil'
+ apt-mark auto ${MONO}
+ echo_progress_done "Binaries removed"
+
+ echo_progress_start "Extracting archive"
+ tar -xvf /tmp/sonarr.tar.gz -C /opt >> "$log" 2>&1
+ chown -R "$sonarrOwner":"$sonarrOwner" /opt/Sonarr
+ echo_progress_done "Archive extracted"
+
+ echo_progress_start "Fixing Sonarr systemd service"
+ # Watch out! If this sed runs, the updater will not trigger anymore. keep this at the bottom.
+ sed -i "s|ExecStart=/usr/bin/mono --debug /opt/Sonarr/Sonarr.exe|ExecStart=/opt/Sonarr/Sonarr|g" /etc/systemd/system/sonarr.service
+ systemctl daemon-reload
+ [[ $isactive == "active" ]] && systemctl start sonarr -q
+ echo_progress_done "Service fixed and restarted"
+ echo_success "Sonarr upgraded to .Net"
+
+ if [[ -f /install/.nginx.lock ]]; then
+ echo_progress_start "Upgrading nginx config for Sonarr"
+ bash /etc/swizzin/scripts/nginx/sonarr.sh
+ systemctl reload nginx -q
+ echo_progress_done "Nginx conf for Sonarr upgraded"
+ fi
+
+ elif [[ $(_sonarr_version) = "mono-v2" ]]; then
+ echo_warn "Sonarr v2 is EOL and not supported. Please upgrade your Sonarr to v4. An attempt will be made to migrate to .NET on the next \`box update\` run"
+ echo_docs "applications/sonarr#migrating-to-v3-on-net-core"
+ fi
+ else
+ echo_log_only "Sonarr's service is not pointing to mono"
+ fi
+ #Mandatory SSL Port change for Readarr
+ #shellcheck source=sources/functions/utils
+ . /etc/swizzin/sources/functions/utils
+ app_name="sonarr"
+ if [ -z "$sonarrOwner" ]; then
+ if ! sonarrOwner="$(swizdb get $app_name/owner)"; then
+ sonarrOwner=$(_get_master_username)
+ ownerToSetInDB='True'
+ fi
+ else
+ ownerToSetInDB='True'
+ fi
+
+ app_configfile="/home/$sonarrOwner/.config/Sonarr/config.xml"
+
+ if [[ $ownerToSetInDB = 'True' ]]; then
+ if [ -e "$app_configfile" ]; then
+ echo_info "Setting ${app_name^} owner = $sonarrOwner in SwizDB"
+ swizdb set "$app_name/owner" "$sonarrOwner"
+ else
+ echo_error "${app_name^} config file for sonarr owner does not exist in expected location.
+We are checking for $app_configfile.
+If the user here is incorrect, please run \`sonarrOwner= box update\`.
+${app_name^} updater is exiting, please try again later."
+ exit 1
+ fi
+ else
+ echo_log_only "Sonarr owner $sonarrOwner apparently did not need an update"
+ fi
if [[ -f /install/.nginx.lock ]]; then
- # Update Sonarr nginx config to bakerboy specs or to allow feed auth bypass
- if grep -q "8989/sonarr" /etc/nginx/apps/sonarr.conf || ! grep -q "calendar" /etc/nginx/apps/sonarr.conf; then
+ if grep -q "8989/sonarr" /etc/nginx/apps/sonarr.conf || ! grep -q "proxy_read_timeout" /etc/nginx/apps/sonarr.conf; then
echo_progress_start "Upgrading nginx config for Sonarr"
bash /etc/swizzin/scripts/nginx/sonarr.sh
systemctl reload nginx -q
diff --git a/scripts/update/tautulli.sh b/scripts/update/tautulli.sh
index 659776e93..0c26416aa 100755
--- a/scripts/update/tautulli.sh
+++ b/scripts/update/tautulli.sh
@@ -13,13 +13,35 @@ if [[ -f /install/.tautulli.lock ]]; then
echo_progress_done
fi
- if ! grep -q python3 /etc/systemd/system/tautulli.service; then
- echo_progress_start "Updating Tautulli systemd service file"
- sed -i 's|ExecStart=.*|ExecStart=/usr/bin/python3 /opt/tautulli/Tautulli.py --quiet --daemon --nolaunch --config /opt/tautulli/config.ini --datadir /opt/tautulli|g' /etc/systemd/system/tautulli.service
- chown -R tautulli:nogroup /opt/tautulli
- sudo -u tautulli git -C /opt/tautulli pull
+ if [[ ! -d /opt/.venv/tautulli ]]; then
+ echo_progress_start "Migrating Tautulli to venv"
+ . /etc/swizzin/sources/functions/pyenv
+ systempy3_ver=$(get_candidate_version python3)
+
+ if dpkg --compare-versions ${systempy3_ver} lt 3.8.0; then
+ PYENV=True
+ echo_info "pyenv will be used for the Tautulli venv. You may need to restart tautulli manually!"
+ else
+ LIST='python3-dev python3-setuptools python3-pip python3-venv'
+ apt_install $LIST
+ fi
+
+ case ${PYENV} in
+ True)
+ pyenv_install
+ pyenv_install_version 3.11.3
+ pyenv_create_venv 3.11.3 /opt/.venv/tautulli
+ chown -R tautulli: /opt/.venv/tautulli
+ ;;
+ *)
+ python3_venv tautulli tautulli
+ ;;
+ esac
+ sed -i 's|ExecStart=/usr|ExecStart=/opt/.venv/tautulli|g' /etc/systemd/system/tautulli.service
systemctl daemon-reload
- systemctl try-restart tautulli
+ if systemctl is-active tautulli > /dev/null 2>&1; then
+ systemctl restart tautulli
+ fi
echo_progress_done
fi
fi
diff --git a/scripts/upgrade/nzbhydra.sh b/scripts/upgrade/nzbhydra.sh
index bb24ff370..38bfdd7ca 100755
--- a/scripts/upgrade/nzbhydra.sh
+++ b/scripts/upgrade/nzbhydra.sh
@@ -131,7 +131,7 @@ WorkingDirectory=/opt/nzbhydra2
# NZBHydra stores its data in a "data" subfolder of its installation path
# To change that set the --datafolder parameter:
# --datafolder /path-to/datafolder
-ExecStart=/opt/nzbhydra2/nzbhydra2 --nobrowser --datafolder /home/${username}/.config/nzbhydra2 --nopidfile
+ExecStart=/opt/nzbhydra2/nzbhydra2wrapperPy3.py --nobrowser --datafolder /home/${username}/.config/nzbhydra2 --nopidfile
Restart=always
@@ -159,7 +159,7 @@ if [[ -z $localversion ]] || dpkg --compare-versions ${localversion#v} lt ${late
unzip nzbhydra2.zip >> ${log} 2>&1
rm -f nzbhydra2.zip
- chmod +x nzbhydra2
+ chmod +x nzbhydra2 nzbhydra2wrapperPy3.py
chown -R ${username}: /opt/nzbhydra2
if [[ $active == "active" ]]; then
diff --git a/setup.sh b/setup.sh
index fce81206f..69b59eae8 100755
--- a/setup.sh
+++ b/setup.sh
@@ -198,7 +198,7 @@ _os() {
echo_error "Your distribution ($distribution) is not supported. Swizzin requires Ubuntu or Debian."
exit 1
fi
- if [[ ! $codename =~ ^(buster|focal|bullseye|jammy|bookworm)$ ]]; then
+ if [[ ! $codename =~ ^(buster|focal|bullseye|jammy|bookworm|noble)$ ]]; then
echo_error "Your release ($codename) of $distribution is not supported."
exit 1
fi
@@ -367,7 +367,10 @@ function _post() {
ring_the_bell
echo_success "Swizzin installation complete!"
if [[ -f /install/.nginx.lock ]]; then
- echo_info "Seedbox can be accessed at https://${user}@${ip}"
+ echo_info "Seedbox can be accessed at https://${ip}"
+ if [[ ! -f /install/.panel.lock ]]; then
+ echo_info "Expect a 403 forbidden error on the root domain, since you did not install the panel."
+ fi
fi
if [[ -f /install/.deluge.lock ]]; then
diff --git a/sources/functions/autobrr b/sources/functions/autobrr
index 3e1b35594..511f10f95 100644
--- a/sources/functions/autobrr
+++ b/sources/functions/autobrr
@@ -13,7 +13,7 @@ function autobrr_download_latest() {
;;
esac
- latest=$(curl -sL https://api.github.com/repos/autobrr/autobrr/releases/latest | grep "linux_$arch" | grep browser_download_url | cut -d \" -f4) || {
+ latest=$(curl -sL https://api.github.com/repos/autobrr/autobrr/releases/latest | grep "linux_$arch" | grep browser_download_url | grep ".tar.gz" | cut -d \" -f4) || {
echo_error "Failed to query GitHub for latest version"
exit 1
}
diff --git a/sources/functions/curl b/sources/functions/curl
index fb5f0a7ff..d8586e3f5 100644
--- a/sources/functions/curl
+++ b/sources/functions/curl
@@ -2,8 +2,8 @@
# Upgrade curl to bypass the bug in Debian 10. Can be used on any system however, but the benefit is to Buster users most
configure_curl() {
- apt_install cmake libssl-dev libnghttp2-dev libzstd-dev libldap2-dev libssh2-1-dev libpsl-dev
- rm /usr/local/lib/libcurl.la
+ apt_install cmake libssl-dev libnghttp2-dev libzstd-dev libldap2-dev libssh2-1-dev libpsl-dev libbrotli-dev
+ rm_if_exists /usr/local/lib/libcurl.la
}
build_cares() {
@@ -24,7 +24,7 @@ build_cares() {
rm /tmp/cares.tar.gz
cd /tmp/cares
- rm CMakeCache.txt >> $log 2>&1
+ rm_if_exists CMakeCache.txt
cmake . -D CARES_STATIC=ON -D CARES_SHARED=ON -D CARES_STATIC_PIC=ON -D CMAKE_BUILD_TYPE:STRING="Release" -D CMAKE_C_FLAGS_RELEASE:STRING="-w -O3 -flto=\"$(nproc)\" -march=native" >> ${log} 2>&1 || {
echo_error "There was an error configuring c-ares! Please check the log for more info"
@@ -46,18 +46,19 @@ build_cares() {
build_curl() {
cd /tmp
+ . /etc/swizzin/sources/functions/utils
- wget -q -O /tmp/curl.zip https://salsa.debian.org/debian/curl/-/archive/debian/bullseye-backports/curl-debian-bullseye-backports.zip >> ${log} 2>&1 || {
+ wget -q -O /tmp/curl.zip https://salsa.debian.org/debian/curl/-/archive/debian/bookworm-backports/curl-debian-bookworm-backports.zip >> ${log} 2>&1 || {
echo_error "There was an error downloading curl! Please check the log for more info"
rm /tmp/curl.zip >> $log 2>&1
exit 1
}
- unzip -q /tmp/curl.zip -d /tmp >> $log 2>&1
+ unzip -q -o /tmp/curl.zip -d /tmp >> $log 2>&1
rm /tmp/curl.zip
- cd /tmp/curl-debian-bullseye-backports
- rm CMakeCache.txt >> $log 2>&1
+ cd /tmp/curl-debian-bookworm-backports
+ rm_if_exists CMakeCache.txt
cmake . -D ENABLE_ARES=ON -D ENABLE_WEBSOCKETS=ON -D CURL_LTO=ON -D CURL_USE_OPENSSL=ON -D CURL_USE_OPENLDAP=ON -D CURL_BROTLI=ON -D CURL_ZSTD=ON -D CURL_USE_LIBPSL=ON -D USE_NGHTTP2=ON -D BUILD_SHARED_LIBS=ON -D CMAKE_BUILD_TYPE:STRING="Release" -D CMAKE_C_FLAGS_RELEASE:STRING="-w -O3 -flto=\"$(nproc)\" -march=native" >> ${log} 2>&1 || {
echo_error "There was an error configuring curl! Please check the log for more info"
@@ -76,6 +77,14 @@ build_curl() {
cd /tmp
rm -rf /tmp/curl-* >> $log 2>&1
- ldconfig /usr/local/bin
ldconfig /usr/local/lib
+ ldconfig /usr/local/bin
+
+ rm_if_exists /usr/local/lib/libcurl.so.4
+ ln -s /usr/local/lib/libcurl.so.4.8.0 /usr/local/lib/libcurl.so.4 >> $log 2>&1
+
+ # force lookup of curl path next time it's used
+ if hash -t curl > /dev/null 2>&1; then
+ hash -d curl
+ fi
}
diff --git a/sources/functions/deluge b/sources/functions/deluge
index 5170a1f74..e325729f2 100644
--- a/sources/functions/deluge
+++ b/sources/functions/deluge
@@ -172,7 +172,7 @@ function build_libtorrent_deluge() {
libtorrent_clone
cd /tmp/libtorrent
- VERSION=$(grep AC_INIT configure.ac | grep -oP '\d+\.\d+\.\d+')
+ VERSION=$(grep -oP "VERSION\ = \K\d\.\d\.\d+" Jamfile)
if [[ -f /root/libtorrent-${libtorrent_branch}.patch ]]; then
patch -p1 < /root/libtorrent-${libtorrent_branch}.patch >> ${log} 2>&1 || {
diff --git a/sources/functions/fpm b/sources/functions/fpm
index a87d92df9..33cbf73ac 100644
--- a/sources/functions/fpm
+++ b/sources/functions/fpm
@@ -9,6 +9,10 @@ function install_fpm() {
case $(_os_codename) in
buster)
gem install public_suffix -v 4.0.7 >> $log 2>&1
+ gem install dotenv -v 2.8.1 >> $log 2>&1
+ ;;
+ focal)
+ gem install dotenv -v 2.8.1 >> $log 2>&1
;;
*) ;;
esac
diff --git a/sources/functions/libtorrent b/sources/functions/libtorrent
index 07778df1e..17372277d 100644
--- a/sources/functions/libtorrent
+++ b/sources/functions/libtorrent
@@ -141,20 +141,64 @@ function cleanup_repo_libtorrent() {
}
function booststrap() {
- BOOST_VERSION=1_75_0
+ case $(_os_codename) in
+ buster | focal | bullseye | jammy)
+ BOOST_VERSION=1_75_0
+ ;;
+ *)
+ BOOST_VERSION=1_85_0
+ ;;
+ esac
export BOOST_ROOT=/opt/boost_${BOOST_VERSION}
export BOOST_INCLUDEDIR=${BOOST_ROOT}
export BOOST_BUILD_PATH=${BOOST_ROOT}
+ oldBoosts=($(ls /opt 2> /dev/null | grep boost | grep -v ${BOOST_VERSION}))
+ if [[ -n ${oldBoosts[@]} ]]; then
+ for oldBoost in ${oldBoosts[@]}; do
+ echo_info "Removing old boost: ${oldBoost}"
+ if [[ -d /opt/${oldBoost} ]]; then
+ rm -rf /opt/${oldBoost}
+ fi
+ done
+ fi
if [[ ! -d ${BOOST_ROOT} ]]; then
echo_progress_start "Installing boost"
cd /opt
- wget https://boostorg.jfrog.io/artifactory/main/release/${BOOST_VERSION//_/.}/source/boost_${BOOST_VERSION}.tar.gz >> ${log} 2>&1 || {
- echo_warn "Could not download boost from main mirror, attempting fallback."
- wget https://deac-ams.dl.sourceforge.net/project/boost/boost/${BOOST_VERSION//_/.}/boost_${BOOST_VERSION}.tar.gz >> ${log} 2>&1 || {
- echo_error "Boost could not be downloaded. Setup will exit."
- exit 1
- }
- }
+ declare -A boost_mirror_urls=(
+ ["jfrog.io"]="https://boostorg.jfrog.io/artifactory/main/release/${BOOST_VERSION//_/.}/source/boost_${BOOST_VERSION}.tar.gz"
+ ["boost.io"]="https://archives.boost.io/release/${BOOST_VERSION//_/.}/source/boost_${BOOST_VERSION}.tar.gz"
+ ["sourceforge"]="https://deac-ams.dl.sourceforge.net/project/boost/boost/${BOOST_VERSION//_/.}/boost_${BOOST_VERSION}.tar.gz"
+ )
+
+ boost_failed_downloads=0
+ boost_valid_mime_types=("application/octet-stream" "application/x-gzip")
+
+ for boost_mirror in "${!boost_mirror_urls[@]}"; do
+ boost_url="${boost_mirror_urls[${boost_mirror}]}"
+
+ boost_response=$(wget --spider -S --max-redirect=2 --server-response "${boost_url}" 2>&1)
+ boost_content_type=$(echo "${boost_response}" | awk '/Content-Type/ {print $2}')
+
+ if [[ " ${boost_valid_mime_types[*]} " == *" ${boost_content_type} "* ]]; then
+ echo "Downloading from ${boost_mirror}: ${boost_url}..." >> ${log} 2>&1
+ wget --max-redirect=2 "${boost_url}" >> ${log} 2>&1
+ if [ $? -eq 0 ]; then
+ echo_info "Download from ${boost_mirror} successful, extracting files."
+ break
+ else
+ echo_info "Download from ${boost_mirror}. Trying next mirror..." >> ${log}
+ ((boost_failed_downloads++))
+ fi
+ else
+ echo_info "Skipping mirror ${boost_mirror}. Not a gzip file or offline" >> ${log} 2>&1
+ ((boost_failed_downloads++))
+ fi
+ done
+
+ if [ "${boost_failed_downloads}" -eq "${#boost_mirror_urls[@]}" ]; then
+ echo_error "No download mirror available."
+ exit 1
+ fi
tar xvf boost_${BOOST_VERSION}.tar.gz >> ${log} 2>&1
rm -f boost_${BOOST_VERSION}.tar.gz
cd ${BOOST_ROOT}
diff --git a/sources/functions/navidrome b/sources/functions/navidrome
index 6ef35f41c..8f6c55d59 100644
--- a/sources/functions/navidrome
+++ b/sources/functions/navidrome
@@ -4,7 +4,7 @@ function _navidrome_download_latest() {
echo_progress_start "Downloading release archive"
case "$(_os_arch)" in
- "amd64") arch='x86_64' ;;
+ "amd64") arch='amd64' ;;
"arm64") arch="arm64" ;;
"armhf") arch="armv7" ;;
*)
@@ -16,7 +16,7 @@ function _navidrome_download_latest() {
github_tag="$(git ls-remote -q -t --refs https://github.com/navidrome/navidrome.git | awk '{sub("refs/tags/", ""); print $2 }' | awk '!/^$/' | sort -rV | head -n 1)"
latest="https://github.com/navidrome/navidrome/releases/download/${github_tag}/navidrome_${github_tag#v}_Linux_${arch}.tar.gz"
- if ! curl "${latest}" -L -o "/tmp/navidrome.tar.gz" &>> "${log}"; then
+ if ! curl "${latest}" -f -L -o "/tmp/navidrome.tar.gz" &>> "${log}"; then
echo_error "Download failed, exiting"
exit 1
fi
diff --git a/sources/functions/npm b/sources/functions/npm
index 984ca7c09..8f3035a81 100644
--- a/sources/functions/npm
+++ b/sources/functions/npm
@@ -3,10 +3,14 @@
function npm_install() {
if [[ ! -f /etc/apt/sources.list.d/nodesource.list ]]; then
- bash <(curl -sL https://deb.nodesource.com/setup_18.x) >> $log 2>&1 || {
- echo_error "Failed to install node"
- return 1
- }
+ apt_update
+ apt_install ca-certificates curl gnupg
+ mkdir -p /etc/apt/keyrings
+ curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
+ NODE_MAJOR=20
+ echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
+ apt_update
+ apt_install nodejs
elif [[ -f /etc/apt/sources.list.d/nodesource.list ]]; then
npm_update
fi
@@ -20,12 +24,14 @@ function npm_install() {
function npm_update() {
if [[ -f /etc/apt/sources.list.d/nodesource.list ]]; then
- if [[ $(grep -m1 -oP 'node_\d+' /etc/apt/sources.list.d/nodesource.list | sed 's/node_//g') -lt "18" ]]; then
- echo_progress_start "Upgrading nodejs to version 18 LTS"
- bash <(curl -sL https://deb.nodesource.com/setup_18.x) >> $log 2>&1 || {
- echo_error "Failed to install node"
- return 1
- }
+ if [[ $(grep -m1 -oP 'node_\d+' /etc/apt/sources.list.d/nodesource.list | sed 's/node_//g') -lt "20" ]]; then
+ echo_progress_start "Upgrading nodejs to version 20 LTS"
+ apt_update
+ apt_install ca-certificates curl gnupg
+ mkdir -p /etc/apt/keyrings
+ curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
+ NODE_MAJOR=20
+ echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
apt_update
apt_upgrade
echo_progress_done "Npm upgraded"
diff --git a/sources/functions/qbittorrent b/sources/functions/qbittorrent
index 29401a870..88d56ffe0 100644
--- a/sources/functions/qbittorrent
+++ b/sources/functions/qbittorrent
@@ -11,6 +11,7 @@ function whiptail_qbittorrent() {
latestv43=$(echo "$releases" | grep -m1 -oP '^4\.3\.\d?.?\d')
latestv44=$(echo "$releases" | grep -m1 -oP '^4\.4\.\d?.?\d')
latestv45=$(echo "$releases" | grep -m1 -oP '^4\.5\.\d?.?\d')
+ latestv46=$(echo "$releases" | grep -m1 -oP '^4\.6\.\d?.?\d')
#latestv=$(echo "$releases" | grep -m1 -oP '\d.\d?.?\d?.?\d')
repov=$(get_candidate_version qbittorrent-nox)
case ${codename} in
@@ -26,6 +27,7 @@ function whiptail_qbittorrent() {
*)
function=$(whiptail --title "Pick qbittorrent version" --menu "Choose a qBittorrent version:" --ok-button "Continue" --nocancel 12 50 6 \
"Repo" "${repov}" \
+ "4.6" "(${latestv46})" \
"4.5" "(${latestv45})" \
"4.4" "(${latestv44})" \
"4.3" "(${latestv43})" \
@@ -55,6 +57,9 @@ function whiptail_qbittorrent() {
;;
4.5)
export QBITTORRENT_VERSION=${latestv45}
+ ;;
+ 4.6)
+ export QBITTORRENT_VERSION=${latestv46}
;;
Repo)
export QBITTORRENT_VERSION=repo
@@ -169,6 +174,31 @@ function qbittorrent_version_info() {
qbt_use_qt6=ON
cryptography_type=openssl
build_type=cmake
+ ;;
+ 4.6.*)
+ if [[ -n ${LIBTORRENT_VERSION} ]]; then
+ case $LIBTORRENT_VERSION in
+ RC_2_0)
+ libtorrent_branch=RC_2_0
+ ;;
+ RC_1_2)
+ libtorrent_branch=RC_1_2
+ ;;
+ *)
+ echo_error "LIBTORRENT_VERSION must be either RC_1_2 or RC_2_0. You entered ${LIBTORRENT_VERSION}."
+ exit 1
+ ;;
+ esac
+ echo_info "Overriding libtorrent version with ${LIBTORRENT_VERSION}"
+ else
+ libtorrent_branch=RC_1_2
+ fi
+ libtorrent_minimum_version=1.2.19
+ stdcver="c++17"
+ qt_minimum_version=6.4
+ qbt_use_qt6=ON
+ cryptography_type=openssl
+ build_type=cmake
;;
*)
echo_error "qBittorrent version should be between 4.1.*(.*) and 4.4.*(.*) -- Setup will not proceed."
@@ -203,7 +233,7 @@ function install_qt() {
if [[ -z ${qbt_use_qt6} ]]; then
LIST='qtbase5-dev qttools5-dev'
else
- LIST='qt6-base-dev qt6-tools-dev qt6-l10n-tools qt6-tools-dev-tools'
+ LIST='qt6-base-dev qt6-tools-dev qt6-l10n-tools qt6-tools-dev-tools qt6-base-private-dev'
fi
qt_repo_version=$(get_candidate_version ${LIST[0]})
if [[ -z $qt_repo_version ]]; then
diff --git a/sources/functions/rtorrent b/sources/functions/rtorrent
index a91daa34c..4b173a875 100644
--- a/sources/functions/rtorrent
+++ b/sources/functions/rtorrent
@@ -5,60 +5,87 @@ export release=$(lsb_release -rs)
export codename=$(lsb_release -cs)
function whiptail_rtorrent() {
- if [[ -z $rtorrentver ]] && [[ -z $1 ]]; then
+ if [[ -z $rtorrentver ]] && [[ -z $1 ]] && [[ -z $RTORRENT_VERSION ]]; then
repov=$(get_candidate_version rtorrent)
whiptail --title "rTorrent Install Advisory" --msgbox "We recommend rTorrent version selection instead of repo (distro) releases. They will compile additional performance and stability improvements in 90s. UDNS includes a stability patch for UDP trackers on rTorrent." 15 50
function=$(whiptail --title "Choose an rTorrent version" --menu "All versions other than repo will be locally compiled from source" --ok-button "Continue" 14 50 5 \
+ 0.10.0 "" \
0.9.8 "" \
0.9.7 "" \
0.9.6 "" \
UDNS "(0.9.8)" \
+ PGO "(0.9.8)" \
Repo "(${repov})" 3>&1 1>&2 2>&3) || {
echo_error "rTorrent version choice aborted"
exit 1
}
- case $function in
- 0.9.6)
- export rtorrentver='0.9.6'
- export libtorrentver='0.13.6'
- export libudns='false'
- ;;
-
- 0.9.7)
- export rtorrentver='0.9.7'
- export libtorrentver='0.13.7'
- export libudns='false'
- ;;
-
- 0.9.8)
- export rtorrentver='0.9.8'
- export libtorrentver='0.13.8'
- export libudns='false'
- ;;
-
- UDNS)
- export rtorrentver='0.9.8'
- export libtorrentver='0.13.8'
- export libudns='true'
- ;;
-
- Repo)
- export rtorrentver='repo'
- export libtorrentver='repo'
- export libudns='false'
- ;;
-
- *)
- echo_error "$function is not a valid rTorrent version"
- exit 1
- ;;
- esac
+ set_rtorrent_version $function
+ elif [[ -n $RTORRENT_VERSION ]]; then
+ set_rtorrent_version $RTORRENT_VERSION
fi
}
+function set_rtorrent_version() {
+ case $1 in
+ 0.9.6 | '0.9.6')
+ export rtorrentver='0.9.6'
+ export libtorrentver='0.13.6'
+ export libudns='false'
+ export rtorrentpgo='false'
+ ;;
+
+ 0.9.7 | '0.9.7')
+ export rtorrentver='0.9.7'
+ export libtorrentver='0.13.7'
+ export libudns='false'
+ export rtorrentpgo='false'
+ ;;
+
+ 0.9.8 | '0.9.8')
+ export rtorrentver='0.9.8'
+ export libtorrentver='0.13.8'
+ export libudns='false'
+ export rtorrentpgo='false'
+ ;;
+
+ 0.10.0 | '0.10.0')
+ export rtorrentver='0.10.0'
+ export libtorrentver='0.14.0'
+ export libudns='false'
+ export rtorrentpgo='false'
+ ;;
+
+ UDNS | 'UDNS')
+ export rtorrentver='0.9.8'
+ export libtorrentver='0.13.8'
+ export libudns='true'
+ export rtorrentpgo='false'
+ ;;
+
+ PGO | 'PGO')
+ export rtorrentver='0.9.8'
+ export libtorrentver='0.13.8'
+ export libudns='true'
+ export rtorrentpgo='true'
+ ;;
+
+ Repo | 'Repo')
+ export rtorrentver='repo'
+ export libtorrentver='repo'
+ export libudns='false'
+ export rtorrentpgo='false'
+ ;;
+
+ *)
+ echo_error "$1 is not a valid rTorrent version"
+ exit 1
+ ;;
+ esac
+}
+
function configure_rtorrent() {
# Link time optimizations for 4 plus threads
if [ $(nproc) -ge 4 ]; then
@@ -74,11 +101,19 @@ function configure_rtorrent() {
export rtorrentpipe=""
fi
# GCC optimization level for program compilation
- if [ $(nproc) -le 2 ]; then
+ if [ $(nproc) -le 1 ]; then
export rtorrentlevel="-O1"
+ elif [ $(nproc) -ge 8 ]; then
+ export rtorrentlevel="-O3"
else
export rtorrentlevel="-O2"
fi
+ # GCC PGO for program compilation
+ if [[ ${rtorrentpgo} == "true" ]]; then
+ export rtorrentprofile="-fprofile-use"
+ else
+ export rtorrentprofile=""
+ fi
}
function depends_rtorrent() {
@@ -86,7 +121,7 @@ function depends_rtorrent() {
APT='subversion dos2unix bc screen zip unzip sysstat build-essential comerr-dev
dstat automake libtool libcppunit-dev libssl-dev pkg-config libcurl4-openssl-dev
libsigc++-2.0-dev unzip curl libncurses5-dev yasm fontconfig libfontconfig1
- libfontconfig1-dev mediainfo'
+ libfontconfig1-dev mediainfo autoconf-archive'
apt_install $APT
. /etc/swizzin/sources/functions/fpm
@@ -103,7 +138,7 @@ function depends_rtorrent() {
rm_if_exists "/tmp/mktorrent"
unzip -d mktorrent -j mktorrent.zip >> $log 2>&1
cd mktorrent
- make >> $log 2>&1
+ make -j$(nproc) CC=gcc CFLAGS="-w ${rtorrentflto} ${rtorrentpipe} ${rtorrentlevel}" >> $log 2>&1
make install PREFIX=/usr >> $log 2>&1
cd /tmp
rm -rf mktorrent*
@@ -114,7 +149,7 @@ function depends_rtorrent() {
cd /tmp/udns
./autogen.sh >> $log 2>&1
./configure --prefix=/usr >> $log 2>&1
- make -j$(nproc) CFLAGS="-w ${rtorrentflto} ${rtorrentpipe} -O2 -fPIC" >> $log 2>&1
+ make -j$(nproc) CFLAGS="-w ${rtorrentflto} ${rtorrentpipe} ${rtorrentlevel} -fPIC" >> $log 2>&1
make -s install >> $log 2>&1
cd /tmp
rm -rf udns*
@@ -126,18 +161,17 @@ function build_xmlrpc-c() {
. /etc/swizzin/sources/functions/utils
rm_if_exists "/tmp/xmlrpc-c"
rm_if_exists "/tmp/dist/xmlrpc-c "
- XMLRPC_REV=2954
- svn co http://svn.code.sf.net/p/xmlrpc-c/code/advanced@$XMLRPC_REV /tmp/xmlrpc-c >> $log 2>&1 || { svn co https://github.com/mirror/xmlrpc-c/trunk/advanced@$XMLRPC_REV /tmp/xmlrpc-c >> $log 2>&1; }
+ svn checkout svn://svn.code.sf.net/p/xmlrpc-c/code/stable@3212 /tmp/xmlrpc-c >> $log 2>&1;
cd /tmp/xmlrpc-c
cp -rf /etc/swizzin/sources/patches/rtorrent/xmlrpc-config.guess config.guess >> $log 2>&1
cp -rf /etc/swizzin/sources/patches/rtorrent/xmlrpc-config.sub config.sub >> $log 2>&1
- ./configure --prefix=/usr --disable-cplusplus --disable-wininet-client --disable-libwww-client >> $log 2>&1 || {
+ ./configure --prefix=/usr --disable-cplusplus --disable-wininet-client --disable-libwww-client --disable-abyss-server --disable-cgi-server >> $log 2>&1 || {
echo_error "Something went wrong while configuring xmlrpc"
exit 1
}
source <(sed 's/ //g' version.mk)
VERSION=$XMLRPC_MAJOR_RELEASE.$XMLRPC_MINOR_RELEASE.$XMLRPC_POINT_RELEASE
- make -j$(nproc) CFLAGS="-w ${rtorrentflto} ${rtorrentpipe}" >> $log 2>&1
+ make -j$(nproc) CFLAGS="-w ${rtorrentlevel} ${rtorrentflto} ${rtorrentpipe}" >> $log 2>&1
make DESTDIR=/tmp/dist/xmlrpc-c install >> $log 2>&1 || {
echo_error "Something went wrong while making xmlrpc"
exit 1
@@ -151,28 +185,40 @@ function build_xmlrpc-c() {
}
function build_libtorrent_rakshasa() {
- libtorrentloc="https://github.com/rakshasa/libtorrent/archive/refs/tags/v${libtorrentver}.tar.gz"
- cd "/tmp"
- . /etc/swizzin/sources/functions/utils
- rm_if_exists "/tmp/libtorrent"
- mkdir /tmp/libtorrent
- curl -sL ${libtorrentloc} -o /tmp/libtorrent-${libtorrentver}.tar.gz
- VERSION=$libtorrentver
- tar -xf /tmp/libtorrent-${libtorrentver}.tar.gz -C /tmp/libtorrent --strip-components=1 >> $log 2>&1
- cd /tmp/libtorrent >> $log 2>&1
-
- if [[ -f /root/libtorrent-rakshasa-${libtorrentver}.patch ]]; then
- patch -p1 < /root/libtorrent-rakshasa-${libtorrentver}.patch >> ${log} 2>&1 || {
- echo _error "Something went wrong when patching libtorrent-rakshasa"
- exit 1
- }
- echo_info "Libtorrent-rakshasa patch found and applied!"
+ if [[ ${libtorrentver} == "0.14.0" ]]; then
+ build_libtorrent_rakshasa_new
else
- echo_log_only "No libtorrent-rakshasa patch found at /root/libtorrent-rakshasa-${libtorrentver}.patch"
+ build_libtorrent_rakshasa_old
fi
+}
+
+function build_libtorrent_rakshasa_new() {
+ . /etc/swizzin/sources/functions/utils
+ download_libtorrent_rakshasa
+ auto_patch_libtorrent_rakshasa
+
+ autoreconf -vfi >> $log 2>&1
+ ./configure --prefix=/usr --enable-aligned >> $log 2>&1 || {
+ echo_error "Something went wrong while configuring libtorrent"
+ exit 1
+ }
+ make -j$(nproc) CXXFLAGS="-w ${rtorrentlevel} ${rtorrentflto} ${rtorrentpipe}" >> $log 2>&1 || {
+ echo_error "Something went wrong while making libtorrent"
+ exit 1
+ }
+
+ install_libtorrent_rakshasa
+}
+
+function build_libtorrent_rakshasa_old() {
+ . /etc/swizzin/sources/functions/utils
+ download_libtorrent_rakshasa
+ auto_patch_libtorrent_rakshasa
+
if [[ ${libudns} == "true" ]]; then
patch -p1 < /etc/swizzin/sources/patches/rtorrent/libtorrent-udns-0.13.8.patch >> "$log" 2>&1
patch -p1 < /etc/swizzin/sources/patches/rtorrent/libtorrent-scanf-0.13.8.patch >> "$log" 2>&1
+ patch -p1 < /etc/swizzin/sources/patches/rtorrent/lookup-cache-0.13.8.patch >> "$log" 2>&1
fi
if [[ ${libtorrentver} =~ ^("0.13.7"|"0.13.8")$ ]]; then
patch -p1 < /etc/swizzin/sources/patches/rtorrent/throttle-fix-0.13.7-8.patch >> "$log" 2>&1
@@ -188,7 +234,7 @@ function build_libtorrent_rakshasa() {
fi
fi
./autogen.sh >> $log 2>&1
- ./configure --prefix=/usr >> $log 2>&1 || {
+ ./configure --prefix=/usr --enable-aligned >> $log 2>&1 || {
echo_error "Something went wrong while configuring libtorrent"
exit 1
}
@@ -196,6 +242,37 @@ function build_libtorrent_rakshasa() {
echo_error "Something went wrong while making libtorrent"
exit 1
}
+
+ install_libtorrent_rakshasa
+}
+
+function download_libtorrent_rakshasa() {
+ libtorrentloc="https://github.com/rakshasa/libtorrent/archive/refs/tags/v${libtorrentver}.tar.gz"
+ cd "/tmp"
+ . /etc/swizzin/sources/functions/utils
+ rm_if_exists "/tmp/libtorrent"
+ mkdir /tmp/libtorrent
+ curl -sL ${libtorrentloc} -o /tmp/libtorrent-${libtorrentver}.tar.gz
+ tar -xf /tmp/libtorrent-${libtorrentver}.tar.gz -C /tmp/libtorrent --strip-components=1 >> $log 2>&1
+ cd /tmp/libtorrent >> $log 2>&1
+}
+
+function auto_patch_libtorrent_rakshasa() {
+ . /etc/swizzin/sources/functions/utils
+ if [[ -f /root/libtorrent-rakshasa-${libtorrentver}.patch ]]; then
+ patch -p1 < /root/libtorrent-rakshasa-${libtorrentver}.patch >> ${log} 2>&1 || {
+ echo _error "Something went wrong when patching libtorrent-rakshasa"
+ exit 1
+ }
+ echo_info "Libtorrent-rakshasa patch found and applied!"
+ else
+ echo_log_only "No libtorrent-rakshasa patch found at /root/libtorrent-rakshasa-${libtorrentver}.patch"
+ fi
+}
+
+function install_libtorrent_rakshasa() {
+ VERSION=$libtorrentver
+ . /etc/swizzin/sources/functions/utils
rm_if_exists "/tmp/dist/libtorrent-rakshasa"
make DESTDIR=/tmp/dist/libtorrent-rakshasa install >> $log 2>&1
mkdir -p /root/dist
@@ -207,31 +284,55 @@ function build_libtorrent_rakshasa() {
}
function build_rtorrent() {
- rtorrentloc="https://github.com/rakshasa/rtorrent/archive/refs/tags/v${rtorrentver}.tar.gz"
- cd "/tmp"
- . /etc/swizzin/sources/functions/utils
- rm_if_exists "/tmp/rtorrent*"
- mkdir /tmp/rtorrent
- curl -sL ${rtorrentloc} -o /tmp/rtorrent-${rtorrentver}.tar.gz
- tar -xzf /tmp/rtorrent-${rtorrentver}.tar.gz -C /tmp/rtorrent --strip-components=1 >> $log 2>&1
- VERSION=$rtorrentver
- cd /tmp/rtorrent
- if [[ -f /root/rtorrent-${rtorrentver}.patch ]]; then
- patch -p1 < /root/rtorrent-${rtorrentver}.patch >> ${log} 2>&1 || {
- echo _error "Something went wrong when patching rTorrent"
- exit 1
- }
- echo_info "rTorrent patch found and applied!"
+ if [[ ${rtorrentver} == "0.10.0" ]]; then
+ build_rtorrent_new
else
- echo_log_only "No rTorrent patch found at /root/rtorrent-${rtorrentver}.patch"
+ build_rtorrent_old
fi
+}
+
+function build_rtorrent_new() {
+ . /etc/swizzin/sources/functions/utils
+ download_rtorrent
+ auto_patch_rtorrent
+
+ autoreconf -vfi >> $log 2>&1
+ ./configure --prefix=/usr --with-xmlrpc-c >> $log 2>&1 || {
+ echo_error "Something went wrong while configuring rtorrent"
+ exit 1
+ }
+ make -j$(nproc) CXXFLAGS="-w ${rtorrentlevel} ${rtorrentflto} ${rtorrentpipe}" >> $log 2>&1 || {
+ echo_error "Something went wrong while making rtorrent"
+ exit 1
+ }
+
+ install_rtorrent
+}
+
+function build_rtorrent_old() {
+ download_rtorrent
+ auto_patch_rtorrent
+
+ #apply memory leak fixes to 0.9.8 branches bases only (0.9.8, UDNS, PGO) to reduce maintenance and testing
+ #apply first thing to ensure compatibility with the tracker delay scrape patch by modifying higher line numbers first
+ if [[ ${rtorrentver} == "0.9.8" ]]; then
+ patch -p1 < /etc/swizzin/sources/patches/rtorrent/rtorrent-ml-fixes-0.9.8.patch >> "$log" 2>&1
+ fi
+ #apply tracker delay scrape patch to UDNS branch
if [[ ${libudns} == "true" ]]; then
patch -p1 < /etc/swizzin/sources/patches/rtorrent/rtorrent-scrape-0.9.8.patch >> "$log" 2>&1
+ patch -p1 < /etc/swizzin/sources/patches/rtorrent/fast-session-loading-0.9.8.patch >> "$log" 2>&1
fi
#apply lockfile-fix to all rtorrents
patch -p1 < /etc/swizzin/sources/patches/rtorrent/lockfile-fix.patch >> "$log" 2>&1
#apply xmlrpc-fix to all rtorrents
patch -p1 < /etc/swizzin/sources/patches/rtorrent/xmlrpc-fix.patch >> "$log" 2>&1
+ #apply xmlrpc-logic-fix to all rtorrents
+ patch -p1 < /etc/swizzin/sources/patches/rtorrent/xmlrpc-logic-fix.patch >> "$log" 2>&1
+ #apply scgi-fix to all rtorrents
+ patch -p1 < /etc/swizzin/sources/patches/rtorrent/scgi-fix.patch >> "$log" 2>&1
+ #apply session-file-fix to all rtorrents
+ patch -p1 < /etc/swizzin/sources/patches/rtorrent/session-file-fix.patch >> "$log" 2>&1
#use pkgconfig for cppunit if 0.9.6
stdc=
if [[ ${rtorrentver} == "0.9.6" ]]; then
@@ -243,10 +344,57 @@ function build_rtorrent() {
echo_error "Something went wrong while configuring rtorrent"
exit 1
}
- make -j$(nproc) CXXFLAGS="-w ${rtorrentlevel} ${rtorrentflto} ${rtorrentpipe} ${stdc}" >> $log 2>&1 || {
+ if [[ ${rtorrentpgo} == "true" ]]; then
+ echo_log_only "Begin fprofile generate for rTorrent"
+ make -j$(nproc) CXXFLAGS="-w ${rtorrentlevel} ${rtorrentflto} ${rtorrentpipe} ${stdc} -fprofile-generate" >> $log 2>&1 || {
+ echo_error "Something went wrong while making rtorrent with -fprofile-generate"
+ exit 1
+ }
+ make install >> $log 2>&1
+ echo_info "Running rTorrent PGO for 30s. Please wait..."
+ touch ~/.rtorrent.rc
+ screen -d -m -fa -S rtorrent_pgo rtorrent
+ sleep 30
+ screen -X -S rtorrent_pgo quit
+ rm_if_exists "~/.rtorrent.rc"
+ make clean >> $log 2>&1
+ echo_log_only "End fprofile generate for rTorrent"
+ fi
+ make -j$(nproc) CXXFLAGS="-w ${rtorrentlevel} ${rtorrentflto} ${rtorrentpipe} ${stdc} ${rtorrentprofile}" >> $log 2>&1 || {
echo_error "Something went wrong while making rtorrent"
exit 1
}
+
+ install_rtorrent
+}
+
+function download_rtorrent() {
+ rtorrentloc="https://github.com/rakshasa/rtorrent/archive/refs/tags/v${rtorrentver}.tar.gz"
+ cd "/tmp"
+ . /etc/swizzin/sources/functions/utils
+ rm_if_exists "/tmp/rtorrent*"
+ mkdir /tmp/rtorrent
+ curl -sL ${rtorrentloc} -o /tmp/rtorrent-${rtorrentver}.tar.gz
+ tar -xzf /tmp/rtorrent-${rtorrentver}.tar.gz -C /tmp/rtorrent --strip-components=1 >> $log 2>&1
+ cd /tmp/rtorrent
+}
+
+function auto_patch_rtorrent() {
+ . /etc/swizzin/sources/functions/utils
+ if [[ -f /root/rtorrent-${rtorrentver}.patch ]]; then
+ patch -p1 < /root/rtorrent-${rtorrentver}.patch >> ${log} 2>&1 || {
+ echo _error "Something went wrong when patching rTorrent"
+ exit 1
+ }
+ echo_info "rTorrent patch found and applied!"
+ else
+ echo_log_only "No rTorrent patch found at /root/rtorrent-${rtorrentver}.patch"
+ fi
+}
+
+function install_rtorrent() {
+ VERSION=$rtorrentver
+ . /etc/swizzin/sources/functions/utils
rm_if_exists "/tmp/dist/rtorrent"
make DESTDIR=/tmp/dist/rtorrent install >> $log 2>&1
mkdir -p /root/dist
diff --git a/sources/functions/rutorrent b/sources/functions/rutorrent
index 8825033fd..a83c057ca 100644
--- a/sources/functions/rutorrent
+++ b/sources/functions/rutorrent
@@ -1,7 +1,7 @@
#!/bin/bash
function rutorrent_install() {
- apt_install sox geoip-database p7zip-full zip unzip
+ apt_install sox geoip-database p7zip-full zip unzip php-bcmath
mkdir -p /srv
if [[ ! -d /srv/rutorrent ]]; then
@@ -15,8 +15,10 @@ function rutorrent_install() {
chown -R www-data:www-data /srv/rutorrent
rm -rf /srv/rutorrent/plugins/throttle
rm -rf /srv/rutorrent/plugins/_cloudflare
+ rm -rf /srv/rutorrent/plugins/dump
rm -rf /srv/rutorrent/plugins/extratio
rm -rf /srv/rutorrent/plugins/rpc
+ rm -rf /srv/rutorrent/plugins/geoip
rm -rf /srv/rutorrent/conf/config.php
echo_progress_done "ruTorrent cloned"
fi
@@ -26,26 +28,27 @@ function rutorrent_install() {
sed -i 's/pathToCreatetorrent = '\'\''/pathToCreatetorrent = '\''\/usr\/bin\/mktorrent'\''/' /srv/rutorrent/plugins/create/conf.php
sed -i "s/\$pathToExternals\['sox'\] = ''/\$pathToExternals\['sox'\] = '\/usr\/bin\/sox'/g" /srv/rutorrent/plugins/spectrogram/conf.php
- #shellcheck source=sources/functions/utils
. /etc/swizzin/sources/functions/utils
install_rar
- #if [[ ! -d /srv/rutorrent/plugins/theme/themes/club-QuickBox ]]; then
- # git clone https://github.com/QuickBox/club-QuickBox /srv/rutorrent/plugins/theme/themes/club-QuickBox >> "$log" 2>&1 || { echo_error "git of autodl plugin to main plugins seems to have failed"; }
- # perl -pi -e "s/\$defaultTheme \= \"\"\;/\$defaultTheme \= \"club-QuickBox\"\;/g" /srv/rutorrent/plugins/theme/conf.php
- #fi
-
if [[ ! -d /srv/rutorrent/plugins/filemanager ]]; then
- git clone https://github.com/nelu/rutorrent-filemanager /srv/rutorrent/plugins/filemanager >> ${log} 2>&1 || { echo_error "git of autodl plugin to main plugins seems to have failed"; }
+ git clone https://github.com/nelu/rutorrent-filemanager /srv/rutorrent/plugins/filemanager >> ${log} 2>&1 || {
+ echo_error "git of file-manager plugin to main plugins seems to have failed";
+ }
rutorrent_fm_config
- #pinning filemanager should no longer be required
- #git -C /srv/rutorrent/plugins/filemanager checkout 234f5f20841ad3d1e3c095e6c6954a875fc8a6ea >> ${log} 2>&1
fi
if [[ ! -d /srv/rutorrent/plugins/ratiocolor ]]; then
- cd /srv/rutorrent/plugins
- svn co https://github.com/Gyran/rutorrent-ratiocolor.git/trunk ratiocolor >> "$log" 2>&1
- sed -i "s/changeWhat = \"cell-background\";/changeWhat = \"font\";/g" /srv/rutorrent/plugins/ratiocolor/init.js || { echo_error "git of autodl plugin to main plugins seems to have failed"; }
+ git clone https://github.com/Gyran/rutorrent-ratiocolor /srv/rutorrent/plugins/ratiocolor >> "$log" 2>&1
+ sed -i "s/changeWhat = \"cell-background\";/changeWhat = \"font\";/g" /srv/rutorrent/plugins/ratiocolor/init.js || {
+ echo_error "git of ratio plugin to main plugins seems to have failed";
+ }
+ fi
+
+ if [[ ! -d /srv/rutorrent/plugins/geoip2 ]]; then
+ git clone https://github.com/Micdu70/geoip2-rutorrent /srv/rutorrent/plugins/geoip2 >> ${log} 2>&1 || {
+ echo_error "git of geoip2 plugin to main plugins seems to have failed";
+ }
fi
echo_progress_done "Plugins downloaded"
diff --git a/sources/functions/sonarr b/sources/functions/sonarr
new file mode 100644
index 000000000..c4b4fa9e7
--- /dev/null
+++ b/sources/functions/sonarr
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+_sonarr_version() {
+ if sonarrv="$(/usr/bin/mono /opt/Sonarr/Sonarr.exe \? |& head -n 1 | grep -Eo "Version(.*)$")"; then
+ [[ "$sonarrv" =~ ^(Version 0.2.(.*))$ ]] && echo "mono-v2"
+ [[ "$sonarrv" =~ ^(Version 3.0.(.*))$ ]] && echo "mono-v3"
+ elif sonarrv="$(/opt/Sonarr/Sonarr \? |& head -n 1 | grep -Eo "Version(.*)$")"; then
+ [[ "$sonarrv" =~ ^(Version 4.0.(.*))$ ]] && echo "dotnet-v4"
+ else
+ echo_log_only "Sonarr Version Error: No version could be determined"
+ fi
+}
\ No newline at end of file
diff --git a/sources/lang_en b/sources/lang_en
index 69effc119..fd2e0a6f2 100644
--- a/sources/lang_en
+++ b/sources/lang_en
@@ -7,14 +7,7 @@
*******************************************************************************/
// packages
-// $L['FFMPEG'] = '';
-// $L['FILEBROWSER'] = '';
-// $L['MEDUSA'] = '';
-// $L['NZBGET'] = '';
-// $L['QBITTORRENT'] = '';
-// $L['RCLONE'] = '';
-// $L['SICKCHILL'] = '';
-// $L['SICKGEAR'] = '';
+$L['AIRSONIC'] = 'Airsonic is a web-based audio player. It is a maintained forked of Subsonic, with the paid components modified to be free.';
$L['AUTOBRR'] = 'A powerful modern autodl alternative, which monitors IRC announce channels to get releases as soon as they are available and send to your favorite client.';
$L['AUTODL'] = 'A tool to help you automatically add torrents to your clients from IRC announce channels, filtering them through regex expressions.';
$L['BAZARR'] = 'The "-arr" tool to manage subtitles for items in Sonarr and Radarr.';
@@ -25,36 +18,45 @@ $L['CSF'] = 'ConfigServer Firewall, also known as CSF, is a firewall configurati
$L['DELUGE'] = 'Deluge is a lightweight, Free Software, cross-platform BitTorrent client.';
$L['DUCKDNS'] = 'An installer for a cron-job for the free dynamic DNS solution ';
$L['EMBY'] = 'Emby Server is a client-server software package that lets consumers host their legal personal copies of multimedia — music, video and picture files. ... The Emby client software is an app you need to install on mobile devices and certain settop boxes for televisions, like Android TV.';
+$L['FFMPEG'] = 'A complete, cross-platform solution to record, convert and stream audio and video.';
+$L['FILEBROWSER'] = 'A file manager that allows access, editing, and basic file and folder functions from a web browser.';
$L['FLOOD'] = 'A web frontend for rtorrent with a focus on simplicity and a pleasant GUI.';
$L['HEADPHONES'] = 'A music download manager.';
$L['JACKETT'] = 'API Support for your favorite private trackers.';
$L['JELLYFIN'] = 'A TV, Film and Music media streaming player, forked from Emby to keep it free and open-source.';
+$L['JFAGO'] = 'jfa-go is a user management app for Jellyfin (and now Emby) that provides invite-based account creation as well as other features that make one's instance much easier to manage.';
$L['LETSENCRYPT'] = 'A tool to generate and manage SSL Certificates the easy and automated way.';
$L['LIBRESPEED'] = 'Speed-test type utility which allows you to measure your upload and download against your machine.';
$L['LIDARR'] = 'Music management tool for both torrents and usenet.';
$L['LOUNGE'] = 'An always-on IRC client accessible through a web browser.';
$L['MANGO'] = 'A Mangadex manga downloader, organizer and reader.';
+$L['MEDUSA'] = 'Medusa is an automatic Video Library Manager for TV Shows.';
$L['MYLAR'] = 'An automated Comic Book (cbr/cbz) downloader program for use with NZB and torrents.';
$L['NAVIDROME'] = 'Navidrome is an open source web-based music collection server and streamer.';
$L['NETDATA'] = 'Monitoring and statistics tool for your server.';
$L['NEXTCLOUD'] = 'Nextcloud is an open source, self-hosted file sync and share and communication app platform. Access & sync your files, contacts, calendars & communicate and collaborate across your devices. You decide what happens with your data, where it is and who can access it!';
$L['NGINX'] = 'A web server which functions primarily as a reverse proxy in order to facilitate access to web-based applications without the need to remember port numbers.';
+$L['NZBGET'] = 'NZBGet is an efficient, open-source Usenet software designed for downloading binary content from Usenet newsgroups.';
$L['NZBHYDRA'] = 'NZBHydra is a meta search for NZB indexers. It provides easy access to a number of raw and newznab based indexers. You can search all your indexers from one place and use it as indexer source for tools like Sonarr or CouchPotato.';
$L['OMBI'] = 'A TV, film and music request system with multi-user support which interfaces against other media managers in order to automate and facilitate unified access to other users.';
$L['ORGANIZR'] = 'A Dashboard or a one-place-stop webpage for your applications which can heavily integrate into some installed media server and seedbox applications.';
$L['OVPN'] = 'SSL/TLS based user-space VPN. Supports Linux, Solaris, OpenBSD, FreeBSD, NetBSD, Mac OS X, and Windows 2000/XP+.';
$L['PANEL'] = 'Homegrown homepage for your server, swizzin style.';
-$L['PLEX_REQUESTS'] = 'Ombi offers a beautiful and easy to use interface for items users wish to be added to the library. Integrates with CouchPotato, SickRage and Sonarr.';
$L['PLEX'] = 'Plex lets you stream your content to any Plex enabled device.';
+$L['PROWLARR'] = 'Prowlarr is an indexer manager/proxy built on the popular arr .net/reactjs base stack to integrate with your various PVR apps. Prowlarr supports management of both Torrent Trackers and Usenet Indexers.';
$L['PYLOAD'] = 'pyLoad is a download manager for `Hoster` websites, video sites, and HTTP/FTP links. A list of supported sites can be found here';
+$L['QBITTORRENT'] = 'qBittorrent is an open-source software alternative to µTorrent based on the Qt toolkit and libtorrent-rasterbar library.';
$L['QUASSEL'] = 'Quassel IRC is a modern, cross-platform, distributed IRC client based on the Qt4 framework.';
-$L['QUOTAS'] = 'This feature of Linux allows the system administrator to allocate a maximum amount of disk space a user or group may use.';
+$L['QUOTA'] = 'This feature of Linux allows the system administrator to allocate a maximum amount of disk space a user or group may use.';
$L['RADARR'] = 'A Film management system which works with both torrents and usenet.';
$L['RAPIDLEECH'] = 'Rapid Leech is a free server transfer script for use on various popular upload/download sites such as uploaded.net, Rapidshare.com and more than 120 others.';
-// $L['RTORRENT'] = '';
+$L['RCLONE'] = 'Rclone is a feature-rich command-line program to manage files on cloud storage supporting over 70 cloud storage products.';
+$L['RTORRENT'] = 'rTorrent is a quick and efficient BitTorrent client written in C++ that uses the libTorrent library that provides a terminal-based user interface.';
$L['RUTORRENT'] = 'A web-based, multi-user capable interface for rtorrent overflowing with functionality and plugin extensibility ';
$L['SABNZBD'] = 'SABnzbd is a multi-platform binary newsgroup downloader. The program works in the background and simplifies the downloading verifying and extracting of files from Usenet. SABnzbd uses NZB files (similar to .torrent files, but for Usenet), instead of browsing Usenet directly.';
$L['SHELLINABOX'] = 'A web-based terminal for your machine.';
+$L['SICKCHILL'] = 'SickChill is an automatic Video Library Manager for TV Shows similarly to SickRage and SickBeard before it.';
+$L['SICKGEAR'] = 'SickGear, like others in the Sick* lineage, provides management of TV shows and/or Anime, it detects new episodes, links downloader apps, and more.';
$L['SICKRAGE'] = 'Video File Manager for TV Shows, It watches for new episodes of your favorite shows and when they are posted it does its magic.';
$L['SONARR'] = 'Sonarr is a tv series management tool which will work with both torrents and usenet.';
$L['SUBSONIC'] = 'Subsonic is a web-based media server. It is written in Java, so it can run on any operating system with Java support. Subsonic supports streaming to multiple clients simultaneously, and supports any streamable media (including MP3, AAC, and Ogg).';
diff --git a/sources/patches/rtorrent/fast-session-loading-0.9.8.patch b/sources/patches/rtorrent/fast-session-loading-0.9.8.patch
new file mode 100644
index 000000000..b8fb9945a
--- /dev/null
+++ b/sources/patches/rtorrent/fast-session-loading-0.9.8.patch
@@ -0,0 +1,73 @@
+From 41b8950ec54b61526361e5028475d680ccdf759c Mon Sep 17 00:00:00 2001
+From: stickz
+Date: Sun, 15 Oct 2023 18:54:10 -0400
+Subject: [PATCH] Speed up torrent session loading
+
+Don't check if torrents are being removed.
+Perform hash checks after session is loaded.
+---
+ src/control.cc | 2 --
+ src/core/download_factory.cc | 10 ++++++----
+ src/main.cc | 7 +++++++
+ 3 files changed, 13 insertions(+), 6 deletions(-)
+
+diff --git a/src/control.cc b/src/control.cc
+index 60c9b5301..89a7be071 100644
+--- a/src/control.cc
++++ b/src/control.cc
+@@ -114,8 +114,6 @@ Control::initialize() {
+ m_core->listen_open();
+ m_core->download_store()->enable(rpc::call_command_value("session.use_lock"));
+
+- m_core->set_hashing_view(*m_viewManager->find_throw("hashing"));
+-
+ m_ui->init(this);
+
+ if(!display::Canvas::daemon()) {
+diff --git a/src/core/download_factory.cc b/src/core/download_factory.cc
+index 2d2ea5a3b..2a147f5cf 100644
+--- a/src/core/download_factory.cc
++++ b/src/core/download_factory.cc
+@@ -323,11 +323,13 @@ DownloadFactory::receive_success() {
+ std::for_each(m_commands.begin(), m_commands.end(),
+ rak::bind2nd(std::ptr_fun(&rpc::parse_command_multiple_std), rpc::make_target(download)));
+
+- if (m_manager->download_list()->find(infohash) == m_manager->download_list()->end())
+- throw torrent::input_error("The newly created download was removed.");
+-
+ if (!m_session)
+- rpc::call_command("d.state.set", (int64_t)m_start, rpc::make_target(download));
++ {
++ if (m_manager->download_list()->find(infohash) == m_manager->download_list()->end())
++ throw torrent::input_error("The newly created download was removed.");
++
++ rpc::call_command("d.state.set", (int64_t)m_start, rpc::make_target(download));
++ }
+
+ rpc::commands.call_catch(m_session ? "event.download.inserted_session" : "event.download.inserted_new",
+ rpc::make_target(download), torrent::Object(), "Download event action failed: ");
+diff --git a/src/main.cc b/src/main.cc
+index c76558f8f..de8dcfe70 100644
+--- a/src/main.cc
++++ b/src/main.cc
+@@ -62,6 +62,7 @@
+ #include "core/download_factory.h"
+ #include "core/download_store.h"
+ #include "core/manager.h"
++#include "core/view_manager.h"
+ #include "display/canvas.h"
+ #include "display/window.h"
+ #include "display/manager.h"
+@@ -137,6 +138,12 @@ load_session_torrents() {
+ f->load(entries.path() + first->d_name);
+ f->commit();
+ }
++
++ // Perform hash checks after the session is loaded
++ const auto& hashing_view = *control->view_manager()->find_throw("hashing");
++ control->core()->set_hashing_view(hashing_view);
++ hashing_view->set_focus(hashing_view->focus());
++ priority_queue_perform(&taskScheduler, cachedTime);
+ }
+
+ void
diff --git a/sources/patches/rtorrent/libtorrent-udns-0.13.8.patch b/sources/patches/rtorrent/libtorrent-udns-0.13.8.patch
index c3b5552a7..2345386e8 100644
--- a/sources/patches/rtorrent/libtorrent-udns-0.13.8.patch
+++ b/sources/patches/rtorrent/libtorrent-udns-0.13.8.patch
@@ -402,7 +402,7 @@ index 93493e478..04d836f49 100644
- m_slot_resolver = make_resolver_slot(hostname);
+ m_resolver_query = manager->connection_manager()->async_resolver().enqueue(
+ hostname.data(),
-+ AF_INET,
++ AF_UNSPEC,
+ &m_resolver_callback
+ );
+ manager->connection_manager()->async_resolver().flush();
@@ -657,7 +657,7 @@ index 000000000..b53d32e8a
+ }
+ }
+
-+ if (family == AF_INET6 || family == AF_UNSPEC) {
++ if (family == AF_INET6) {
+ query->a6_query = ::dns_submit_a6(m_ctx, name, 0, a6_callback_wrapper, query);
+ if (query->a6_query == NULL) {
+ // it should be impossible for dns_submit_a6 to fail if dns_submit_a4
diff --git a/sources/patches/rtorrent/lookup-cache-0.13.8.patch b/sources/patches/rtorrent/lookup-cache-0.13.8.patch
new file mode 100644
index 000000000..26ab5a830
--- /dev/null
+++ b/sources/patches/rtorrent/lookup-cache-0.13.8.patch
@@ -0,0 +1,286 @@
+From 2ff6646c2710e244a4357e13c216cd01c4a53b0d Mon Sep 17 00:00:00 2001
+From: stickz
+Date: Sun, 15 Oct 2023 14:03:04 -0400
+Subject: [PATCH] Add libtorrent lookup cache
+
+Cache torrent hashes to reduce lookup times.
+---
+ src/dht/dht_hash_map.h | 59 ++---------------------
+ src/torrent/download/download_manager.cc | 61 +++++++++++++++---------
+ src/torrent/download/download_manager.h | 7 +++
+ src/torrent/hash_string.h | 38 +++++++++++++++
+ 4 files changed, 88 insertions(+), 77 deletions(-)
+
+diff --git a/src/dht/dht_hash_map.h b/src/dht/dht_hash_map.h
+index 140f070bb..3b566a7ab 100644
+--- a/src/dht/dht_hash_map.h
++++ b/src/dht/dht_hash_map.h
+@@ -53,60 +53,9 @@
+ namespace torrent {
+
+ #if HAVE_TR1
+-// Hash functions for HashString keys, and dereferencing HashString pointers.
+-
+-// Since the first few bits are very similar if not identical (since the IDs
+-// will be close to our own node ID), we use an offset of 64 bits in the hash
+-// string. These bits will be uniformly distributed until the number of DHT
+-// nodes on the planet approaches 2^64 which is... unlikely.
+-// An offset of 64 bits provides 96 significant bits which is fine as long as
+-// the size of size_t does not exceed 12 bytes, while still having correctly
+-// aligned 64-bit access.
+-static const unsigned int hashstring_hash_ofs = 8;
+-
+-struct hashstring_ptr_hash : public std::unary_function {
+- size_t operator () (const HashString* n) const {
+-#if USE_ALIGNED
+- size_t result = 0;
+- const char *first = n->data() + hashstring_hash_ofs;
+- const char *last = first + sizeof(size_t);
+-
+- while (first != last)
+- result = (result << 8) + *first++;
+-
+- return result;
+-#else
+- return *(size_t*)(n->data() + hashstring_hash_ofs);
+-#endif
+- }
+-};
+-
+-struct hashstring_hash : public std::unary_function {
+- size_t operator () (const HashString& n) const {
+-#if USE_ALIGNED
+- size_t result = 0;
+- const char *first = n.data() + hashstring_hash_ofs;
+- const char *last = first + sizeof(size_t);
+-
+- while (first != last)
+- result = (result << 8) + *first++;
+-
+- return result;
+-#else
+- return *(size_t*)(n.data() + hashstring_hash_ofs);
+-#endif
+- }
+-};
+-
+-// Compare HashString pointers by dereferencing them.
+-struct hashstring_ptr_equal : public std::binary_function {
+- size_t operator () (const HashString* one, const HashString* two) const
+- { return *one == *two; }
+-};
+-
+-class DhtNodeList : public std::unordered_map {
++class DhtNodeList : public std::unordered_map {
+ public:
+- typedef std::unordered_map base_type;
++ using base_type = std::unordered_map;
+
+ // Define accessor iterator with more convenient access to the key and
+ // element values. Allows changing the map definition more easily if needed.
+@@ -125,9 +74,9 @@ class DhtNodeList : public std::unordered_map {
++class DhtTrackerList : public std::unordered_map {
+ public:
+- typedef std::unordered_map base_type;
++ using base_type = std::unordered_map;
+
+ template
+ struct accessor_wrapper : public T {
+diff --git a/src/torrent/download/download_manager.cc b/src/torrent/download/download_manager.cc
+index 6df2792c6..e4ba9c089 100644
+--- a/src/torrent/download/download_manager.cc
++++ b/src/torrent/download/download_manager.cc
+@@ -50,37 +50,58 @@ DownloadManager::insert(DownloadWrapper* d) {
+ if (find(d->info()->hash()) != end())
+ throw internal_error("Could not add torrent as it already exists.");
+
++ lookup_cache.emplace(d->info()->hash(), size());
++ obfuscated_to_hash.emplace(d->info()->hash_obfuscated(), d->info()->hash());
++
+ return base_type::insert(end(), d);
+ }
+
+ DownloadManager::iterator
+ DownloadManager::erase(DownloadWrapper* d) {
+- iterator itr = std::find(begin(), end(), d);
++ auto itr = find(d->info()->hash());
+
+ if (itr == end())
+ throw internal_error("Tried to remove a torrent that doesn't exist");
+
++ lookup_cache.erase(lookup_cache.find(d->info()->hash()));
++ obfuscated_to_hash.erase(obfuscated_to_hash.find(d->info()->hash_obfuscated()));
++
+ delete *itr;
+ return base_type::erase(itr);
+ }
+
+ void
+ DownloadManager::clear() {
+- while (!empty()) {
+- delete base_type::back();
+- base_type::pop_back();
+- }
++ base_type::clear();
++ lookup_cache.clear();
++ obfuscated_to_hash.clear();
+ }
+
+ DownloadManager::iterator
+ DownloadManager::find(const std::string& hash) {
+- return std::find_if(begin(), end(), rak::equal(*HashString::cast_from(hash),
+- rak::on(std::mem_fun(&DownloadWrapper::info), std::mem_fun(&DownloadInfo::hash))));
++ return find(*HashString::cast_from(hash));
+ }
+
+ DownloadManager::iterator
+ DownloadManager::find(const HashString& hash) {
+- return std::find_if(begin(), end(), rak::equal(hash, rak::on(std::mem_fun(&DownloadWrapper::info), std::mem_fun(&DownloadInfo::hash))));
++ auto cached = lookup_cache.find(hash);
++
++ if (cached == lookup_cache.end()) {
++ return end();
++ }
++
++ auto cached_i = cached->second;
++
++ auto itr = cached_i < size() ? begin() + cached_i : end();
++ if (itr == end() || (*itr)->info()->hash() != hash) {
++ itr = std::find_if(begin(), end(), [hash](DownloadWrapper* wrapper) {
++ return hash == wrapper->info()->hash();
++ });
++ }
++
++ lookup_cache[hash] = itr - begin();
++
++ return itr;
+ }
+
+ DownloadManager::iterator
+@@ -95,24 +116,20 @@ DownloadManager::find_chunk_list(ChunkList* cl) {
+
+ DownloadMain*
+ DownloadManager::find_main(const char* hash) {
+- iterator itr = std::find_if(begin(), end(), rak::equal(*HashString::cast_from(hash),
+- rak::on(std::mem_fun(&DownloadWrapper::info), std::mem_fun(&DownloadInfo::hash))));
+-
+- if (itr == end())
+- return NULL;
+- else
+- return (*itr)->main();
++ auto itr = find(*HashString::cast_from(hash));
++ return itr == end() ? NULL : (*itr)->main();
+ }
+
+ DownloadMain*
+-DownloadManager::find_main_obfuscated(const char* hash) {
+- iterator itr = std::find_if(begin(), end(), rak::equal(*HashString::cast_from(hash),
+- rak::on(std::mem_fun(&DownloadWrapper::info), std::mem_fun(&DownloadInfo::hash_obfuscated))));
++DownloadManager::find_main_obfuscated(const char* obfuscated) {
++ auto hash_itr = obfuscated_to_hash.find(*HashString::cast_from(obfuscated));
+
+- if (itr == end())
+- return NULL;
+- else
+- return (*itr)->main();
++ if (hash_itr == obfuscated_to_hash.end()) {
++ return nullptr;
++ }
++
++ auto itr = find(hash_itr->second);
++ return itr == end() ? NULL : (*itr)->main();
+ }
+
+ }
+diff --git a/src/torrent/download/download_manager.h b/src/torrent/download/download_manager.h
+index 4dba916cd..b864e8e22 100644
+--- a/src/torrent/download/download_manager.h
++++ b/src/torrent/download/download_manager.h
+@@ -37,8 +37,11 @@
+ #ifndef LIBTORRENT_DOWNLOAD_MANAGER_H
+ #define LIBTORRENT_DOWNLOAD_MANAGER_H
+
++#include
+ #include
++
+ #include
++#include
+
+ namespace torrent {
+
+@@ -90,6 +93,10 @@ class LIBTORRENT_EXPORT DownloadManager : private std::vector
+ iterator erase(DownloadWrapper* d) LIBTORRENT_NO_EXPORT;
+
+ void clear() LIBTORRENT_NO_EXPORT;
++
++ private:
++ std::unordered_map lookup_cache;
++ std::unordered_map obfuscated_to_hash;
+ };
+
+ }
+diff --git a/src/torrent/hash_string.h b/src/torrent/hash_string.h
+index af60780a2..22150fca0 100644
+--- a/src/torrent/hash_string.h
++++ b/src/torrent/hash_string.h
+@@ -61,6 +61,10 @@ class LIBTORRENT_EXPORT HashString {
+
+ static const size_type size_data = 20;
+
++ static constexpr unsigned int hashstring_hash_ofs = 8;
++ static_assert((hashstring_hash_ofs + sizeof(size_t)) <=
++ HashString::size_data);
++
+ size_type size() const { return size_data; }
+
+ iterator begin() { return m_data; }
+@@ -99,6 +103,14 @@ class LIBTORRENT_EXPORT HashString {
+
+ static HashString* cast_from(char* src) { return (HashString*)src; }
+
++ size_t hash() const {
++ size_t result = 0;
++ std::memcpy(&result,
++ m_data + torrent::HashString::hashstring_hash_ofs,
++ sizeof(size_t));
++ return result;
++ }
++
+ private:
+ char m_data[size_data];
+ };
+@@ -132,4 +144,30 @@ operator <= (const HashString& one, const HashString& two) {
+
+ }
+
++namespace std {
++
++template<>
++struct hash {
++ std::size_t operator()(const torrent::HashString& n) const noexcept {
++ return n.hash();
++ }
++};
++
++template<>
++struct hash {
++ std::size_t operator()(const torrent::HashString* n) const noexcept {
++ return n->hash();
++ }
++};
++
++template<>
++struct equal_to {
++ bool operator()(const torrent::HashString* a,
++ const torrent::HashString* b) const noexcept {
++ return *a == *b;
++ }
++};
++
++}
++
+ #endif
diff --git a/sources/patches/rtorrent/rtorrent-ml-fixes-0.9.8.patch b/sources/patches/rtorrent/rtorrent-ml-fixes-0.9.8.patch
new file mode 100644
index 000000000..b8b209be4
--- /dev/null
+++ b/sources/patches/rtorrent/rtorrent-ml-fixes-0.9.8.patch
@@ -0,0 +1,114 @@
+From ece7a0338d50bffa68993454697b86a055c54a6f Mon Sep 17 00:00:00 2001
+From: stickz
+Date: Wed, 4 Oct 2023 07:12:02 -0400
+Subject: [PATCH] Fix various memory leaks
+
+Resolves a potential memory leak with the curses UI when filtering torrents.
+
+Resolves a memory leak with dynamic commands in the .rtorrent.rc file.
+
+Resolves a memory leak during software initialization with choke groups.
+---
+ src/command_dynamic.cc | 2 +-
+ src/command_groups.cc | 11 +++++++++++
+ src/command_helpers.cc | 6 ++++++
+ src/command_helpers.h | 1 +
+ src/main.cc | 2 ++
+ src/ui/download_list.cc | 2 ++
+ 6 files changed, 23 insertions(+), 1 deletion(-)
+
+diff --git a/src/command_dynamic.cc b/src/command_dynamic.cc
+index a8d0ff02f..3d7a123b1 100644
+--- a/src/command_dynamic.cc
++++ b/src/command_dynamic.cc
+@@ -147,7 +147,7 @@ system_method_insert_object(const torrent::Object::list_type& args, int flags) {
+ throw torrent::input_error("Invalid type.");
+ }
+
+- int cmd_flags = 0;
++ int cmd_flags = rpc::CommandMap::flag_delete_key;
+
+ if (!(flags & rpc::object_storage::flag_static))
+ cmd_flags |= rpc::CommandMap::flag_modifiable;
+diff --git a/src/command_groups.cc b/src/command_groups.cc
+index 359a532e5..cb8bdb584 100644
+--- a/src/command_groups.cc
++++ b/src/command_groups.cc
+@@ -381,3 +381,14 @@ initialize_command_groups() {
+ std::bind(&torrent::choke_queue::heuristics, CHOKE_GROUP(&torrent::choke_group::down_queue))));
+ CMD2_ANY_LIST ("choke_group.down.heuristics.set", std::bind(&apply_cg_heuristics_set, std::placeholders::_2, false));
+ }
++
++void cleanup_command_groups() {
++#if USE_CHOKE_GROUP
++#else
++ while (!cg_list_hack.empty()) {
++ auto cg = cg_list_hack.back();
++ delete cg;
++ cg_list_hack.pop_back();
++ }
++#endif
++}
+\ No newline at end of file
+diff --git a/src/command_helpers.cc b/src/command_helpers.cc
+index 54c0b35e4..31599e265 100644
+--- a/src/command_helpers.cc
++++ b/src/command_helpers.cc
+@@ -57,6 +57,12 @@ void initialize_command_tracker();
+ void initialize_command_scheduler();
+ void initialize_command_ui();
+
++void cleanup_command_groups();
++
++void cleanup_commands() {
++ cleanup_command_groups();
++}
++
+ void
+ initialize_commands() {
+ initialize_command_dynamic();
+diff --git a/src/command_helpers.h b/src/command_helpers.h
+index a104fbbc4..48e7ea258 100644
+--- a/src/command_helpers.h
++++ b/src/command_helpers.h
+@@ -42,6 +42,7 @@
+ #include "rpc/object_storage.h"
+
+ void initialize_commands();
++void cleanup_commands();
+
+ //
+ // New std::function based command_base helper functions:
+diff --git a/src/main.cc b/src/main.cc
+index 6be6a4dee..2310013dc 100644
+--- a/src/main.cc
++++ b/src/main.cc
+@@ -509,6 +509,8 @@ main(int argc, char** argv) {
+ return -1;
+ }
+
++ cleanup_commands();
++
+ torrent::log_cleanup();
+
+ delete control;
+diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc
+index f1d6af5c6..7cb0e9a89 100644
+--- a/src/ui/download_list.cc
++++ b/src/ui/download_list.cc
+@@ -272,6 +272,7 @@ DownloadList::receive_view_input(Input type) {
+ std::getline(ss, view_name_var, ',');
+ if (current_view()->name() == rak::trim(view_name_var)) {
+ control->core()->push_log_std("View '" + current_view()->name() + "' can't be filtered.");
++ delete input;
+ return;
+ }
+ }
+@@ -281,6 +282,7 @@ DownloadList::receive_view_input(Input type) {
+ break;
+
+ default:
++ delete input;
+ throw torrent::internal_error("DownloadList::receive_view_input(...) Invalid input type.");
+ }
+
diff --git a/sources/patches/rtorrent/scgi-fix.patch b/sources/patches/rtorrent/scgi-fix.patch
new file mode 100644
index 000000000..ed44b6453
--- /dev/null
+++ b/sources/patches/rtorrent/scgi-fix.patch
@@ -0,0 +1,23 @@
+From f600ba802201da20834751412faafa374ce255c4 Mon Sep 17 00:00:00 2001
+From: stickz
+Date: Sat, 30 Sep 2023 08:36:15 -0400
+Subject: [PATCH] Increase maximum SCGI request to 16MB
+
+Fixing a problem where xmlrpc-c information fails to update if user is running too many torrents.
+---
+ src/rpc/scgi_task.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/rpc/scgi_task.h b/src/rpc/scgi_task.h
+index e75e9e1ea..a42349bf8 100644
+--- a/src/rpc/scgi_task.h
++++ b/src/rpc/scgi_task.h
+@@ -51,7 +51,7 @@ class SCgiTask : public torrent::Event {
+ public:
+ static const unsigned int default_buffer_size = 2047;
+ static const int max_header_size = 2000;
+- static const int max_content_size = (2 << 20);
++ static const int max_content_size = (2 << 23);
+
+ SCgiTask() { m_fileDesc = -1; }
+
diff --git a/sources/patches/rtorrent/session-file-fix.patch b/sources/patches/rtorrent/session-file-fix.patch
new file mode 100644
index 000000000..91b67e3a9
--- /dev/null
+++ b/sources/patches/rtorrent/session-file-fix.patch
@@ -0,0 +1,46 @@
+From 7594fc942ecd0ed64f7feea24bd54b6fdddba49b Mon Sep 17 00:00:00 2001
+From: stickz
+Date: Sat, 30 Sep 2023 10:34:07 -0400
+Subject: [PATCH] Fix saving session files
+
+Resolves a data corruption issue with torrent session during a power loss.
+---
+ src/core/download_store.cc | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/src/core/download_store.cc b/src/core/download_store.cc
+index 536dba10a..e111b41bc 100644
+--- a/src/core/download_store.cc
++++ b/src/core/download_store.cc
+@@ -40,6 +40,7 @@
+
+ #include
+ #include
++#include
+ #include
+ #include
+ #include
+@@ -102,6 +103,7 @@ bool
+ DownloadStore::write_bencode(const std::string& filename, const torrent::Object& obj, uint32_t skip_mask) {
+ torrent::Object tmp;
+ std::fstream output(filename.c_str(), std::ios::out | std::ios::trunc);
++ int fd = -1;
+
+ if (!output.is_open())
+ goto download_store_save_error;
+@@ -121,6 +123,15 @@ DownloadStore::write_bencode(const std::string& filename, const torrent::Object&
+ goto download_store_save_error;
+
+ output.close();
++
++ // Ensure that the new file is actually written to the disk
++ fd = ::open(filename.c_str(), O_WRONLY);
++ if (fd < 0)
++ goto download_store_save_error;
++
++ fsync(fd);
++ ::close(fd);
++
+ return true;
+
+ download_store_save_error:
diff --git a/sources/patches/rtorrent/xmlrpc-logic-fix.patch b/sources/patches/rtorrent/xmlrpc-logic-fix.patch
new file mode 100644
index 000000000..97f83c287
--- /dev/null
+++ b/sources/patches/rtorrent/xmlrpc-logic-fix.patch
@@ -0,0 +1,23 @@
+From 898d0b21792c9f021a098961c6d47e07a4b188f1 Mon Sep 17 00:00:00 2001
+From: stickz
+Date: Mon, 2 Oct 2023 17:02:06 -0400
+Subject: [PATCH] Resolve xmlrpc logic crash
+
+Resolves a rtorrent crash caused by sending invalid xmlrpc logic.
+---
+ src/rpc/command_impl.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/rpc/command_impl.h b/src/rpc/command_impl.h
+index b7ec9168c..a7838d49c 100644
+--- a/src/rpc/command_impl.h
++++ b/src/rpc/command_impl.h
+@@ -63,7 +63,7 @@ template <> struct target_type_id { static con
+ template <> inline bool
+ is_target_compatible(const target_type& target) { return true; }
+ template <> inline bool
+-is_target_compatible(const target_type& target) { return target.first == command_base::target_file || command_base::target_file_itr; }
++is_target_compatible(const target_type& target) { return (target.first == command_base::target_file || command_base::target_file_itr) && target.first == target_type_id::value; }
+
+ template <> inline target_type
+ get_target_cast(target_type target, int type) { return target; }
diff --git a/unattended.example.env b/unattended.example.env
index 00b90e4d9..83c1b1bc6 100644
--- a/unattended.example.env
+++ b/unattended.example.env
@@ -19,6 +19,9 @@ QBITTORRENT_VERSION="latest"
## transmission flags (https://docs.swizzin.ltd/applications/transmission#install-options)
TRANSMISSION_VERSION="Repo"
+## rtorrent flags (https://swizzin.ltd/applications/rtorrent/#initial-setup)
+RTORRENT_VERSION="0.9.8"
+
## LetsEncrypt options ((https://docs.swizzin.ltd/applications/letsencrypt#install-options))
LE_HOSTNAME="domain.tld"
LE_DEFAULTCONF=yes