mirror of
https://github.com/Ernous/TorrServerJellyfin.git
synced 2025-12-15 20:06:10 +05:00
- rewrite installTorrServerLinux.sh with structured CLI parsing, localization, glibc checks, and silent-mode support - update Linux instructions in README.md with new non-interactive examples, version pinning, user switching, and port overrides Signed-off-by: Pavel Pikta <devops@pavelpikta.com>
1667 lines
47 KiB
Bash
Executable File
1667 lines
47 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
|
||
set -euo pipefail
|
||
|
||
#############################################
|
||
# GLOBAL VARIABLES
|
||
#############################################
|
||
|
||
# Installation settings
|
||
DEFAULT_USERNAME="torrserver"
|
||
DEFAULT_INSTALL_DIR="/opt/torrserver"
|
||
DEFAULT_SERVICE_NAME="torrserver"
|
||
DEFAULT_PORT="8090"
|
||
|
||
# Runtime variables
|
||
username="${DEFAULT_USERNAME}"
|
||
dirInstall="${DEFAULT_INSTALL_DIR}"
|
||
serviceName="${DEFAULT_SERVICE_NAME}"
|
||
scriptname=$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")
|
||
|
||
# Flags
|
||
SILENT_MODE=0
|
||
USE_ROOT_USER=0
|
||
ROOT_PROMPTED=0
|
||
|
||
# Command-line state
|
||
parsedCommand=""
|
||
specificVersion=""
|
||
downgradeRelease=""
|
||
changeUserName=""
|
||
|
||
# Service configuration
|
||
servicePort=""
|
||
isAuth=""
|
||
isRdb=""
|
||
isLog=""
|
||
isAuthUser=""
|
||
isAuthPass=""
|
||
|
||
# Constants
|
||
readonly REPO_URL="https://github.com/YouROK/TorrServer"
|
||
readonly REPO_API_URL="https://api.github.com/repos/YouROK/TorrServer"
|
||
readonly VERSION_PREFIX="MatriX"
|
||
readonly BINARY_NAME_PREFIX="TorrServer-linux"
|
||
readonly MIN_GLIBC_VERSION="2.32"
|
||
readonly MIN_VERSION_REQUIRING_GLIBC=136
|
||
|
||
# Color support
|
||
declare -A colors=([black]=0 [red]=1 [green]=2 [yellow]=3 [blue]=4 [magenta]=5 [cyan]=6 [white]=7)
|
||
supports_color_output=0
|
||
|
||
if command -v tput >/dev/null 2>&1 && [[ -t 1 ]]; then
|
||
if [[ $(tput colors 2>/dev/null) -ge 8 ]]; then
|
||
supports_color_output=1
|
||
fi
|
||
fi
|
||
|
||
# Language
|
||
lang="en"
|
||
|
||
#############################################
|
||
# TRANSLATION SYSTEM
|
||
#############################################
|
||
|
||
# Message dictionary
|
||
declare -A MSG_EN=(
|
||
# General
|
||
[lang_choice]="Choose Language:"
|
||
[lang_english]="English"
|
||
[lang_russian]="Русский"
|
||
[your_lang]="Your language (Ваш язык): "
|
||
[have_fun]="Have Fun!"
|
||
|
||
# Script info
|
||
[script_title]="TorrServer install and configuration script for Linux"
|
||
[help_hint]="Enter $scriptname -h or --help or help for all available commands"
|
||
|
||
# Checks
|
||
[check_internet]="Check Internet access…"
|
||
[have_internet]="Have Internet Access"
|
||
[no_internet]="No Internet. Check your network and DNS settings."
|
||
[need_root]="Script must run as root or user with sudo privileges. Example: sudo $scriptname"
|
||
[need_ping]="Please install iputils-ping first"
|
||
[unsupported_arch]="Unsupported Arch. Can't continue."
|
||
[unsupported_os]="It looks like you are running this installer on a system other than Debian, Ubuntu, Fedora, CentOS, Amazon Linux, Oracle Linux or Arch Linux."
|
||
|
||
# User management
|
||
[user_exists]="User %s exists!"
|
||
[user_added]="User %s has been added to system!"
|
||
[user_add_failed]="Failed to add %s user!"
|
||
[user_removed]="User %s has been removed from system!"
|
||
[user_remove_failed]="Failed to remove %s user!"
|
||
[user_not_found]="%s - no such user!"
|
||
|
||
# Version
|
||
[downloading]="Downloading TorrServer"
|
||
[target_version]="Target version:"
|
||
[installed_version]="installed:"
|
||
[target_label]="target:"
|
||
[version_not_found]="ERROR: Version %s not found in releases"
|
||
[check_versions]="Please check available versions at: $REPO_URL/releases"
|
||
[already_installed]="You already have TorrServer %s installed"
|
||
[have_latest]="You have latest TorrServer %s"
|
||
[update_found]="TorrServer update found!"
|
||
[will_install]="Will install TorrServer version %s"
|
||
|
||
# Installation
|
||
[installing_packages]="Installing missing packages…"
|
||
[install_configure]="Install and configure TorrServer…"
|
||
[starting_service]="Starting TorrServer…"
|
||
[install_complete]="TorrServer %s installed to %s"
|
||
[access_web]="You can now open your browser at http://%s:%s to access TorrServer web GUI."
|
||
[use_auth]="Use user \"%s\" with password \"%s\" for authentication"
|
||
|
||
# Prompts
|
||
[want_update]="Want to update TorrServer? (Yes/No) "
|
||
[want_install]="Want to install or configure TorrServer? (Yes|No) Type Delete to uninstall. "
|
||
[change_port]="Change TorrServer web-port? (Yes/No) "
|
||
[enter_port]="Enter port number: "
|
||
[enable_auth]="Enable server authorization? (Yes/No) "
|
||
[prompt_user]="User: "
|
||
[prompt_password]="Password: "
|
||
[enable_rdb]="Start TorrServer in public read-only mode? (Yes/No) "
|
||
[enable_log]="Enable TorrServer log output to file? (Yes/No) "
|
||
[confirm_delete]="Are you sure you want to delete TorrServer? (Yes/No) "
|
||
[yes_no_delete]="Enter Yes, No or Delete"
|
||
|
||
# Uninstall
|
||
[install_dir_label]="TorrServer install dir -"
|
||
[uninstall_warning]="This action will delete TorrServer including all it's torrents, settings and files on path above!"
|
||
[uninstalled]="TorrServer uninstalled!"
|
||
|
||
# Status
|
||
[found_in]="TorrServer found in"
|
||
[not_found]="TorrServer not found. It's not installed or have zero size."
|
||
[no_version_info]="No version information available. Can be server issue."
|
||
[store_auth]="Store %s:%s to %s"
|
||
[use_existing_auth]="Use existing auth from %s - %s"
|
||
[set_readonly]="Set database to read-only mode…"
|
||
[readonly_hint]="To change remove --rdb option from %s or rerun install script without parameters"
|
||
[log_location]="TorrServer log stored at %s"
|
||
[systemctl_missing]="systemctl is not available. Skipping service management commands."
|
||
[systemctl_failed]="Warning: systemctl %s failed"
|
||
[service_start_failed]="Warning: TorrServer service failed to start. Check systemctl status for details."
|
||
[user_change_success]="Service user changed to %s"
|
||
[user_change_permissions]="Updated ownership of %s to %s:%s"
|
||
[user_change_missing]="TorrServer installation not found in %s. Run install first."
|
||
[user_change_invalid]="Only %s or %s are allowed for --change-user"
|
||
|
||
# glibc
|
||
[glibc_error]="ERROR: TorrServer version %s requires glibc >= $MIN_GLIBC_VERSION"
|
||
[glibc_current]="Your system has glibc %s"
|
||
[glibc_upgrade]="Please install a version < $MIN_VERSION_REQUIRING_GLIBC or upgrade your system"
|
||
[glibc_detected]="Detected glibc version: %s"
|
||
[glibc_ok]="OK: glibc version meets requirements for TorrServer %s"
|
||
[glibc_no_requirement]="TorrServer version %s: no special glibc requirements"
|
||
[glibc_warning]="Warning: Could not detect glibc version"
|
||
[glibc_may_fail]="TorrServer version %s requires glibc >= $MIN_GLIBC_VERSION"
|
||
[glibc_install_may_fail]="Installation may fail if your system doesn't meet this requirement"
|
||
[update_cancelled]="Update cancelled due to glibc incompatibility"
|
||
[downgrade_cancelled]="Downgrade cancelled due to glibc incompatibility"
|
||
|
||
# OS version errors
|
||
[os_not_supported]="Your %s version is not supported."
|
||
[os_script_supports]="Script supports only %s %s"
|
||
|
||
# User mode
|
||
[running_as_root]="Service will run as root user"
|
||
[running_as_user]="Service will run as %s user"
|
||
)
|
||
|
||
declare -A MSG_RU=(
|
||
# General
|
||
[lang_choice]="Choose Language:"
|
||
[lang_english]="English"
|
||
[lang_russian]="Русский"
|
||
[your_lang]="Your language (Ваш язык): "
|
||
[have_fun]="Have Fun!"
|
||
|
||
# Script info
|
||
[script_title]="Скрипт установки, удаления и настройки TorrServer для Linux"
|
||
[help_hint]="Наберите $scriptname -h или --help или help для вызова справки всех доступных команд"
|
||
|
||
# Checks
|
||
[check_internet]="Проверяем соединение с Интернетом…"
|
||
[have_internet]="соединение с Интернетом успешно"
|
||
[no_internet]="Нет Интернета. Проверьте ваше соединение, а также разрешение имен DNS."
|
||
[need_root]="Вам нужно запустить скрипт от root или пользователя с правами sudo. Пример: sudo $scriptname"
|
||
[need_ping]="Сначала установите iputils-ping"
|
||
[unsupported_arch]="Не поддерживаемая архитектура. Продолжение невозможно."
|
||
[unsupported_os]="Похоже, что вы запускаете этот установщик в системе отличной от Debian, Ubuntu, Fedora, CentOS, Amazon Linux, Oracle Linux или Arch Linux."
|
||
|
||
# User management
|
||
[user_exists]="пользователь %s найден!"
|
||
[user_added]="пользователь %s добавлен!"
|
||
[user_add_failed]="не удалось добавить пользователя %s!"
|
||
[user_removed]="Пользователь %s удален!"
|
||
[user_remove_failed]="не удалось удалить пользователя %s!"
|
||
[user_not_found]="пользователь %s не найден!"
|
||
|
||
# Version
|
||
[downloading]="Загружаем TorrServer"
|
||
[target_version]="Устанавливаемая версия:"
|
||
[installed_version]="установлен:"
|
||
[target_label]="устанавливаемая:"
|
||
[version_not_found]="ОШИБКА: Версия %s не найдена в релизах"
|
||
[check_versions]="Проверьте доступные версии по адресу: $REPO_URL/releases"
|
||
[already_installed]="TorrServer %s уже установлен"
|
||
[have_latest]="Установлен TorrServer последней версии %s"
|
||
[update_found]="Доступно обновление сервера"
|
||
[will_install]="Будет установлена версия TorrServer %s"
|
||
|
||
# Installation
|
||
[installing_packages]="Устанавливаем недостающие пакеты…"
|
||
[install_configure]="Устанавливаем и настраиваем TorrServer…"
|
||
[starting_service]="Запускаем службу TorrServer…"
|
||
[install_complete]="TorrServer %s установлен в директории %s"
|
||
[access_web]="Теперь вы можете открыть браузер по адресу http://%s:%s для доступа к вебу TorrServer"
|
||
[use_auth]="Для авторизации используйте пользователя «%s» с паролем «%s»"
|
||
|
||
# Prompts
|
||
[want_update]="Хотите обновить TorrServer? (Yes/No) "
|
||
[want_install]="Хотите установить, обновить или настроить TorrServer? (Yes|No) Для удаления введите «Delete» "
|
||
[change_port]="Хотите изменить порт для TorrServer? (Yes/No) "
|
||
[enter_port]="Введите номер порта: "
|
||
[enable_auth]="Включить авторизацию на сервере? (Yes/No) "
|
||
[prompt_user]="Пользователь: "
|
||
[prompt_password]="Пароль: "
|
||
[enable_rdb]="Запускать TorrServer в публичном режиме без возможности изменения настроек через веб сервера? (Yes/No) "
|
||
[enable_log]="Включить запись журнала работы TorrServer в файл? (Yes/No) "
|
||
[confirm_delete]="Вы уверены что хотите удалить программу? (Yes/No) "
|
||
[yes_no_delete]="Ввведите Yes, No или Delete"
|
||
|
||
# Uninstall
|
||
[install_dir_label]="Директория c TorrServer -"
|
||
[uninstall_warning]="Это действие удалит все данные TorrServer включая базу данных торрентов и настройки по указанному выше пути!"
|
||
[uninstalled]="TorrServer удален из системы!"
|
||
|
||
# Status
|
||
[found_in]="TorrServer найден в директории"
|
||
[not_found]="TorrServer не найден, возможно он не установлен или размер бинарника равен 0."
|
||
[no_version_info]="Информация о версии недоступна. Возможно сервер не доступен."
|
||
[store_auth]="Сохраняем %s:%s в %s"
|
||
[use_existing_auth]="Используйте реквизиты из %s для авторизации - %s"
|
||
[set_readonly]="База данных устанавливается в режим «только для чтения»…"
|
||
[readonly_hint]="Для изменения отредактируйте %s, убрав опцию --rdb или запустите интерактивную установку без параметров повторно"
|
||
[log_location]="лог TorrServer располагается по пути %s"
|
||
[systemctl_missing]="systemctl недоступен. Пропускаем команды управления службой."
|
||
[systemctl_failed]="Предупреждение: команда systemctl %s завершилась ошибкой"
|
||
[service_start_failed]="Предупреждение: служба TorrServer не запустилась. Проверьте systemctl status для деталей."
|
||
[user_change_success]="Сервис TorrServer теперь запускается от пользователя %s"
|
||
[user_change_permissions]="Обновлены права на %s: %s:%s"
|
||
[user_change_missing]="Установка TorrServer не найдена в %s. Сначала выполните установку."
|
||
[user_change_invalid]="Параметр --change-user принимает только %s или %s"
|
||
|
||
# glibc
|
||
[glibc_error]="ОШИБКА: TorrServer версии %s требует glibc >= $MIN_GLIBC_VERSION"
|
||
[glibc_current]="В вашей системе установлена glibc %s"
|
||
[glibc_upgrade]="Пожалуйста, установите версию < $MIN_VERSION_REQUIRING_GLIBC или обновите систему"
|
||
[glibc_detected]="Обнаружена версия glibc: %s"
|
||
[glibc_ok]="OK: версия glibc соответствует требованиям для TorrServer %s"
|
||
[glibc_no_requirement]="TorrServer версии %s: нет особых требований к glibc"
|
||
[glibc_warning]="Предупреждение: Не удалось определить версию glibc"
|
||
[glibc_may_fail]="TorrServer версии %s требует glibc >= $MIN_GLIBC_VERSION"
|
||
[glibc_install_may_fail]="Установка может завершиться неудачей, если система не соответствует требованиям"
|
||
[update_cancelled]="Обновление отменено из-за несовместимости glibc"
|
||
[downgrade_cancelled]="Понижение версии отменено из-за несовместимости glibc"
|
||
|
||
# OS version errors
|
||
[os_not_supported]="Ваша версия %s не поддерживается."
|
||
[os_script_supports]="Скрипт поддерживает только %s %s"
|
||
|
||
# User mode
|
||
[running_as_root]="Служба будет запущена от пользователя root"
|
||
[running_as_user]="Служба будет запущена от пользователя %s"
|
||
)
|
||
|
||
# Translation function
|
||
msg() {
|
||
local key="$1"
|
||
shift
|
||
local message=""
|
||
|
||
if [[ $lang == "ru" ]]; then
|
||
message="${MSG_RU[$key]:-$key}"
|
||
else
|
||
message="${MSG_EN[$key]:-$key}"
|
||
fi
|
||
|
||
# Apply printf formatting if additional arguments provided
|
||
if [[ $# -gt 0 ]]; then
|
||
# shellcheck disable=SC2059
|
||
printf "$message" "$@"
|
||
else
|
||
printf '%s\n' "$message"
|
||
fi
|
||
}
|
||
|
||
#############################################
|
||
# UTILITY FUNCTIONS
|
||
#############################################
|
||
|
||
colorize() {
|
||
if [[ $supports_color_output -eq 1 ]]; then
|
||
printf "%s%s%s" "$(tput setaf "${colors[$1]:-7}")" "$2" "$(tput op)"
|
||
else
|
||
printf "%s" "$2"
|
||
fi
|
||
}
|
||
|
||
isRoot() {
|
||
[[ $EUID -eq 0 ]]
|
||
}
|
||
|
||
getBinaryName() {
|
||
echo "${BINARY_NAME_PREFIX}-${architecture}"
|
||
}
|
||
|
||
getVersionTag() {
|
||
local version="$1"
|
||
echo "${VERSION_PREFIX}.${version}"
|
||
}
|
||
|
||
buildDownloadUrl() {
|
||
local target_version="$1"
|
||
local binary_name="$2"
|
||
|
||
if [[ "$target_version" == "latest" ]]; then
|
||
echo "${REPO_URL}/releases/latest/download/${binary_name}"
|
||
else
|
||
echo "${REPO_URL}/releases/download/${target_version}/${binary_name}"
|
||
fi
|
||
}
|
||
|
||
getLang() {
|
||
lang=$(locale | grep LANG | cut -d= -f2 | tr -d '"' | cut -d_ -f1)
|
||
if [[ $lang != "ru" ]]; then
|
||
lang="en"
|
||
fi
|
||
}
|
||
|
||
getIP() {
|
||
local ip="localhost"
|
||
|
||
if command -v dig >/dev/null 2>&1; then
|
||
ip=$(dig +short myip.opendns.com @resolver1.opendns.com 2>/dev/null || echo "")
|
||
if [[ -z "$ip" ]]; then
|
||
ip="localhost"
|
||
fi
|
||
elif command -v host >/dev/null 2>&1; then
|
||
local host_output=""
|
||
host_output=$(host myip.opendns.com resolver1.opendns.com 2>/dev/null || true)
|
||
ip=$(printf "%s\n" "$host_output" | tail -n1 | awk '{print $NF}')
|
||
if [[ -z "$ip" ]]; then
|
||
ip="localhost"
|
||
fi
|
||
fi
|
||
|
||
serverIP="$ip"
|
||
}
|
||
|
||
checkRunning() {
|
||
pgrep -f '[Tt]orr[Ss]erver'
|
||
}
|
||
|
||
promptYesNo() {
|
||
local prompt="$1"
|
||
local default="${2:-n}"
|
||
|
||
if [[ $SILENT_MODE -eq 1 ]]; then
|
||
if [[ "$default" == "y" ]]; then
|
||
return 0
|
||
else
|
||
return 1
|
||
fi
|
||
fi
|
||
|
||
local answer
|
||
IFS= read -r -p " $prompt " answer </dev/tty
|
||
|
||
if [[ "$answer" =~ ^[YyДд] ]]; then
|
||
return 0
|
||
else
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
promptInput() {
|
||
local prompt="$1"
|
||
local default="$2"
|
||
|
||
if [[ $SILENT_MODE -eq 1 ]]; then
|
||
echo "$default"
|
||
return
|
||
fi
|
||
|
||
local answer
|
||
IFS= read -r -p " $prompt " answer </dev/tty
|
||
echo "${answer:-$default}"
|
||
}
|
||
|
||
readEnvFromProc() {
|
||
local pid="$1"
|
||
local key="$2"
|
||
|
||
if [[ -z "$pid" || -z "$key" || ! -r "/proc/$pid/environ" ]]; then
|
||
return 1
|
||
fi
|
||
|
||
while IFS= read -r -d '' entry; do
|
||
case "$entry" in
|
||
"$key"=*)
|
||
printf '%s' "${entry#"${key}"=}"
|
||
return 0
|
||
;;
|
||
esac
|
||
done < "/proc/$pid/environ"
|
||
|
||
return 1
|
||
}
|
||
|
||
systemctlCmd() {
|
||
local quiet=0
|
||
if [[ ${1:-} == "--quiet" ]]; then
|
||
quiet=1
|
||
shift
|
||
fi
|
||
|
||
if ! command -v systemctl >/dev/null 2>&1; then
|
||
if [[ $quiet -eq 0 && $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(msg systemctl_missing)"
|
||
fi
|
||
return 1
|
||
fi
|
||
|
||
local rc
|
||
systemctl "$@" >/dev/null 2>&1
|
||
rc=$?
|
||
if [[ $rc -ne 0 ]]; then
|
||
if [[ $quiet -eq 0 && $SILENT_MODE -eq 0 ]]; then
|
||
printf " - %s\n" "$(msg systemctl_failed "$*")"
|
||
fi
|
||
return $rc
|
||
fi
|
||
|
||
return 0
|
||
}
|
||
|
||
#############################################
|
||
# VERSION MANAGEMENT
|
||
#############################################
|
||
|
||
getLatestRelease() {
|
||
curl -s "${REPO_API_URL}/releases/latest" |
|
||
grep -iE '"tag_name":|"version":' |
|
||
sed -E 's/.*"([^"]+)".*/\1/' |
|
||
head -n1
|
||
}
|
||
|
||
getSpecificRelease() {
|
||
local version="$1"
|
||
local tag_name
|
||
tag_name=$(getVersionTag "$version")
|
||
local response
|
||
response=$(curl -s "${REPO_API_URL}/releases/tags/$tag_name")
|
||
|
||
if echo "$response" | grep -q '"tag_name"'; then
|
||
echo "$tag_name"
|
||
else
|
||
echo ""
|
||
fi
|
||
}
|
||
|
||
getTargetVersion() {
|
||
if [[ -n "$specificVersion" ]]; then
|
||
local target_release
|
||
target_release=$(getSpecificRelease "$specificVersion")
|
||
if [[ -z "$target_release" ]]; then
|
||
echo " - $(colorize red "$(msg version_not_found "$specificVersion")")"
|
||
echo " - $(msg check_versions)"
|
||
exit 1
|
||
fi
|
||
echo "$target_release"
|
||
else
|
||
getLatestRelease
|
||
fi
|
||
}
|
||
|
||
downloadBinary() {
|
||
local url="$1"
|
||
local destination="$2"
|
||
local version_info="$3"
|
||
|
||
local curl_args=(-L)
|
||
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(msg downloading) $version_info..."
|
||
curl_args+=(--progress-bar -#)
|
||
else
|
||
curl_args+=(-s -S)
|
||
fi
|
||
|
||
curl "${curl_args[@]}" -o "$destination" "$url"
|
||
chmod +x "$destination"
|
||
}
|
||
|
||
#############################################
|
||
# GLIBC COMPATIBILITY
|
||
#############################################
|
||
|
||
getGlibcVersion() {
|
||
local glibc_version
|
||
|
||
# Try ldd --version (most reliable)
|
||
if command -v ldd >/dev/null 2>&1; then
|
||
glibc_version=$(ldd --version 2>/dev/null | head -n1 | grep -oE '[0-9]+\.[0-9]+' | head -n1)
|
||
if [[ -n "$glibc_version" ]]; then
|
||
echo "$glibc_version"
|
||
return 0
|
||
fi
|
||
fi
|
||
|
||
# Try getconf GNU_LIBC_VERSION
|
||
if command -v getconf >/dev/null 2>&1; then
|
||
glibc_version=$(getconf GNU_LIBC_VERSION 2>/dev/null | grep -oE '[0-9]+\.[0-9]+')
|
||
if [[ -n "$glibc_version" ]]; then
|
||
echo "$glibc_version"
|
||
return 0
|
||
fi
|
||
fi
|
||
|
||
# Try rpm package manager
|
||
if command -v rpm >/dev/null 2>&1; then
|
||
glibc_version=$(rpm -q glibc 2>/dev/null | grep -oE '[0-9]+\.[0-9]+' | head -n1)
|
||
if [[ -n "$glibc_version" ]]; then
|
||
echo "$glibc_version"
|
||
return 0
|
||
fi
|
||
fi
|
||
|
||
# Try dpkg package manager
|
||
if command -v dpkg >/dev/null 2>&1; then
|
||
glibc_version=$(dpkg -l libc6 2>/dev/null | awk '/^ii/ {print $3}' | grep -oE '[0-9]+\.[0-9]+' | head -n1)
|
||
if [[ -n "$glibc_version" ]]; then
|
||
echo "$glibc_version"
|
||
return 0
|
||
fi
|
||
fi
|
||
|
||
return 1
|
||
}
|
||
|
||
compareVersions() {
|
||
local ver1="$1"
|
||
local ver2="$2"
|
||
local sorted_first
|
||
sorted_first=$(printf '%s\n' "$ver1" "$ver2" | sort -V | head -n1)
|
||
[[ "$sorted_first" == "$ver2" ]]
|
||
}
|
||
|
||
checkGlibcCompatibility() {
|
||
local target_version="$1"
|
||
local version_number
|
||
|
||
# Extract numeric version
|
||
if [[ "$target_version" =~ ${VERSION_PREFIX}\.([0-9]+) ]]; then
|
||
version_number="${BASH_REMATCH[1]}"
|
||
elif [[ "$target_version" =~ ^[0-9]+$ ]]; then
|
||
version_number="$target_version"
|
||
else
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(msg glibc_warning)"
|
||
fi
|
||
return 0
|
||
fi
|
||
|
||
# Check if version requires glibc 2.32+
|
||
if [[ $version_number -ge $MIN_VERSION_REQUIRING_GLIBC ]]; then
|
||
local current_glibc
|
||
current_glibc=$(getGlibcVersion)
|
||
|
||
if [[ -z "$current_glibc" ]]; then
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(msg glibc_warning)"
|
||
echo " - $(msg glibc_may_fail "$target_version")"
|
||
echo " - $(msg glibc_install_may_fail)"
|
||
fi
|
||
return 0
|
||
fi
|
||
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(msg glibc_detected "$current_glibc")"
|
||
fi
|
||
|
||
if ! compareVersions "$current_glibc" "$MIN_GLIBC_VERSION"; then
|
||
echo " - $(colorize red "$(msg glibc_error "$target_version")")"
|
||
echo " - $(msg glibc_current "$current_glibc")"
|
||
echo " - $(msg glibc_upgrade)"
|
||
return 1
|
||
fi
|
||
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(colorize green "$(msg glibc_ok "$target_version")")"
|
||
fi
|
||
else
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(msg glibc_no_requirement "$target_version")"
|
||
fi
|
||
fi
|
||
|
||
return 0
|
||
}
|
||
|
||
#############################################
|
||
# USER MANAGEMENT
|
||
#############################################
|
||
|
||
addUser() {
|
||
if ! isRoot; then
|
||
return 1
|
||
fi
|
||
|
||
if [[ $username == "root" ]]; then
|
||
return 0
|
||
fi
|
||
|
||
if id "$username" >/dev/null 2>&1; then
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
printf " - %s\n" "$(msg user_exists "$username")"
|
||
fi
|
||
return 0
|
||
else
|
||
if useradd --home-dir "$dirInstall" --create-home --shell /bin/false -c "TorrServer" "$username" 2>/dev/null; then
|
||
chmod 755 "$dirInstall"
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
printf " - %s\n" "$(msg user_added "$username")"
|
||
fi
|
||
return 0
|
||
else
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
printf " - %s\n" "$(msg user_add_failed "$username")"
|
||
fi
|
||
return 1
|
||
fi
|
||
fi
|
||
}
|
||
|
||
delUser() {
|
||
if ! isRoot; then
|
||
return 1
|
||
fi
|
||
|
||
if [[ $username == "root" ]]; then
|
||
return 0
|
||
fi
|
||
|
||
if id "$username" >/dev/null 2>&1; then
|
||
if userdel --remove "$username" 2>/dev/null; then
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
printf " - %s\n" "$(msg user_removed "$username")"
|
||
fi
|
||
return 0
|
||
else
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
printf " - %s\n" "$(msg user_remove_failed "$username")"
|
||
fi
|
||
return 1
|
||
fi
|
||
else
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
printf " - %s\n" "$(msg user_not_found "$username")"
|
||
fi
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
#############################################
|
||
# OS DETECTION & PACKAGES
|
||
#############################################
|
||
|
||
installPackages() {
|
||
local pkg_type="$1"
|
||
shift
|
||
local packages=("$@")
|
||
|
||
case "$pkg_type" in
|
||
deb)
|
||
local missing=()
|
||
for pkg in "${packages[@]}"; do
|
||
if ! dpkg -s "$pkg" >/dev/null 2>&1; then
|
||
missing+=("$pkg")
|
||
fi
|
||
done
|
||
if [[ ${#missing[@]} -gt 0 ]]; then
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " $(msg installing_packages)"
|
||
fi
|
||
apt -y install "${missing[@]}"
|
||
fi
|
||
;;
|
||
rpm)
|
||
local pkg_manager="$1"
|
||
shift
|
||
packages=("$@")
|
||
for pkg in "${packages[@]}"; do
|
||
if [[ -z "$(rpm -qa "$pkg" 2>/dev/null)" ]]; then
|
||
$pkg_manager -y install "$pkg"
|
||
fi
|
||
done
|
||
;;
|
||
arch)
|
||
for pkg in "${packages[@]}"; do
|
||
if [[ -z $(pacman -Qqe "$pkg" 2>/dev/null) ]]; then
|
||
pacman -Sy --noconfirm "$pkg"
|
||
fi
|
||
done
|
||
;;
|
||
esac
|
||
}
|
||
|
||
getRpmPackageManager() {
|
||
local version_id="$1"
|
||
|
||
if [[ "$version_id" =~ ^[0-9]+$ ]] && [[ $version_id -ge 8 ]] && command -v dnf >/dev/null 2>&1; then
|
||
echo "dnf"
|
||
elif command -v dnf >/dev/null 2>&1; then
|
||
echo "dnf"
|
||
else
|
||
echo "yum"
|
||
fi
|
||
}
|
||
|
||
validateOSVersion() {
|
||
local os_name="$1"
|
||
local supported_versions="$2"
|
||
local version_id="$3"
|
||
|
||
local major_version
|
||
major_version=$(echo "$version_id" | cut -d '.' -f1)
|
||
|
||
if [[ ! $major_version =~ ^($supported_versions)$ ]]; then
|
||
echo ""
|
||
echo " $(msg os_not_supported "$os_name")"
|
||
echo ""
|
||
echo " $(msg os_script_supports "$os_name" "$supported_versions")"
|
||
echo ""
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
checkOS() {
|
||
if [[ -e /etc/debian_version ]]; then
|
||
# shellcheck source=/dev/null
|
||
source /etc/os-release
|
||
|
||
if [[ $ID == "debian" || $ID == "raspbian" ]]; then
|
||
local current_version_id
|
||
current_version_id="${VERSION_ID:-}"
|
||
if [[ -n "$current_version_id" && $current_version_id -lt 6 ]]; then
|
||
validateOSVersion "Debian" ">=6" "$current_version_id"
|
||
fi
|
||
elif [[ $ID == "ubuntu" ]]; then
|
||
local current_version_id
|
||
current_version_id="${VERSION_ID:-}"
|
||
local major
|
||
major=$(echo "$current_version_id" | cut -d '.' -f1)
|
||
if [[ -n "$current_version_id" && $major -lt 10 ]]; then
|
||
validateOSVersion "Ubuntu" ">=10" "$current_version_id"
|
||
fi
|
||
fi
|
||
|
||
installPackages deb curl iputils-ping dnsutils
|
||
|
||
elif [[ -e /etc/system-release ]]; then
|
||
# shellcheck source=/dev/null
|
||
source /etc/os-release
|
||
local pkg_manager
|
||
|
||
case "$ID" in
|
||
fedora)
|
||
pkg_manager=$(getRpmPackageManager "${VERSION_ID%%.*}")
|
||
installPackages rpm "$pkg_manager" curl iputils bind-utils
|
||
;;
|
||
centos|redhat)
|
||
validateOSVersion "CentOS/RedHat" "7|8|9|10" "$VERSION_ID"
|
||
pkg_manager=$(getRpmPackageManager "${VERSION_ID%%.*}")
|
||
installPackages rpm "$pkg_manager" curl iputils bind-utils
|
||
;;
|
||
rocky)
|
||
validateOSVersion "RockyLinux" "8|9|10" "$VERSION_ID"
|
||
pkg_manager=$(getRpmPackageManager "${VERSION_ID%%.*}")
|
||
installPackages rpm "$pkg_manager" curl iputils bind-utils
|
||
;;
|
||
almalinux)
|
||
validateOSVersion "AlmaLinux" "8|9|10" "$VERSION_ID"
|
||
pkg_manager=$(getRpmPackageManager "${VERSION_ID%%.*}")
|
||
installPackages rpm "$pkg_manager" curl iputils bind-utils
|
||
;;
|
||
ol)
|
||
validateOSVersion "Oracle Linux" "8|9|10" "$VERSION_ID"
|
||
pkg_manager=$(getRpmPackageManager "${VERSION_ID%%.*}")
|
||
installPackages rpm "$pkg_manager" curl iputils bind-utils
|
||
;;
|
||
amzn)
|
||
if [[ $VERSION_ID != "2" ]]; then
|
||
validateOSVersion "Amazon Linux" "2" "$VERSION_ID"
|
||
fi
|
||
installPackages rpm yum curl iputils bind-utils
|
||
;;
|
||
esac
|
||
|
||
elif [[ -e /etc/arch-release ]]; then
|
||
installPackages arch curl iputils bind-tools
|
||
|
||
else
|
||
echo " $(msg unsupported_os)"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
checkArch() {
|
||
case $(uname -m) in
|
||
i386|i686) architecture="386" ;;
|
||
x86_64) architecture="amd64" ;;
|
||
aarch64) architecture="arm64" ;;
|
||
armv7|armv7l) architecture="arm7" ;;
|
||
armv6|armv6l) architecture="arm5" ;;
|
||
*)
|
||
echo " $(msg unsupported_arch)"
|
||
exit 1
|
||
;;
|
||
esac
|
||
}
|
||
|
||
checkInternet() {
|
||
if ! command -v ping >/dev/null 2>&1; then
|
||
echo " $(msg need_ping)"
|
||
exit 1
|
||
fi
|
||
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " $(msg check_internet)"
|
||
fi
|
||
|
||
if ! ping -c 2 google.com &> /dev/null; then
|
||
echo " - $(msg no_internet)"
|
||
exit 1
|
||
fi
|
||
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(msg have_internet)"
|
||
fi
|
||
}
|
||
|
||
initialCheck() {
|
||
if ! isRoot; then
|
||
echo " $(msg need_root)"
|
||
exit 1
|
||
fi
|
||
|
||
checkOS
|
||
checkArch
|
||
checkInternet
|
||
}
|
||
|
||
#############################################
|
||
# INSTALLATION FUNCTIONS
|
||
#############################################
|
||
|
||
checkInstalled() {
|
||
# Set username based on USE_ROOT_USER flag
|
||
if [[ $USE_ROOT_USER -eq 1 ]]; then
|
||
username="root"
|
||
else
|
||
username="${DEFAULT_USERNAME}"
|
||
if ! addUser; then
|
||
username="root"
|
||
fi
|
||
fi
|
||
|
||
local binName
|
||
binName=$(getBinaryName)
|
||
if [[ -f "$dirInstall/$binName" ]] && [[ $(stat -c%s "$dirInstall/$binName" 2>/dev/null) -ne 0 ]]; then
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(msg found_in) $dirInstall"
|
||
fi
|
||
return 0
|
||
else
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(msg not_found)"
|
||
fi
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
checkInstalledVersion() {
|
||
local binName
|
||
binName=$(getBinaryName)
|
||
local target_version
|
||
target_version=$(getTargetVersion)
|
||
local installed_version
|
||
installed_version="$("$dirInstall/$binName" --version 2>/dev/null | awk '{print $2}')"
|
||
|
||
if [[ -z "$target_version" ]]; then
|
||
echo " - $(msg no_version_info)"
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "$target_version" == "$installed_version" ]]; then
|
||
if [[ -n "$specificVersion" ]]; then
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(msg already_installed "$target_version")"
|
||
fi
|
||
else
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(msg have_latest "$target_version")"
|
||
fi
|
||
fi
|
||
return 0
|
||
else
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
if [[ -n "$specificVersion" ]]; then
|
||
echo " - $(msg will_install "$target_version")"
|
||
else
|
||
echo " - $(msg update_found)"
|
||
fi
|
||
echo " $(msg installed_version) \"$installed_version\""
|
||
echo " $(msg target_label) \"$target_version\""
|
||
fi
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
createServiceFile() {
|
||
cat << EOF > "$dirInstall/$serviceName.service"
|
||
[Unit]
|
||
Description=TorrServer - stream torrent to http
|
||
Wants=network-online.target
|
||
After=network.target
|
||
|
||
[Service]
|
||
User=$username
|
||
Group=$username
|
||
Type=simple
|
||
NonBlocking=true
|
||
EnvironmentFile=$dirInstall/$serviceName.config
|
||
ExecStart=${dirInstall}/$(getBinaryName) \$DAEMON_OPTIONS
|
||
ExecReload=/bin/kill -HUP \${MAINPID}
|
||
ExecStop=/bin/kill -INT \${MAINPID}
|
||
TimeoutSec=30
|
||
Restart=on-failure
|
||
RestartSec=5s
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
EOF
|
||
}
|
||
|
||
configureService() {
|
||
# Port configuration
|
||
if [[ -z "$servicePort" ]]; then
|
||
local inferred_default="$DEFAULT_PORT"
|
||
if promptYesNo "$(msg change_port)" "n"; then
|
||
servicePort=$(promptInput "$(msg enter_port)" "$inferred_default")
|
||
else
|
||
servicePort="$inferred_default"
|
||
fi
|
||
fi
|
||
|
||
# Auth configuration
|
||
if [[ -z "$isAuth" ]]; then
|
||
if promptYesNo "$(msg enable_auth)" "n"; then
|
||
isAuth=1
|
||
else
|
||
isAuth=0
|
||
fi
|
||
fi
|
||
|
||
# Setup auth if enabled
|
||
if [[ $isAuth -eq 1 ]]; then
|
||
if [[ ! -f "$dirInstall/accs.db" ]]; then
|
||
isAuthUser=$(promptInput "$(msg prompt_user)" "admin")
|
||
isAuthPass=$(promptInput "$(msg prompt_password)" "admin")
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
printf ' %s\n' "$(msg store_auth "$isAuthUser" "$isAuthPass" "${dirInstall}/accs.db")"
|
||
fi
|
||
echo -e "{\n \"$isAuthUser\": \"$isAuthPass\"\n}" > "$dirInstall/accs.db"
|
||
else
|
||
local auth
|
||
auth=$(cat "$dirInstall/accs.db" | head -2 | tail -1 | tr -d '[:space:]' | tr -d '"')
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
printf ' - %s\n' "$(msg use_existing_auth "${dirInstall}/accs.db" "$auth")"
|
||
fi
|
||
fi
|
||
|
||
cat << EOF > "$dirInstall/$serviceName.config"
|
||
DAEMON_OPTIONS="--port $servicePort --path $dirInstall --httpauth"
|
||
EOF
|
||
else
|
||
cat << EOF > "$dirInstall/$serviceName.config"
|
||
DAEMON_OPTIONS="--port $servicePort --path $dirInstall"
|
||
EOF
|
||
fi
|
||
|
||
# Read-only database configuration
|
||
if [[ -z "$isRdb" ]]; then
|
||
if promptYesNo "$(msg enable_rdb)" "n"; then
|
||
isRdb=1
|
||
else
|
||
isRdb=0
|
||
fi
|
||
fi
|
||
|
||
if [[ $isRdb -eq 1 ]]; then
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " $(msg set_readonly)"
|
||
printf ' %s\n' "$(msg readonly_hint "$dirInstall/$serviceName.config")"
|
||
fi
|
||
sed -i 's|DAEMON_OPTIONS="--port|DAEMON_OPTIONS="--rdb --port|' "$dirInstall/$serviceName.config"
|
||
fi
|
||
|
||
# Logging configuration
|
||
if [[ -z "$isLog" ]]; then
|
||
if promptYesNo "$(msg enable_log)" "n"; then
|
||
isLog=1
|
||
else
|
||
isLog=0
|
||
fi
|
||
fi
|
||
|
||
if [[ $isLog -eq 1 ]]; then
|
||
sed -i "s|--path|--logpath $dirInstall/$serviceName.log --path|" "$dirInstall/$serviceName.config"
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
printf ' - %s\n' "$(msg log_location "$dirInstall/$serviceName.log")"
|
||
fi
|
||
fi
|
||
}
|
||
|
||
changeServiceUser() {
|
||
local target_user="$1"
|
||
if [[ -z "$target_user" ]]; then
|
||
echo "Error: Username required for --change-user"
|
||
exit 1
|
||
fi
|
||
|
||
if [[ ! -d "$dirInstall" ]] || [[ ! -f "$dirInstall/$serviceName.config" ]]; then
|
||
echo " - $(msg user_change_missing "$dirInstall")"
|
||
exit 1
|
||
fi
|
||
|
||
checkArch
|
||
|
||
local normalized_target
|
||
normalized_target=$(echo "$target_user" | tr '[:upper:]' '[:lower:]')
|
||
local default_lower
|
||
default_lower=$(echo "$DEFAULT_USERNAME" | tr '[:upper:]' '[:lower:]')
|
||
|
||
if [[ "$normalized_target" == "root" ]]; then
|
||
target_user="root"
|
||
USE_ROOT_USER=1
|
||
username="root"
|
||
elif [[ "$normalized_target" == "$default_lower" ]]; then
|
||
target_user="$DEFAULT_USERNAME"
|
||
USE_ROOT_USER=0
|
||
username="$DEFAULT_USERNAME"
|
||
if ! id "$username" >/dev/null 2>&1; then
|
||
if ! addUser; then
|
||
printf " - %s\n" "$(msg user_add_failed "$username")"
|
||
exit 1
|
||
fi
|
||
fi
|
||
else
|
||
printf " - %s\n" "$(msg user_change_invalid "root" "$DEFAULT_USERNAME")"
|
||
exit 1
|
||
fi
|
||
|
||
local owner="$username"
|
||
local group
|
||
if [[ "$username" == "root" ]]; then
|
||
group="root"
|
||
else
|
||
group="$(id -gn "$username" 2>/dev/null || echo "$username")"
|
||
fi
|
||
|
||
createServiceFile
|
||
sed -i 's/^[ \t]*//' "$dirInstall/$serviceName.service"
|
||
ln -sf "$dirInstall/$serviceName.service" /usr/local/lib/systemd/system/
|
||
|
||
if [[ -d "$dirInstall" ]]; then
|
||
chown -R "$owner":"$group" "$dirInstall"
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
printf ' - %s\n' "$(msg user_change_permissions "$dirInstall" "$owner" "$group")"
|
||
fi
|
||
fi
|
||
|
||
local restart_rc=0
|
||
if ! systemctlCmd daemon-reload; then
|
||
restart_rc=1
|
||
fi
|
||
if ! systemctlCmd restart "$serviceName.service"; then
|
||
restart_rc=1
|
||
fi
|
||
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
printf ' - %s\n' "$(msg user_change_success "$username")"
|
||
if [[ "$username" == "root" ]]; then
|
||
echo " - $(msg running_as_root)"
|
||
else
|
||
printf ' - %s\n' "$(msg running_as_user "$username")"
|
||
fi
|
||
if [[ $restart_rc -eq 1 ]]; then
|
||
echo " - $(colorize yellow "$(msg service_start_failed)")"
|
||
fi
|
||
else
|
||
printf "%s\n" "$(msg user_change_success "$username")"
|
||
if [[ $restart_rc -eq 1 ]]; then
|
||
printf "%s\n" "$(msg service_start_failed)"
|
||
fi
|
||
fi
|
||
}
|
||
|
||
installTorrServer() {
|
||
if [[ $SILENT_MODE -eq 0 && $ROOT_PROMPTED -eq 0 ]]; then
|
||
if [[ $USE_ROOT_USER -ne 1 ]]; then
|
||
if promptYesNo "Run service as root user? (Yes/No)" "n"; then
|
||
USE_ROOT_USER=1
|
||
username="root"
|
||
fi
|
||
fi
|
||
ROOT_PROMPTED=1
|
||
fi
|
||
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " $(msg install_configure)"
|
||
fi
|
||
|
||
# Get target version and check glibc compatibility
|
||
local target_version
|
||
target_version=$(getTargetVersion)
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(msg target_version) $target_version"
|
||
fi
|
||
|
||
if ! checkGlibcCompatibility "$target_version"; then
|
||
exit 1
|
||
fi
|
||
|
||
# Check if already installed and up to date
|
||
if checkInstalled; then
|
||
if ! checkInstalledVersion; then
|
||
if promptYesNo "$(msg want_update)" "y"; then
|
||
UpdateVersion
|
||
return
|
||
fi
|
||
else
|
||
# Already installed and up to date, just reconfigure if needed
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(msg running_as_user "$username")"
|
||
fi
|
||
return
|
||
fi
|
||
fi
|
||
|
||
# Create directories
|
||
if [[ ! -d "$dirInstall" ]]; then
|
||
mkdir -p "$dirInstall"
|
||
fi
|
||
if [[ ! -d "/usr/local/lib/systemd/system" ]]; then
|
||
mkdir -p "/usr/local/lib/systemd/system"
|
||
fi
|
||
|
||
# Download binary if needed
|
||
local binName
|
||
binName=$(getBinaryName)
|
||
if [[ ! -f "$dirInstall/$binName" ]] || [[ ! -x "$dirInstall/$binName" ]] || [[ $(stat -c%s "$dirInstall/$binName" 2>/dev/null) -eq 0 ]]; then
|
||
local urlBin
|
||
if [[ -n "$specificVersion" ]]; then
|
||
urlBin=$(buildDownloadUrl "$target_version" "$binName")
|
||
else
|
||
urlBin=$(buildDownloadUrl "latest" "$binName")
|
||
fi
|
||
downloadBinary "$urlBin" "$dirInstall/$binName" "$target_version"
|
||
fi
|
||
|
||
# Create service and config files
|
||
createServiceFile
|
||
configureService
|
||
|
||
# Set up systemd service
|
||
ln -sf "$dirInstall/$serviceName.service" /usr/local/lib/systemd/system/
|
||
sed -i 's/^[ \t]*//' "$dirInstall/$serviceName.service"
|
||
sed -i 's/^[ \t]*//' "$dirInstall/$serviceName.config"
|
||
|
||
local service_started=0
|
||
|
||
# Start service
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " $(msg starting_service)"
|
||
fi
|
||
if ! systemctlCmd daemon-reload; then
|
||
:
|
||
fi
|
||
if ! systemctlCmd enable "$serviceName.service"; then
|
||
:
|
||
fi
|
||
if systemctlCmd restart "$serviceName.service"; then
|
||
service_started=1
|
||
fi
|
||
|
||
# Show completion message
|
||
getIP
|
||
local installed_version="$target_version"
|
||
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo ""
|
||
printf ' %s\n' "$(msg install_complete "$installed_version" "$dirInstall")"
|
||
echo ""
|
||
printf ' %s\n' "$(msg access_web "$serverIP" "$servicePort")"
|
||
echo ""
|
||
|
||
if [[ $isAuth -eq 1 && -n "$isAuthUser" ]]; then
|
||
printf ' %s\n' "$(msg use_auth "$isAuthUser" "$isAuthPass")"
|
||
echo ""
|
||
fi
|
||
|
||
if [[ $username == "root" ]]; then
|
||
echo " $(colorize yellow "$(msg running_as_root)")"
|
||
else
|
||
printf ' %s\n' "$(msg running_as_user "$username")"
|
||
fi
|
||
|
||
if [[ $service_started -eq 0 ]]; then
|
||
echo " $(colorize yellow "$(msg service_start_failed)")"
|
||
fi
|
||
echo ""
|
||
fi
|
||
|
||
if [[ $SILENT_MODE -eq 1 ]]; then
|
||
printf "%s\n" "$(msg install_complete "$installed_version" "$dirInstall")"
|
||
printf "%s\n" "$(msg access_web "$serverIP" "$servicePort")"
|
||
if [[ $isAuth -eq 1 && -n "$isAuthUser" ]]; then
|
||
printf "%s\n" "$(msg use_auth "$isAuthUser" "$isAuthPass")"
|
||
fi
|
||
fi
|
||
|
||
return 0
|
||
}
|
||
|
||
UpdateVersion() {
|
||
local target_version
|
||
target_version=$(getTargetVersion)
|
||
|
||
if ! checkGlibcCompatibility "$target_version"; then
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(msg update_cancelled)"
|
||
fi
|
||
return 1
|
||
fi
|
||
|
||
if ! systemctlCmd stop "$serviceName.service"; then
|
||
:
|
||
fi
|
||
|
||
local binName
|
||
binName=$(getBinaryName)
|
||
local urlBin
|
||
if [[ -n "$specificVersion" ]]; then
|
||
urlBin=$(buildDownloadUrl "$target_version" "$binName")
|
||
else
|
||
urlBin=$(buildDownloadUrl "latest" "$binName")
|
||
fi
|
||
|
||
downloadBinary "$urlBin" "$dirInstall/$binName" "$target_version"
|
||
|
||
# Update service file to reflect user change
|
||
if [[ -f "$dirInstall/$serviceName.service" ]]; then
|
||
createServiceFile
|
||
if ! systemctlCmd daemon-reload; then
|
||
:
|
||
fi
|
||
fi
|
||
|
||
if ! systemctlCmd start "$serviceName.service"; then
|
||
:
|
||
fi
|
||
|
||
return 0
|
||
}
|
||
|
||
DowngradeVersion() {
|
||
local target_version
|
||
target_version=$(getVersionTag "$downgradeRelease")
|
||
|
||
if ! checkGlibcCompatibility "$target_version"; then
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(msg downgrade_cancelled)"
|
||
fi
|
||
return 1
|
||
fi
|
||
|
||
if ! systemctlCmd stop "$serviceName.service"; then
|
||
:
|
||
fi
|
||
|
||
local binName
|
||
binName=$(getBinaryName)
|
||
local urlBin
|
||
urlBin=$(buildDownloadUrl "$target_version" "$binName")
|
||
downloadBinary "$urlBin" "$dirInstall/$binName" "$target_version"
|
||
|
||
# Update service file to reflect user change
|
||
if [[ -f "$dirInstall/$serviceName.service" ]]; then
|
||
createServiceFile
|
||
if ! systemctlCmd daemon-reload; then
|
||
:
|
||
fi
|
||
fi
|
||
|
||
if ! systemctlCmd start "$serviceName.service"; then
|
||
:
|
||
fi
|
||
|
||
return 0
|
||
}
|
||
|
||
#############################################
|
||
# CLEANUP FUNCTIONS
|
||
#############################################
|
||
|
||
cleanup() {
|
||
if ! systemctlCmd --quiet stop "$serviceName"; then
|
||
:
|
||
fi
|
||
if ! systemctlCmd --quiet disable "$serviceName"; then
|
||
:
|
||
fi
|
||
rm -rf /usr/local/lib/systemd/system/"$serviceName.service" "$dirInstall" 2>/dev/null
|
||
delUser
|
||
}
|
||
|
||
cleanAll() {
|
||
if ! systemctlCmd --quiet stop torr; then
|
||
:
|
||
fi
|
||
if ! systemctlCmd --quiet stop torrserver; then
|
||
:
|
||
fi
|
||
if ! systemctlCmd --quiet disable torr; then
|
||
:
|
||
fi
|
||
if ! systemctlCmd --quiet disable torrserver; then
|
||
:
|
||
fi
|
||
rm -rf /home/torrserver 2>/dev/null
|
||
rm -rf /usr/local/torr 2>/dev/null
|
||
rm -rf /opt/torr* 2>/dev/null
|
||
rm -f /{,etc,usr/local/lib}/systemd/system/tor{,r,rserver}.service 2>/dev/null
|
||
}
|
||
|
||
uninstall() {
|
||
checkArch
|
||
checkInstalled
|
||
|
||
if [[ $SILENT_MODE -eq 1 ]]; then
|
||
cleanup
|
||
cleanAll
|
||
echo " - $(msg uninstalled)"
|
||
return
|
||
fi
|
||
|
||
echo ""
|
||
echo " $(msg install_dir_label) ${dirInstall}"
|
||
echo ""
|
||
echo " $(msg uninstall_warning)"
|
||
echo ""
|
||
|
||
if promptYesNo "$(msg confirm_delete)" "n"; then
|
||
cleanup
|
||
cleanAll
|
||
echo " - $(msg uninstalled)"
|
||
echo ""
|
||
else
|
||
echo ""
|
||
fi
|
||
}
|
||
|
||
#############################################
|
||
# HELP & MAIN
|
||
#############################################
|
||
|
||
helpUsage() {
|
||
cat << EOF
|
||
$scriptname - TorrServer Installation Script
|
||
|
||
Usage: $scriptname [COMMAND] [OPTIONS]
|
||
|
||
Commands:
|
||
-i, --install [VERSION] Install latest or specific version
|
||
install [VERSION]
|
||
-u, --update Update to latest version
|
||
update
|
||
-c, --check Check for updates (version info only)
|
||
check
|
||
-d, --down VERSION Downgrade to specific version
|
||
down VERSION
|
||
-r, --remove Uninstall TorrServer
|
||
remove
|
||
-C, --change-user USER Change TorrServer service user (root|torrserver)
|
||
change-user USER
|
||
-h, --help Show this help message
|
||
help
|
||
|
||
Options:
|
||
--root Run service as root user
|
||
--silent Non-interactive mode with defaults
|
||
|
||
Examples:
|
||
# Install latest version interactively
|
||
sudo $scriptname --install
|
||
|
||
# Install specific version as root user silently
|
||
sudo $scriptname --install 135 --root --silent
|
||
|
||
# Update with silent mode
|
||
sudo $scriptname --update --silent
|
||
|
||
# Check for updates
|
||
sudo $scriptname --check
|
||
|
||
# Uninstall silently
|
||
sudo $scriptname --remove --silent
|
||
|
||
# Switch service to run as root
|
||
sudo $scriptname -C root
|
||
|
||
# Switch service back to torrserver user
|
||
sudo $scriptname --change-user torrserver
|
||
|
||
Default Settings (silent mode):
|
||
- Port: ${portOverride:-$DEFAULT_PORT}
|
||
- User: torrserver (or root with --root flag)
|
||
- Auth: disabled
|
||
- Read-only mode: disabled
|
||
- Logging: disabled
|
||
|
||
EOF
|
||
}
|
||
|
||
parseArguments() {
|
||
parsedCommand=""
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case $1 in
|
||
-i|--install|install)
|
||
parsedCommand="install"
|
||
shift
|
||
# Check for version number
|
||
if [[ $# -gt 0 ]]; then
|
||
local next_arg="$1"
|
||
if [[ "$next_arg" =~ ^[0-9]+$ ]]; then
|
||
specificVersion="$next_arg"
|
||
shift
|
||
fi
|
||
fi
|
||
;;
|
||
-u|--update|update)
|
||
parsedCommand="update"
|
||
shift
|
||
;;
|
||
-c|--check|check)
|
||
parsedCommand="check"
|
||
shift
|
||
;;
|
||
-d|--down|down)
|
||
parsedCommand="downgrade"
|
||
shift
|
||
if [[ $# -gt 0 ]]; then
|
||
local next_arg="$1"
|
||
if [[ "$next_arg" =~ ^[0-9]+$ ]]; then
|
||
downgradeRelease="$next_arg"
|
||
shift
|
||
else
|
||
echo "Error: Version number required for downgrade"
|
||
echo "Example: $scriptname -d 101"
|
||
exit 1
|
||
fi
|
||
else
|
||
echo "Error: Version number required for downgrade"
|
||
echo "Example: $scriptname -d 101"
|
||
exit 1
|
||
fi
|
||
;;
|
||
-r|--remove|remove)
|
||
parsedCommand="remove"
|
||
shift
|
||
;;
|
||
-C|--change-user|change-user)
|
||
parsedCommand="change_user"
|
||
shift
|
||
if [[ $# -gt 0 ]]; then
|
||
changeUserName="$1"
|
||
shift
|
||
else
|
||
echo "Error: Username required for --change-user"
|
||
exit 1
|
||
fi
|
||
;;
|
||
-h|--help|help)
|
||
getLang # Set language before showing help
|
||
helpUsage
|
||
exit 0
|
||
;;
|
||
--root)
|
||
USE_ROOT_USER=1
|
||
shift
|
||
;;
|
||
--silent)
|
||
SILENT_MODE=1
|
||
shift
|
||
;;
|
||
*)
|
||
echo "Unknown option: $1"
|
||
helpUsage
|
||
exit 1
|
||
;;
|
||
esac
|
||
done
|
||
}
|
||
|
||
#############################################
|
||
# MAIN EXECUTION
|
||
#############################################
|
||
|
||
main() {
|
||
getLang
|
||
|
||
parseArguments "$@"
|
||
|
||
local command="$parsedCommand"
|
||
|
||
case "$command" in
|
||
install)
|
||
if [[ $SILENT_MODE -eq 0 && -n "$specificVersion" ]]; then
|
||
echo " - Installing specific version: $specificVersion"
|
||
fi
|
||
initialCheck
|
||
|
||
if [[ $SILENT_MODE -eq 1 ]]; then
|
||
servicePort="$DEFAULT_PORT"
|
||
isAuth=0
|
||
isRdb=0
|
||
isLog=0
|
||
fi
|
||
|
||
if [[ $USE_ROOT_USER -eq 1 ]]; then
|
||
username="root"
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - $(msg running_as_root)"
|
||
fi
|
||
fi
|
||
|
||
if ! checkInstalled; then
|
||
installTorrServer
|
||
else
|
||
createServiceFile
|
||
if ! systemctlCmd daemon-reload; then
|
||
:
|
||
fi
|
||
if ! systemctlCmd stop "$serviceName.service"; then
|
||
:
|
||
fi
|
||
if ! systemctlCmd start "$serviceName.service"; then
|
||
:
|
||
fi
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo " - Service reconfigured for user: $username"
|
||
fi
|
||
fi
|
||
exit 0
|
||
;;
|
||
update)
|
||
initialCheck
|
||
if [[ $USE_ROOT_USER -eq 1 ]]; then
|
||
username="root"
|
||
fi
|
||
if checkInstalled; then
|
||
if ! checkInstalledVersion; then
|
||
UpdateVersion
|
||
fi
|
||
fi
|
||
exit 0
|
||
;;
|
||
check)
|
||
initialCheck
|
||
if checkInstalled; then
|
||
checkInstalledVersion
|
||
fi
|
||
exit 0
|
||
;;
|
||
downgrade)
|
||
initialCheck
|
||
if [[ $USE_ROOT_USER -eq 1 ]]; then
|
||
username="root"
|
||
fi
|
||
if checkInstalled; then
|
||
DowngradeVersion
|
||
fi
|
||
exit 0
|
||
;;
|
||
remove)
|
||
uninstall
|
||
exit 0
|
||
;;
|
||
change_user)
|
||
if [[ -z "$changeUserName" ]]; then
|
||
echo "Error: Username required for --change-user"
|
||
exit 1
|
||
fi
|
||
if ! isRoot; then
|
||
echo " $(msg need_root)"
|
||
exit 1
|
||
fi
|
||
changeServiceUser "$changeUserName"
|
||
exit 0
|
||
;;
|
||
esac
|
||
|
||
# Interactive mode if no command provided and not silent
|
||
if [[ $SILENT_MODE -eq 0 ]]; then
|
||
echo ""
|
||
echo " $(msg lang_choice)"
|
||
echo " [$(colorize green 1)] $(msg lang_english)"
|
||
echo " [$(colorize yellow 2)] $(msg lang_russian)"
|
||
local answer_lang
|
||
answer_lang=$(promptInput "$(msg your_lang)" "1")
|
||
if [[ "$answer_lang" == "2" ]]; then
|
||
lang="ru"
|
||
fi
|
||
|
||
echo ""
|
||
echo "============================================================="
|
||
echo " $(msg script_title)"
|
||
echo "============================================================="
|
||
echo ""
|
||
echo " $(msg help_hint)"
|
||
echo ""
|
||
|
||
if promptYesNo "$(msg want_install)" "n"; then
|
||
initialCheck
|
||
|
||
if promptYesNo "Run service as root user? (Yes/No)" "n"; then
|
||
USE_ROOT_USER=1
|
||
username="root"
|
||
fi
|
||
ROOT_PROMPTED=1
|
||
|
||
installTorrServer
|
||
fi
|
||
fi
|
||
|
||
echo " $(msg have_fun)"
|
||
echo ""
|
||
}
|
||
|
||
# Run main function
|
||
main "$@"
|