Files
ProxmoxVE/tools/addon/filebrowser-quantum.sh
T
CanbiZ (MickLesk) 969cc5e9b8 FileBrowser Quantum: migrate the config and database to v2 (#17815)
v2.0.0 reads the config strictly and stops at the v1 keys the addon
wrote (server.port, conditionals, indexingIntervalMinutes). It also only
imports the old BoltDB when server.database.migrateFrom names it and no
database.db is left in the working directory. The update now rewrites
the config, renames the database and points migrateFrom at it, keeping
a copy of the v1 config. New installs write the v2 layout.
2026-10-09 21:24:00 +02:00

280 lines
8.7 KiB
Bash

#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: MickLesk
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/filebrowserspace/quantum
APP="FileBrowser Quantum"
APP_TYPE="addon"
INSTALL_PATH="/usr/local/bin/filebrowser"
CONFIG_PATH="/usr/local/community-scripts/fq-config.yaml"
DEFAULT_PORT=8080
SRC_DIR="/"
if ! command -v curl &>/dev/null; then
printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2
if [[ -f /etc/alpine-release ]]; then
apk update >/dev/null 2>&1
apk add --no-cache curl >/dev/null 2>&1
else
apt-get update >/dev/null 2>&1
apt-get install -y curl >/dev/null 2>&1
fi
fi
source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/core/core.func")
source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/lib/tools.func")
source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/core/error_handler.func")
source <(curl -fsSL "${COMMUNITY_SCRIPTS_CORE_URL:-https://raw.githubusercontent.com/community-scripts/core/main}/api/api.func") 2>/dev/null || true
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "filebrowser-quantum" "addon"
# Enable error handling
set -Eeuo pipefail
trap 'error_handler' ERR
# Initialize all core functions (colors, formatting, icons, STD mode)
load_functions
header_info
get_lxc_ip
IP="$LOCAL_IP"
# Proxmox Host Warning
if [[ -d "/etc/pve" ]]; then
msg_warn "Running this addon directly on the Proxmox host is not recommended!"
msg_warn "Only the boot disk will be visible — passthrough drives will not be indexed."
msg_warn "This causes incorrect disk usage stats and incomplete file browsing."
msg_warn "Run this addon inside an LXC or VM instead and mount your drives there."
echo ""
echo -n "${TAB}Continue anyway on the Proxmox host? (y/N): "
read -r host_confirm
if [[ ! "${host_confirm,,}" =~ ^(y|yes)$ ]]; then
msg_error "Aborted."
exit 0
fi
fi
# OS Detection
if [[ -f "/etc/alpine-release" ]]; then
OS="Alpine"
SERVICE_PATH="/etc/init.d/filebrowser"
PKG_MANAGER="apk add --no-cache"
elif [[ -f "/etc/debian_version" ]]; then
OS="Debian"
SERVICE_PATH="/etc/systemd/system/filebrowser.service"
PKG_MANAGER="apt install -y"
else
msg_error "Unsupported OS detected. Exiting."
exit 238
fi
# Detect legacy FileBrowser installation
LEGACY_DB="/usr/local/community-scripts/filebrowser.db"
LEGACY_BIN="/usr/local/bin/filebrowser"
LEGACY_SERVICE_DEB="/etc/systemd/system/filebrowser.service"
LEGACY_SERVICE_ALP="/etc/init.d/filebrowser"
if [[ -f "$LEGACY_DB" || -f "$LEGACY_BIN" && ! -f "$CONFIG_PATH" ]]; then
msg_warn "Detected legacy FileBrowser installation."
echo -n "${TAB}Uninstall legacy FileBrowser and continue with Quantum install? (y/n): "
read -r remove_legacy
if [[ "${remove_legacy,,}" =~ ^(y|yes)$ ]]; then
msg_info "Uninstalling legacy FileBrowser"
if [[ -f "$LEGACY_SERVICE_DEB" ]]; then
systemctl disable --now filebrowser.service &>/dev/null || true
rm -f "$LEGACY_SERVICE_DEB"
elif [[ -f "$LEGACY_SERVICE_ALP" ]]; then
rc-service filebrowser stop &>/dev/null || true
rc-update del filebrowser &>/dev/null || true
rm -f "$LEGACY_SERVICE_ALP"
fi
rm -f "$LEGACY_BIN" "$LEGACY_DB"
msg_ok "Legacy FileBrowser removed"
else
msg_error "Installation aborted by user."
exit 0
fi
fi
# v2 rejects v1 config keys and imports the BoltDB on its first start
migrate_v1_config() {
local dir="/usr/local/community-scripts" db=0
[[ -s "$dir/database.db" && ! -s "$dir/filebrowser.sqlite" ]] && db=1
((db)) || grep -qE 'conditionals:|indexingIntervalMinutes:' "$CONFIG_PATH" || return 0
cp "$CONFIG_PATH" "${CONFIG_PATH}.v1.bak"
((db)) && mv "$dir/database.db" "$dir/database.db.old"
awk -v db="$db" '
{ match($0, /^ */); ind = RLENGTH }
/^[^ #]/ { top = $1 }
cond && ind > ci { print substr($0, 3); next }
{ cond = 0 }
/^[[:space:]]*conditionals:[[:space:]]*$/ { cond = 1; ci = ind; next }
/^[[:space:]]*indexingIntervalMinutes:/ { next }
top == "server:" && /^ port:/ { port = $2; next }
{ print }
/^server:/ && db { print " database:"; print " migrateFrom: \"database.db.old\"" }
END { if (port != "") { print "http:"; print " port: " port } }
' "${CONFIG_PATH}.v1.bak" >"$CONFIG_PATH"
}
# Existing installation
if [[ -f "$INSTALL_PATH" ]]; then
msg_warn "${APP} is already installed."
echo -n "${TAB}Uninstall ${APP}? (y/N): "
read -r uninstall_prompt
if [[ "${uninstall_prompt,,}" =~ ^(y|yes)$ ]]; then
msg_info "Uninstalling ${APP}"
if [[ "$OS" == "Debian" ]]; then
systemctl disable --now filebrowser.service &>/dev/null || true
rm -f "$SERVICE_PATH"
else
rc-service filebrowser stop &>/dev/null || true
rc-update del filebrowser &>/dev/null || true
rm -f "$SERVICE_PATH"
fi
rm -f "$INSTALL_PATH" "$CONFIG_PATH" "$HOME/.filebrowser-quantum"
msg_ok "${APP} has been uninstalled."
exit 0
fi
echo -n "${TAB}Update ${APP}? (y/N): "
read -r update_prompt
if [[ "${update_prompt,,}" =~ ^(y|yes)$ ]]; then
if check_for_gh_release "filebrowser-quantum" "gtsteffaniak/filebrowser"; then
msg_info "Updating ${APP}"
if ! command -v curl &>/dev/null; then $STD $PKG_MANAGER curl; fi
fetch_and_deploy_gh_release "filebrowser-quantum" "gtsteffaniak/filebrowser" "singlefile" "latest" "/usr/local/bin" "linux-$(arch_resolve)-filebrowser"
mv -f /usr/local/bin/filebrowser-quantum "$INSTALL_PATH"
if [[ -f "$CONFIG_PATH" ]]; then
sed -i '/^\s*disableIndexing:/d' "$CONFIG_PATH"
migrate_v1_config
fi
if [[ "$OS" == "Debian" ]]; then
systemctl restart filebrowser.service
else
rc-service filebrowser restart
fi
msg_ok "Updated ${APP}"
fi
exit 0
else
msg_warn "Update skipped. Exiting."
exit 0
fi
fi
msg_warn "${APP} is not installed."
echo -n "${TAB}Enter port number (Default: ${DEFAULT_PORT}): "
read -r PORT
PORT=${PORT:-$DEFAULT_PORT}
echo -n "${TAB}Install ${APP}? (y/n): "
read -r install_prompt
if ! [[ "${install_prompt,,}" =~ ^(y|yes)$ ]]; then
msg_warn "Installation skipped. Exiting."
exit 0
fi
msg_info "Installing ${APP} on ${OS}"
$STD $PKG_MANAGER \
curl \
ffmpeg
fetch_and_deploy_gh_release "filebrowser-quantum" "gtsteffaniak/filebrowser" "singlefile" "latest" "/usr/local/bin" "linux-$(arch_resolve)-filebrowser"
mv -f /usr/local/bin/filebrowser-quantum "$INSTALL_PATH"
msg_ok "Installed ${APP}"
msg_info "Preparing configuration directory"
mkdir -p /usr/local/community-scripts
chown root:root /usr/local/community-scripts
chmod 755 /usr/local/community-scripts
msg_ok "Directory prepared"
echo -n "${TAB}Use No Authentication? (y/N): "
read -r noauth_prompt
# === YAML CONFIG GENERATION ===
if [[ "${noauth_prompt,,}" =~ ^(y|yes)$ ]]; then
cat <<EOF >"$CONFIG_PATH"
http:
port: $PORT
server:
sources:
- path: "$SRC_DIR"
name: "RootFS"
config:
denyByDefault: false
rules:
- neverWatchPath: "/proc"
- neverWatchPath: "/sys"
- neverWatchPath: "/dev"
- neverWatchPath: "/run"
- neverWatchPath: "/tmp"
- neverWatchPath: "/lost+found"
auth:
methods:
noauth: true
EOF
msg_ok "Configured with no authentication"
else
cat <<EOF >"$CONFIG_PATH"
http:
port: $PORT
server:
sources:
- path: "$SRC_DIR"
name: "RootFS"
config:
denyByDefault: false
rules:
- neverWatchPath: "/proc"
- neverWatchPath: "/sys"
- neverWatchPath: "/dev"
- neverWatchPath: "/run"
- neverWatchPath: "/tmp"
- neverWatchPath: "/lost+found"
auth:
adminUsername: admin
adminPassword: community-scripts.org
EOF
msg_ok "Configured with default admin (admin / community-scripts.org)"
fi
msg_info "Creating service"
if [[ "$OS" == "Debian" ]]; then
cat <<EOF >"$SERVICE_PATH"
[Unit]
Description=FileBrowser Quantum
After=network.target
[Service]
User=root
WorkingDirectory=/usr/local/community-scripts
ExecStart=/usr/local/bin/filebrowser -c $CONFIG_PATH
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl enable --now filebrowser &>/dev/null
else
cat <<EOF >"$SERVICE_PATH"
#!/sbin/openrc-run
command="/usr/local/bin/filebrowser"
command_args="-c $CONFIG_PATH"
command_background=true
directory="/usr/local/community-scripts"
pidfile="/usr/local/community-scripts/pidfile"
depend() {
need net
}
EOF
chmod +x "$SERVICE_PATH"
$STD rc-update add filebrowser default
$STD rc-service filebrowser start
fi
msg_ok "Service created successfully"
msg_ok "${APP} is reachable at: ${BL}http://${IP}:${PORT}${CL}"