2026-04-14 23:55:08 +02:00
|
|
|
|
#!/bin/bash
|
2026-09-14 11:14:56 +02:00
|
|
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
# Script Name: system-update.sh
|
|
|
|
|
|
#
|
|
|
|
|
|
# Description:
|
|
|
|
|
|
# Performs automated system maintenance and package updates.
|
|
|
|
|
|
#
|
|
|
|
|
|
# Tasks:
|
|
|
|
|
|
# - apt update
|
|
|
|
|
|
# - apt upgrade
|
|
|
|
|
|
# - apt dist-upgrade
|
|
|
|
|
|
# - apt autoclean
|
|
|
|
|
|
# - apt autoremove
|
|
|
|
|
|
# - flatpak update
|
|
|
|
|
|
# - cleanup old log files
|
|
|
|
|
|
# - update Docker images
|
|
|
|
|
|
# - restart Docker service
|
|
|
|
|
|
# - maintain SpotDL Python virtual environment
|
|
|
|
|
|
# - install/update spotdl, yt-dlp and youtube-dl
|
|
|
|
|
|
# - optional email reporting
|
|
|
|
|
|
#
|
|
|
|
|
|
# Requirements:
|
|
|
|
|
|
# - apt
|
|
|
|
|
|
# - flatpak (optional)
|
|
|
|
|
|
# - python3-venv
|
|
|
|
|
|
# - docker (optional)
|
|
|
|
|
|
# - mail (optional, for -mail mode)
|
|
|
|
|
|
#
|
|
|
|
|
|
# Usage:
|
|
|
|
|
|
#
|
|
|
|
|
|
# Normal execution:
|
|
|
|
|
|
# ./system-update.sh
|
|
|
|
|
|
#
|
|
|
|
|
|
# Email report mode:
|
|
|
|
|
|
# ./system-update.sh -mail
|
|
|
|
|
|
#
|
|
|
|
|
|
# Logs:
|
|
|
|
|
|
# ~/.LOG/log_update_<timestamp>.log
|
|
|
|
|
|
#
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
|
|
|
|
set -o pipefail
|
2026-10-06 13:45:09 +02:00
|
|
|
|
usage() {
|
|
|
|
|
|
cat <<EOF
|
|
|
|
|
|
Usage: ${0##*/} [OPTIONS]
|
|
|
|
|
|
|
|
|
|
|
|
Update apt pythoni flatpak and docker
|
|
|
|
|
|
|
|
|
|
|
|
Options:
|
|
|
|
|
|
-h, --help Show this help message and exit
|
|
|
|
|
|
--version Show script version
|
|
|
|
|
|
|
|
|
|
|
|
EOF
|
|
|
|
|
|
}
|
2026-09-14 11:14:56 +02:00
|
|
|
|
|
2026-04-14 23:55:08 +02:00
|
|
|
|
home_dir="/home/lucas"
|
2026-09-14 11:14:56 +02:00
|
|
|
|
|
2026-04-14 23:55:08 +02:00
|
|
|
|
green="\e[32m"
|
|
|
|
|
|
red="\e[31m"
|
|
|
|
|
|
norm="\e[0m"
|
2026-09-14 11:14:56 +02:00
|
|
|
|
|
2026-04-14 23:55:08 +02:00
|
|
|
|
MAIL=false
|
2026-10-06 13:45:09 +02:00
|
|
|
|
BUILD=false
|
|
|
|
|
|
die() {
|
|
|
|
|
|
echo "Error: $*" >&2
|
|
|
|
|
|
echo
|
|
|
|
|
|
usage >&2
|
|
|
|
|
|
exit 2
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
parse_args() {
|
|
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
|
|
|
|
case "$1" in
|
|
|
|
|
|
-h|--help)
|
|
|
|
|
|
usage
|
|
|
|
|
|
exit 0
|
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
|
|
--version)
|
|
|
|
|
|
echo "${0##*/} 1.0"
|
|
|
|
|
|
exit 0
|
|
|
|
|
|
;;
|
|
|
|
|
|
--build)
|
|
|
|
|
|
BUILD=true
|
|
|
|
|
|
shift 1;
|
|
|
|
|
|
;;
|
|
|
|
|
|
--mail)
|
|
|
|
|
|
MAIL=true
|
|
|
|
|
|
shift 1;
|
|
|
|
|
|
;;
|
|
|
|
|
|
-*)
|
|
|
|
|
|
die "Unknown option: $1"
|
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
|
|
*)
|
|
|
|
|
|
die "Unexpected argument: $1"
|
|
|
|
|
|
;;
|
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
|
|
shift
|
|
|
|
|
|
done
|
|
|
|
|
|
}
|
2026-09-14 11:14:56 +02:00
|
|
|
|
|
|
|
|
|
|
write_out() {
|
|
|
|
|
|
if [[ "${MAIL}" == "true" ]]; then
|
|
|
|
|
|
printf "$@\n" >> /tmp/update.txt
|
|
|
|
|
|
else
|
|
|
|
|
|
printf "$@\n"
|
|
|
|
|
|
fi
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
echo "Start Update"
|
|
|
|
|
|
|
|
|
|
|
|
mkdir -p "${home_dir}/.LOG"
|
|
|
|
|
|
|
|
|
|
|
|
log_date="$(date +"%m%d%H")"
|
|
|
|
|
|
|
|
|
|
|
|
if [[ "$1" == "-mail" ]]; then
|
|
|
|
|
|
> /tmp/update.txt
|
|
|
|
|
|
|
|
|
|
|
|
exec 3>&1 4>&2 \
|
|
|
|
|
|
1>"${home_dir}/.LOG/log_update_${log_date}.log" \
|
|
|
|
|
|
2>&1
|
|
|
|
|
|
|
|
|
|
|
|
MAIL=true
|
|
|
|
|
|
green=""
|
|
|
|
|
|
red=""
|
|
|
|
|
|
norm=""
|
2026-04-14 23:55:08 +02:00
|
|
|
|
fi
|
2026-09-14 11:14:56 +02:00
|
|
|
|
|
2026-04-14 23:55:08 +02:00
|
|
|
|
write_out "Start: $(date)"
|
2026-09-14 11:14:56 +02:00
|
|
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
# System Updates
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
# Standard updates
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
|
|
|
|
CMD=(
|
|
|
|
|
|
"apt -y update"
|
|
|
|
|
|
"apt -y upgrade"
|
|
|
|
|
|
"apt -y dist-upgrade"
|
|
|
|
|
|
"apt -y autoclean"
|
|
|
|
|
|
"apt -y autoremove"
|
|
|
|
|
|
"find ${home_dir}/.LOG/ -name 'log_update_*' -mtime +6 -type f -delete"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
MSG=(
|
|
|
|
|
|
"update"
|
|
|
|
|
|
"upgrade"
|
|
|
|
|
|
"dist-upgrade"
|
|
|
|
|
|
"autoclean"
|
|
|
|
|
|
"autoremove"
|
|
|
|
|
|
"log-cleanup"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
for ((i=0; i<${#CMD[@]}; i++)); do
|
|
|
|
|
|
|
|
|
|
|
|
printf "Running: %s\n" "${CMD[$i]}"
|
|
|
|
|
|
|
2026-10-12 10:06:37 +00:00
|
|
|
|
if eval "sudo ${CMD[$i]}"; then
|
2026-09-14 11:14:56 +02:00
|
|
|
|
write_out "${MSG[$i]} [${green}OK${norm}]"
|
|
|
|
|
|
else
|
|
|
|
|
|
write_out "${MSG[$i]} [${red}FAIL${norm}]"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
2026-04-14 23:55:08 +02:00
|
|
|
|
done
|
|
|
|
|
|
|
2026-09-14 11:14:56 +02:00
|
|
|
|
###############################################################################
|
|
|
|
|
|
# Flatpak Update
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
|
|
|
|
if command -v flatpak >/dev/null 2>&1; then
|
|
|
|
|
|
|
|
|
|
|
|
echo "Starting Flatpak Update..."
|
|
|
|
|
|
|
2026-10-12 10:06:37 +00:00
|
|
|
|
sudo flatpak update -y --noninteractive
|
2026-09-14 11:14:56 +02:00
|
|
|
|
|
|
|
|
|
|
ret=$?
|
|
|
|
|
|
|
|
|
|
|
|
echo "Flatpak returned: ${ret}"
|
|
|
|
|
|
|
|
|
|
|
|
if [[ $ret -eq 0 ]]; then
|
|
|
|
|
|
write_out "flatpak-update [${green}OK${norm}]"
|
|
|
|
|
|
else
|
|
|
|
|
|
write_out "flatpak-update [${red}FAIL${norm}]"
|
|
|
|
|
|
fi
|
2026-04-14 23:55:08 +02:00
|
|
|
|
fi
|
2026-08-19 11:24:15 +02:00
|
|
|
|
|
2026-09-14 11:14:56 +02:00
|
|
|
|
echo "Finished Package Update"
|
2026-08-19 11:24:15 +02:00
|
|
|
|
|
2026-09-14 11:14:56 +02:00
|
|
|
|
###############################################################################
|
|
|
|
|
|
# SpotDL Virtual Environment
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-10-12 10:06:37 +00:00
|
|
|
|
PACKAGES=(
|
|
|
|
|
|
yt-dlp
|
|
|
|
|
|
spotdl
|
|
|
|
|
|
)
|
2026-09-14 11:14:56 +02:00
|
|
|
|
|
2026-10-12 10:06:37 +00:00
|
|
|
|
# Install pipx if missing
|
|
|
|
|
|
if ! command -v pipx >/dev/null 2>&1; then
|
|
|
|
|
|
echo "Installing pipx..."
|
|
|
|
|
|
sudo apt update
|
|
|
|
|
|
sudo apt install -y pipx
|
|
|
|
|
|
pipx ensurepath
|
2026-04-14 23:55:08 +02:00
|
|
|
|
fi
|
2026-10-12 10:06:37 +00:00
|
|
|
|
|
|
|
|
|
|
# Check ffmpeg
|
|
|
|
|
|
if ! command -v ffmpeg >/dev/null 2>&1; then
|
|
|
|
|
|
echo "Installing ffmpeg..."
|
|
|
|
|
|
sudo apt install -y ffmpeg
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Install or update packages
|
|
|
|
|
|
for pkg in "${PACKAGES[@]}"; do
|
|
|
|
|
|
if pipx list --short 2>/dev/null | grep -qx "$pkg"; then
|
|
|
|
|
|
echo "Updating $pkg..."
|
|
|
|
|
|
pipx upgrade "$pkg"
|
|
|
|
|
|
else
|
|
|
|
|
|
echo "Installing $pkg..."
|
|
|
|
|
|
pipx install "$pkg"
|
2026-09-26 13:18:01 +00:00
|
|
|
|
fi
|
2026-10-12 10:06:37 +00:00
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
|
|
# Install Deno for spotdl if missing
|
|
|
|
|
|
if ! command -v deno >/dev/null 2>&1; then
|
|
|
|
|
|
echo "Installing Deno..."
|
|
|
|
|
|
curl -fsSL https://deno.land/install.sh | sh
|
|
|
|
|
|
|
|
|
|
|
|
# Add to PATH for current shell
|
|
|
|
|
|
export PATH="$HOME/.deno/bin:$PATH"
|
2026-09-14 11:14:56 +02:00
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
# Docker Updates
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
|
|
|
|
if command -v docker >/dev/null 2>&1; then
|
|
|
|
|
|
|
|
|
|
|
|
echo "Updating Docker images"
|
|
|
|
|
|
|
2026-10-01 15:45:29 +02:00
|
|
|
|
docker images --format "{{.Repository}}:{{.Tag}}" |
|
|
|
|
|
|
while read -r image; do
|
2026-10-04 19:42:37 +00:00
|
|
|
|
echo "####################################################"
|
|
|
|
|
|
echo "### $image"
|
|
|
|
|
|
echo "####################################################"
|
|
|
|
|
|
|
2026-10-01 15:45:29 +02:00
|
|
|
|
case "$image" in
|
|
|
|
|
|
qbittorrent-qbittorrent:*)
|
|
|
|
|
|
echo "Updating custom qBittorrent image..."
|
|
|
|
|
|
(
|
2026-10-06 13:45:09 +02:00
|
|
|
|
latest="$(curl -s https://api.github.com/repos/qbittorrent/qBittorrent/releases/latest | grep '"tag_name"' | cut -d '"' -f 4 | cut -d '-' -f2)"
|
|
|
|
|
|
current="$(docker exec -it qbittorrent /app/qbittorrent-nox -v | cut -d 'v' -f2)"
|
|
|
|
|
|
if [[ "$LATEST" != "$CURRENT" && "$BUILD" == "true" ]]; then
|
|
|
|
|
|
echo "New version available: $CURRENT -> $LATEST"
|
|
|
|
|
|
cd /docker/qbittorrent &&
|
|
|
|
|
|
docker compose build --pull &&
|
|
|
|
|
|
docker compose up -d
|
|
|
|
|
|
elif [[ "$LATEST" != "$CURRENT" ]]; then
|
|
|
|
|
|
echo "New version available: $CURRENT -> $LATEST"
|
|
|
|
|
|
echo "BUILD is turend off"
|
|
|
|
|
|
else
|
|
|
|
|
|
echo "No new version available: $CURRENT == $LATEST"
|
|
|
|
|
|
fi
|
2026-10-01 15:45:29 +02:00
|
|
|
|
)
|
|
|
|
|
|
;;
|
2026-10-13 17:50:11 +00:00
|
|
|
|
nextcloud:*)
|
|
|
|
|
|
docker pull "$image"
|
|
|
|
|
|
docker exec -it nextcloud php occ app:update --all
|
|
|
|
|
|
;;
|
2026-10-01 15:45:29 +02:00
|
|
|
|
*"<none>"*)
|
|
|
|
|
|
;;
|
|
|
|
|
|
*)
|
|
|
|
|
|
docker pull "$image"
|
|
|
|
|
|
;;
|
|
|
|
|
|
esac
|
|
|
|
|
|
done
|
|
|
|
|
|
|
2026-09-14 11:14:56 +02:00
|
|
|
|
systemctl restart docker
|
|
|
|
|
|
|
|
|
|
|
|
if [[ $? -eq 0 ]]; then
|
|
|
|
|
|
write_out "docker [${green}OK${norm}]"
|
|
|
|
|
|
else
|
|
|
|
|
|
write_out "docker [${red}FAIL${norm}]"
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
2026-10-01 15:45:29 +02:00
|
|
|
|
if [ -f /docker/qbittorrent/docker-compose.yml ]; then
|
|
|
|
|
|
cd /docker/qbittorrent || exit 1
|
|
|
|
|
|
|
|
|
|
|
|
if docker compose config >/dev/null 2>&1; then
|
|
|
|
|
|
echo "Updating custom qBittorrent image..."
|
|
|
|
|
|
docker compose build --pull
|
|
|
|
|
|
docker compose up -d
|
|
|
|
|
|
fi
|
|
|
|
|
|
fi
|
2026-10-04 19:42:37 +00:00
|
|
|
|
|
|
|
|
|
|
for d in /docker/*; do
|
|
|
|
|
|
if [ -d $d ]; then
|
|
|
|
|
|
docker compose -f $d/docker-compose.yaml up -d
|
|
|
|
|
|
fi
|
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-10-02 10:59:01 +00:00
|
|
|
|
docker container prune -f
|
|
|
|
|
|
docker network prune -f
|
|
|
|
|
|
docker image prune -a -f
|
|
|
|
|
|
docker builder prune -f
|
2026-10-01 15:45:29 +02:00
|
|
|
|
|
2026-10-04 19:42:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
2026-09-14 11:14:56 +02:00
|
|
|
|
###############################################################################
|
|
|
|
|
|
# Mail Report
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
|
|
|
|
|
|
|
if [[ "${MAIL}" == "true" ]]; then
|
|
|
|
|
|
|
|
|
|
|
|
mail_str="$(cat /tmp/update.txt)"
|
|
|
|
|
|
|
|
|
|
|
|
echo "$mail_str" | mail \
|
|
|
|
|
|
-s "Automated Server Message - Upgrade" \
|
|
|
|
|
|
lucas-f@live.at
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
2026-09-26 13:18:01 +00:00
|
|
|
|
write_out "Finished: $(date)"
|