Compare commits

..

1 Commits

Author SHA1 Message Date
CanbiZ (MickLesk)
ec1ea0b539 Make shell command substitutions safe with || true
Add defensive fallbacks (|| true) to multiple command substitutions to prevent non-zero exits when commands produce no output or are unavailable. Changes touch misc/api.func, misc/build.func and misc/tools.func and cover places like lspci, /proc/cpuinfo parsing, /etc/os-release reads, hostname -I usage, grep reads from vars files and maps, pct config parsing, storage/template lookups, tool version detection, NVIDIA driver version extraction, and MeiliSearch config parsing. These edits do not change functional behavior aside from ensuring the scripts continue running (variables will be empty) instead of failing in stricter shells or when commands return non-zero status.
2026-03-25 08:59:11 +01:00
44 changed files with 440 additions and 671 deletions

View File

@@ -426,28 +426,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details>
## 2026-03-26
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Immich: Bump to 2.6.2 | use start.sh in service, ensure DB_HOSTNAME in .env | Fix Rights Issue with ZFS Shares [@MickLesk](https://github.com/MickLesk) ([#13199](https://github.com/community-scripts/ProxmoxVE/pull/13199))
- #### ✨ New Features
- SparkyFitness: add garmin microservice as addon [@tomfrenzel](https://github.com/tomfrenzel) ([#12642](https://github.com/community-scripts/ProxmoxVE/pull/12642))
### 💾 Core
- #### 🐞 Bug Fixes
- tools.func: pin npm to 11.11.0 to work around Node.js 22.22.2 regression [@MickLesk](https://github.com/MickLesk) ([#13296](https://github.com/community-scripts/ProxmoxVE/pull/13296))
- #### 🔧 Refactor
- core: use /usr/bin/install to prevent function shadowing [@MickLesk](https://github.com/MickLesk) ([#13299](https://github.com/community-scripts/ProxmoxVE/pull/13299))
## 2026-03-25
### 🚀 Updated Scripts
@@ -456,12 +434,6 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
- Komodo v2: migrate env vars to v2 and update source [@MickLesk](https://github.com/MickLesk) ([#13262](https://github.com/community-scripts/ProxmoxVE/pull/13262))
### 💾 Core
- #### 🔧 Refactor
- core: make shell command substitutions safe with || true [@MickLesk](https://github.com/MickLesk) ([#13279](https://github.com/community-scripts/ProxmoxVE/pull/13279))
## 2026-03-24
### 🆕 New Scripts

View File

@@ -5,7 +5,7 @@
<p><em>A Community Legacy in Memory of @tteck</em></p>
<p>
<a href="https://community-scripts.org">
<a href="https://community-scripts.com">
<img src="https://img.shields.io/badge/🌐_Website-Visit-4c9b3f?style=for-the-badge&labelColor=2d3748" alt="Website" />
</a>
<a href="https://discord.gg/3AnUqsXnmK">

View File

@@ -73,7 +73,7 @@ function update_script() {
$STD curl -fsSL https://github.com/filebrowser/filebrowser/releases/download/v2.23.0/linux-amd64-filebrowser.tar.gz | tar -xzv -C /usr/local/bin
$STD filebrowser config init -a '0.0.0.0'
$STD filebrowser config set -a '0.0.0.0'
$STD filebrowser users add admin community-scripts.org --perm.admin
$STD filebrowser users add admin community-scripts.com --perm.admin
msg_ok "Installed FileBrowser"
msg_info "Creating Service"
@@ -93,7 +93,7 @@ WantedBy=default.target" >$service_path
msg_ok "Completed successfully!\n"
echo -e "FileBrowser should be reachable by going to the following URL.
${BL}http://$LOCAL_IP:8080${CL} admin|community-scripts.org\n"
${BL}http://$LOCAL_IP:8080${CL} admin|community-scripts.com\n"
exit
fi
}

View File

@@ -109,7 +109,7 @@ EOF
msg_ok "Image-processing libraries up to date"
fi
RELEASE="v2.6.2"
RELEASE="v2.6.1"
if check_for_gh_release "Immich" "immich-app/immich" "${RELEASE}" "each release is tested individually before the version is updated. Please do not open issues for this"; then
if [[ $(cat ~/.immich) > "2.5.1" ]]; then
msg_info "Enabling Maintenance Mode"
@@ -214,10 +214,7 @@ EOF
cd "$SRC_DIR"/machine-learning
mkdir -p "$ML_DIR"
# chown excluding upload dir contents (may be a mount with restricted permissions)
chown immich:immich "$INSTALL_DIR"
find "$INSTALL_DIR" -maxdepth 1 -mindepth 1 ! -name upload -exec chown -R immich:immich {} +
chown immich:immich "${UPLOAD_DIR:-$INSTALL_DIR/upload}" 2>/dev/null || true
chown -R immich:immich "$INSTALL_DIR"
chown immich:immich ./uv.lock
export VIRTUAL_ENV="${ML_DIR}"/ml-venv
export UV_HTTP_TIMEOUT=300
@@ -266,20 +263,7 @@ EOF
[[ ! -f /usr/bin/immich ]] && ln -sf "$APP_DIR"/cli/bin/immich /usr/bin/immich
[[ ! -f /usr/bin/immich-admin ]] && ln -sf "$APP_DIR"/bin/immich-admin /usr/bin/immich-admin
if ! grep -q '^DB_HOSTNAME=' "$INSTALL_DIR"/.env; then
sed -i '/^DB_DATABASE_NAME/a DB_HOSTNAME=127.0.0.1' "$INSTALL_DIR"/.env
fi
if grep -q 'ExecStart=/usr/bin/node' /etc/systemd/system/immich-web.service; then
sed -i '/^EnvironmentFile=/d' /etc/systemd/system/immich-web.service
sed -i "s|^ExecStart=.*|ExecStart=${APP_DIR}/bin/start.sh|" /etc/systemd/system/immich-web.service
systemctl daemon-reload
fi
# chown excluding upload dir contents (may be a mount with restricted permissions)
chown immich:immich "$INSTALL_DIR"
find "$INSTALL_DIR" -maxdepth 1 -mindepth 1 ! -name upload -exec chown -R immich:immich {} +
chown immich:immich "${UPLOAD_DIR:-$INSTALL_DIR/upload}" 2>/dev/null || true
chown -R immich:immich "$INSTALL_DIR"
if [[ "${MAINT_MODE:-0}" == 1 ]]; then
msg_info "Disabling Maintenance Mode"
cd /opt/immich/app/bin

View File

@@ -68,7 +68,7 @@ function update_script() {
$STD curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | bash
$STD filebrowser config init -a '0.0.0.0'
$STD filebrowser config set -a '0.0.0.0'
$STD filebrowser users add admin community-scripts.org --perm.admin
$STD filebrowser users add admin community-scripts.com --perm.admin
msg_ok "Installed FileBrowser"
msg_info "Creating Service"
@@ -90,7 +90,7 @@ EOF
msg_ok "Completed successfully!\n"
echo -e "FileBrowser should be reachable by going to the following URL.
${BL}http://$LOCAL_IP:8080${CL} admin|community-scripts.org\n"
${BL}http://$LOCAL_IP:8080${CL} admin|community-scripts.com\n"
exit
fi
if [ "$UPD" == "4" ]; then

View File

@@ -50,7 +50,7 @@ function update_script() {
/opt/semaphore/config.json
SEM_PW=$(cat ~/semaphore.creds)
systemctl start semaphore
$STD semaphore user add --admin --login admin --email admin@community-scripts.org --name Administrator --password "${SEM_PW}" --config /opt/semaphore/config.json
$STD semaphore user add --admin --login admin --email admin@community-scripts.com --name Administrator --password "${SEM_PW}" --config /opt/semaphore/config.json
msg_ok "Moved from BoltDB to SQLite"
fi

View File

@@ -62,10 +62,10 @@ expect "Email address"
send "\r"
expect "Password"
send "community-scripts.org\r"
send "community-scripts.com\r"
expect "Password (again)"
send "community-scripts.org\r"
send "community-scripts.com\r"
expect eof
EOF

View File

@@ -58,7 +58,7 @@ service:
use_prerelease: false
dashboard:
icon: https://raw.githubusercontent.com/community-scripts/ProxmoxVE/refs/heads/main/misc/images/logo.png
icon_link_to: https://community-scripts.org/
icon_link_to: https://community-scripts.com/
web_url: https://github.com/community-scripts/ProxmoxVE/releases
EOF
msg_ok "Setup Config"

View File

@@ -35,7 +35,7 @@ PG_DB_NAME="healthchecks_db" PG_DB_USER="hc_user" PG_DB_PASS=$(openssl rand -bas
msg_info "Setup Keys (Admin / Secret)"
SECRET_KEY="$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | cut -c1-32)"
ADMIN_EMAIL="admin@community-scripts.org"
ADMIN_EMAIL="admin@community-scripts.com"
ADMIN_PASSWORD="$PG_DB_PASS"
{
echo "healthchecks Admin Email: $ADMIN_EMAIL"

View File

@@ -295,7 +295,7 @@ ML_DIR="${APP_DIR}/machine-learning"
GEO_DIR="${INSTALL_DIR}/geodata"
mkdir -p {"${APP_DIR}","${UPLOAD_DIR}","${GEO_DIR}","${INSTALL_DIR}"/cache}
fetch_and_deploy_gh_release "Immich" "immich-app/immich" "tarball" "v2.6.2" "$SRC_DIR"
fetch_and_deploy_gh_release "Immich" "immich-app/immich" "tarball" "v2.6.1" "$SRC_DIR"
PNPM_VERSION="$(jq -r '.packageManager | split("@")[1] | split("+")[0]' ${SRC_DIR}/package.json)"
NODE_VERSION="24" NODE_MODULE="pnpm@${PNPM_VERSION}" setup_nodejs
@@ -344,11 +344,7 @@ msg_ok "Installed Immich Server, Web and Plugin Components"
cd "$SRC_DIR"/machine-learning
$STD useradd -U -s /usr/sbin/nologin -r -M -d "$INSTALL_DIR" immich
mkdir -p "$ML_DIR"
# chown excluding upload dir contents (may be a mount with restricted permissions)
chown immich:immich "$INSTALL_DIR"
find "$INSTALL_DIR" -maxdepth 1 -mindepth 1 ! -name upload -exec chown -R immich:immich {} +
chown immich:immich "$UPLOAD_DIR" 2>/dev/null || true
mkdir -p "$ML_DIR" && chown -R immich:immich "$INSTALL_DIR"
export VIRTUAL_ENV="${ML_DIR}/ml-venv"
export UV_HTTP_TIMEOUT=300
if [[ -f ~/.openvino ]]; then
@@ -473,7 +469,8 @@ User=immich
Group=immich
UMask=0077
WorkingDirectory=${APP_DIR}
ExecStart=${APP_DIR}/bin/start.sh
EnvironmentFile=${INSTALL_DIR}/.env
ExecStart=/usr/bin/node ${APP_DIR}/dist/main
Restart=on-failure
SyslogIdentifier=immich-web
StandardOutput=append:/var/log/immich/web.log
@@ -503,11 +500,7 @@ StandardError=append:/var/log/immich/ml.log
[Install]
WantedBy=multi-user.target
EOF
chown -R immich:immich /var/log/immich
# chown excluding upload dir contents (may be a mount with restricted permissions)
chown immich:immich "$INSTALL_DIR"
find "$INSTALL_DIR" -maxdepth 1 -mindepth 1 ! -name upload -exec chown -R immich:immich {} +
chown immich:immich "$UPLOAD_DIR" 2>/dev/null || true
chown -R immich:immich "$INSTALL_DIR" /var/log/immich
systemctl enable -q --now immich-ml.service immich-web.service
msg_ok "Modified user, created env file, scripts and services"

View File

@@ -17,7 +17,7 @@ fetch_and_deploy_gh_release "inspircd" "inspircd/inspircd" "binary" "latest" "/o
msg_info "Configuring InspIRCd"
cat <<EOF >/etc/inspircd/inspircd.conf
<define name="networkDomain" value="community-scripts.org">
<define name="networkDomain" value="community-scripts.com">
<define name="networkName" value="Proxmox VE Helper-Scripts">
<server

View File

@@ -55,10 +55,10 @@ $STD expect <<EOF
set timeout -1
log_user 0
spawn bin/console kimai:user:create admin admin@community-scripts.org ROLE_SUPER_ADMIN
spawn bin/console kimai:user:create admin admin@community-scripts.com ROLE_SUPER_ADMIN
expect "Please enter the password:"
send "community-scripts.org\r"
send "community-scripts.com\r"
expect eof
EOF

View File

@@ -33,7 +33,7 @@ $STD yarn config set ignore-engines true
$STD yarn install
$STD yarn run production
$STD php artisan key:generate
$STD php artisan setup:production --email=admin@community-scripts.org --password=community-scripts.org --force
$STD php artisan setup:production --email=admin@community-scripts.com --password=community-scripts.com --force
chown -R www-data:www-data /opt/monica
chmod -R 775 /opt/monica/storage
echo "* * * * * root php /opt/monica/artisan schedule:run >> /dev/null 2>&1" >>/etc/crontab

View File

@@ -94,7 +94,7 @@ expect "Administrator username" {
send "community-scripts\r"
}
expect "Administrator email address" {
send "admin@community-scripts.org\r"
send "admin@community-scripts.com\r"
}
expect "Password" {
send "community-scripts\r"

View File

@@ -60,7 +60,7 @@ read -r -p "${TAB3}Enter your ACME Email: " ACME_EMAIL_INPUT
yq -i "
.services.npmplus.environment |=
(map(select(. != \"TZ=*\" and . != \"ACME_EMAIL=*\" and . != \"INITIAL_ADMIN_EMAIL=*\" and . != \"INITIAL_ADMIN_PASSWORD=*\")) +
[\"TZ=$TZ_INPUT\", \"ACME_EMAIL=$ACME_EMAIL_INPUT\", \"INITIAL_ADMIN_EMAIL=admin@local.com\", \"INITIAL_ADMIN_PASSWORD=community-scripts.org\"])
[\"TZ=$TZ_INPUT\", \"ACME_EMAIL=$ACME_EMAIL_INPUT\", \"INITIAL_ADMIN_EMAIL=admin@local.com\", \"INITIAL_ADMIN_PASSWORD=community-scripts.com\"])
" /opt/compose.yaml
msg_info "Building and Starting NPMplus (Patience)"

View File

@@ -99,7 +99,7 @@ PHOTOPRISM_DEBUG='false'
PHOTOPRISM_LOG_LEVEL='info'
# Site Info
PHOTOPRISM_SITE_CAPTION='https://community-scripts.org'
PHOTOPRISM_SITE_CAPTION='https://community-scripts.com'
PHOTOPRISM_SITE_DESCRIPTION=''
PHOTOPRISM_SITE_AUTHOR=''
EOF

View File

@@ -40,7 +40,7 @@ cat <<EOF >/opt/semaphore/config.json
"access_key_encryption": "${SEM_KEY}"
}
EOF
$STD semaphore user add --admin --login admin --email admin@community-scripts.org --name Administrator --password "${SEM_PW}" --config /opt/semaphore/config.json
$STD semaphore user add --admin --login admin --email admin@community-scripts.com --name Administrator --password "${SEM_PW}" --config /opt/semaphore/config.json
echo "${SEM_PW}" >~/semaphore.creds
msg_ok "Setup Semaphore"

View File

@@ -40,7 +40,6 @@ sed \
-e "s|^SPARKY_FITNESS_SERVER_HOST=.*|SPARKY_FITNESS_SERVER_HOST=localhost|" \
-e "s|^SPARKY_FITNESS_SERVER_PORT=.*|SPARKY_FITNESS_SERVER_PORT=3010|" \
-e "s|^SPARKY_FITNESS_FRONTEND_URL=.*|SPARKY_FITNESS_FRONTEND_URL=http://${LOCAL_IP}:80|" \
-e "s|^GARMIN_MICROSERVICE_URL=.*|GARMIN_MICROSERVICE_URL=http://${LOCAL_IP}:8000|" \
-e "s|^SPARKY_FITNESS_API_ENCRYPTION_KEY=.*|SPARKY_FITNESS_API_ENCRYPTION_KEY=$(openssl rand -hex 32)|" \
-e "s|^BETTER_AUTH_SECRET=.*|BETTER_AUTH_SECRET=$(openssl rand -hex 32)|" \
"/etc/sparkyfitness/.env"

View File

@@ -20,7 +20,7 @@ need_tool() {
msg_info "Installing tools: $*"
apk add --no-cache "$@" >/dev/null 2>&1 || {
msg_error "apk add failed for: $*"
return 100
return 1
}
msg_ok "Tools ready: $*"
fi
@@ -52,17 +52,17 @@ ensure_usr_local_bin_persist() {
download_with_progress() {
# $1 url, $2 dest
local url="$1" out="$2" cl
need_tool curl pv || return 127
need_tool curl pv || return 1
cl=$(curl -fsSLI "$url" 2>/dev/null | awk 'tolower($0) ~ /^content-length:/ {print $2}' | tr -d '\r')
if [ -n "$cl" ]; then
curl -fsSL "$url" | pv -s "$cl" >"$out" || {
msg_error "Download failed: $url"
return 250
return 1
}
else
curl -fL# -o "$out" "$url" || {
msg_error "Download failed: $url"
return 250
return 1
}
fi
}
@@ -82,14 +82,14 @@ check_for_gh_release() {
net_resolves api.github.com || {
msg_error "DNS/network error: api.github.com"
return 6
return 1
}
need_tool curl jq || return 127
need_tool curl jq || return 1
tag=$(curl -fsSL "https://api.github.com/repos/${source}/releases/latest" | jq -r '.tag_name // empty')
[ -z "$tag" ] && {
msg_error "Unable to fetch latest tag for $app"
return 22
return 1
}
release="${tag#v}"
@@ -133,12 +133,12 @@ fetch_and_deploy_gh() {
net_resolves api.github.com || {
msg_error "DNS/network error"
return 6
return 1
}
need_tool curl jq tar || return 127
need_tool curl jq tar || return 1
[ "$mode" = "prebuild" ] || [ "$mode" = "singlefile" ] && need_tool unzip >/dev/null 2>&1 || true
tmpd="$(mktemp -d)" || return 252
tmpd="$(mktemp -d)" || return 1
mkdir -p "$target"
# Release JSON
@@ -146,13 +146,13 @@ fetch_and_deploy_gh() {
json="$(curl -fsSL "https://api.github.com/repos/$repo/releases/latest")" || {
msg_error "GitHub API failed"
rm -rf "$tmpd"
return 22
return 1
}
else
json="$(curl -fsSL "https://api.github.com/repos/$repo/releases/tags/$version")" || {
msg_error "GitHub API failed"
rm -rf "$tmpd"
return 22
return 1
}
fi
@@ -163,7 +163,7 @@ fetch_and_deploy_gh() {
[ -z "$version" ] && {
msg_error "No tag in release json"
rm -rf "$tmpd"
return 65
return 1
}
case "$mode" in
@@ -173,26 +173,26 @@ fetch_and_deploy_gh() {
filename="${app_lc}-${version}.tar.gz"
download_with_progress "$url" "$tmpd/$filename" || {
rm -rf "$tmpd"
return 250
return 1
}
tar -xzf "$tmpd/$filename" -C "$tmpd" || {
msg_error "tar extract failed"
rm -rf "$tmpd"
return 251
return 1
}
unpack="$(find "$tmpd" -mindepth 1 -maxdepth 1 -type d | head -n1)"
# copy content of unpack to target
(cd "$unpack" && tar -cf - .) | (cd "$target" && tar -xf -) || {
msg_error "copy failed"
rm -rf "$tmpd"
return 252
return 1
}
;;
prebuild)
[ -n "$pattern" ] || {
msg_error "prebuild requires asset pattern"
rm -rf "$tmpd"
return 65
return 1
}
url="$(printf '%s' "$json" | jq -r '.assets[].browser_download_url' | awk -v p="$pattern" '
BEGIN{IGNORECASE=1}
@@ -201,19 +201,19 @@ fetch_and_deploy_gh() {
[ -z "$url" ] && {
msg_error "asset not found for pattern: $pattern"
rm -rf "$tmpd"
return 250
return 1
}
filename="${url##*/}"
download_with_progress "$url" "$tmpd/$filename" || {
rm -rf "$tmpd"
return 250
return 1
}
# unpack archive (Zip or tarball)
case "$filename" in
*.zip)
need_tool unzip || {
rm -rf "$tmpd"
return 127
return 1
}
mkdir -p "$tmpd/unp"
unzip -q "$tmpd/$filename" -d "$tmpd/unp"
@@ -225,7 +225,7 @@ fetch_and_deploy_gh() {
*)
msg_error "unsupported archive: $filename"
rm -rf "$tmpd"
return 251
return 1
;;
esac
# top-level folder strippen
@@ -234,13 +234,13 @@ fetch_and_deploy_gh() {
(cd "$unpack" && tar -cf - .) | (cd "$target" && tar -xf -) || {
msg_error "copy failed"
rm -rf "$tmpd"
return 252
return 1
}
else
(cd "$tmpd/unp" && tar -cf - .) | (cd "$target" && tar -xf -) || {
msg_error "copy failed"
rm -rf "$tmpd"
return 252
return 1
}
fi
;;
@@ -248,7 +248,7 @@ fetch_and_deploy_gh() {
[ -n "$pattern" ] || {
msg_error "singlefile requires asset pattern"
rm -rf "$tmpd"
return 65
return 1
}
url="$(printf '%s' "$json" | jq -r '.assets[].browser_download_url' | awk -v p="$pattern" '
BEGIN{IGNORECASE=1}
@@ -257,19 +257,19 @@ fetch_and_deploy_gh() {
[ -z "$url" ] && {
msg_error "asset not found for pattern: $pattern"
rm -rf "$tmpd"
return 250
return 1
}
filename="${url##*/}"
download_with_progress "$url" "$target/$app" || {
rm -rf "$tmpd"
return 250
return 1
}
chmod +x "$target/$app"
;;
*)
msg_error "Unknown mode: $mode"
rm -rf "$tmpd"
return 65
return 1
;;
esac
@@ -291,20 +291,20 @@ setup_yq() {
return 0
fi
need_tool curl || return 127
need_tool curl || return 1
local arch bin url tmp
case "$(uname -m)" in
x86_64) arch="amd64" ;;
aarch64) arch="arm64" ;;
*)
msg_error "Unsupported arch for yq: $(uname -m)"
return 238
return 1
;;
esac
url="https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${arch}"
tmp="$(mktemp)"
download_with_progress "$url" "$tmp" || return 250
/usr/bin/install -m 0755 "$tmp" /usr/local/bin/yq
download_with_progress "$url" "$tmp" || return 1
install -m 0755 "$tmp" /usr/local/bin/yq
rm -f "$tmp"
msg_ok "Setup yq ($(yq --version 2>/dev/null))"
}
@@ -313,13 +313,13 @@ setup_yq() {
# Adminer Alpine
# ------------------------------
setup_adminer() {
need_tool curl || return 127
need_tool curl || return 1
msg_info "Setup Adminer (Alpine)"
mkdir -p /var/www/localhost/htdocs/adminer
curl -fsSL https://github.com/vrana/adminer/releases/latest/download/adminer.php \
-o /var/www/localhost/htdocs/adminer/index.php || {
msg_error "Adminer download failed"
return 250
return 1
}
msg_ok "Adminer at /adminer (served by your webserver)"
}
@@ -329,7 +329,7 @@ setup_adminer() {
# optional: PYTHON_VERSION="3.12"
# ------------------------------
setup_uv() {
need_tool curl tar || return 127
need_tool curl tar || return 1
local UV_BIN="/usr/local/bin/uv"
local arch tarball url tmpd ver installed
@@ -338,7 +338,7 @@ setup_uv() {
aarch64) arch="aarch64-unknown-linux-musl" ;;
*)
msg_error "Unsupported arch for uv: $(uname -m)"
return 238
return 1
;;
esac
@@ -346,7 +346,7 @@ setup_uv() {
ver="${ver#v}"
[ -z "$ver" ] && {
msg_error "uv: cannot determine latest version"
return 250
return 1
}
if has "$UV_BIN"; then
@@ -360,29 +360,29 @@ setup_uv() {
msg_info "Setup uv $ver"
fi
tmpd="$(mktemp -d)" || return 252
tmpd="$(mktemp -d)" || return 1
tarball="uv-${arch}.tar.gz"
url="https://github.com/astral-sh/uv/releases/download/v${ver}/${tarball}"
download_with_progress "$url" "$tmpd/uv.tar.gz" || {
rm -rf "$tmpd"
return 250
return 1
}
tar -xzf "$tmpd/uv.tar.gz" -C "$tmpd" || {
msg_error "uv: extract failed"
rm -rf "$tmpd"
return 251
return 1
}
# tar contains ./uv
if [ -x "$tmpd/uv" ]; then
/usr/bin/install -m 0755 "$tmpd/uv" "$UV_BIN"
install -m 0755 "$tmpd/uv" "$UV_BIN"
else
# fallback: in subfolder
/usr/bin/install -m 0755 "$tmpd"/*/uv "$UV_BIN" 2>/dev/null || {
install -m 0755 "$tmpd"/*/uv "$UV_BIN" 2>/dev/null || {
msg_error "uv binary not found in tar"
rm -rf "$tmpd"
return 252
return 1
}
fi
rm -rf "$tmpd"
@@ -395,13 +395,13 @@ setup_uv() {
$0 ~ "^cpython-"maj"\\." { print $0 }' | awk -F- '{print $2}' | sort -V | tail -n1)"
[ -z "$match" ] && {
msg_error "No matching Python for $PYTHON_VERSION"
return 250
return 1
}
if ! uv python list | grep -q "cpython-${match}-linux"; then
msg_info "Installing Python $match via uv"
uv python install "$match" || {
msg_error "uv python install failed"
return 150
return 1
}
msg_ok "Python $match installed (uv)"
fi
@@ -421,7 +421,7 @@ setup_java() {
msg_info "Setup Java (OpenJDK $JAVA_VERSION)"
apk add --no-cache "$pkg" >/dev/null 2>&1 || {
msg_error "apk add $pkg failed"
return 100
return 1
}
# set JAVA_HOME
local prof="/etc/profile.d/20-java.sh"
@@ -441,32 +441,32 @@ setup_go() {
msg_info "Setup Go (apk)"
apk add --no-cache go >/dev/null 2>&1 || {
msg_error "apk add go failed"
return 100
return 1
}
msg_ok "Go ready: $(go version 2>/dev/null)"
return 0
fi
need_tool curl tar || return 127
need_tool curl tar || return 1
local ARCH TARBALL URL TMP
case "$(uname -m)" in
x86_64) ARCH="amd64" ;;
aarch64) ARCH="arm64" ;;
*)
msg_error "Unsupported arch for Go: $(uname -m)"
return 238
return 1
;;
esac
TARBALL="go${GO_VERSION}.linux-${ARCH}.tar.gz"
URL="https://go.dev/dl/${TARBALL}"
msg_info "Setup Go $GO_VERSION (tarball)"
TMP="$(mktemp)"
download_with_progress "$URL" "$TMP" || return 250
download_with_progress "$URL" "$TMP" || return 1
rm -rf /usr/local/go
tar -C /usr/local -xzf "$TMP" || {
msg_error "extract go failed"
rm -f "$TMP"
return 251
return 1
}
rm -f "$TMP"
ln -sf /usr/local/go/bin/go /usr/local/bin/go
@@ -488,7 +488,7 @@ setup_composer() {
# Fallback to generic php if 83 not available
apk add --no-cache php-cli php-openssl php-phar php-iconv >/dev/null 2>&1 || {
msg_error "Failed to install php-cli for composer"
return 100
return 1
}
}
msg_ok "PHP CLI ready: $(php -v | head -n1)"
@@ -500,14 +500,14 @@ setup_composer() {
msg_info "Setup Composer"
fi
need_tool curl || return 127
need_tool curl || return 1
curl -fsSL https://getcomposer.org/installer -o /tmp/composer-setup.php || {
msg_error "composer installer download failed"
return 250
return 1
}
php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer >/dev/null 2>&1 || {
msg_error "composer install failed"
return 150
return 1
}
rm -f /tmp/composer-setup.php
ensure_usr_local_bin_persist

View File

@@ -267,12 +267,12 @@ install_ssh_keys_into_ct() {
msg_info "Installing selected SSH keys into CT ${CTID}"
pct exec "$CTID" -- sh -c 'mkdir -p /root/.ssh && chmod 700 /root/.ssh' || {
msg_error "prepare /root/.ssh failed"
return 252
return 1
}
pct push "$CTID" "$SSH_KEYS_FILE" /root/.ssh/authorized_keys >/dev/null 2>&1 ||
pct exec "$CTID" -- sh -c "cat > /root/.ssh/authorized_keys" <"$SSH_KEYS_FILE" || {
msg_error "write authorized_keys failed"
return 252
return 1
}
pct exec "$CTID" -- sh -c 'chmod 600 /root/.ssh/authorized_keys' || true
msg_ok "Installed SSH keys into CT ${CTID}"
@@ -839,7 +839,7 @@ choose_and_set_storage_for_file() {
template) key="var_template_storage" ;;
*)
msg_error "Unknown storage class: $class"
return 65
return 1
;;
esac
@@ -862,7 +862,7 @@ choose_and_set_storage_for_file() {
fi
else
# If the current value is preselectable, we could show it, but per your requirement we always offer selection
select_storage "$class" || return 150
select_storage "$class" || return 1
fi
_write_storage_to_vars "$vf" "$key" "$STORAGE_RESULT"
@@ -1264,7 +1264,7 @@ default_var_settings() {
return 0
}
done
return 252
return 1
}
# Allow override of storages via env (for non-interactive use cases)
[ -n "${var_template_storage:-}" ] && TEMPLATE_STORAGE="$var_template_storage"
@@ -1357,7 +1357,7 @@ EOF
local dv
dv="$(_find_default_vars)" || {
msg_error "default.vars not found after ensure step"
return 252
return 1
}
load_vars_file "$dv"
@@ -1642,7 +1642,7 @@ maybe_offer_save_app_defaults() {
if whiptail --backtitle "Proxmox VE Helper Scripts" \
--yesno "Save these advanced settings as defaults for ${APP}?\n\nThis will create:\n${app_vars_path}" 12 72; then
mkdir -p "$(dirname "$app_vars_path")"
/usr/bin/install -m 0644 "$new_tmp" "$app_vars_path"
install -m 0644 "$new_tmp" "$app_vars_path"
msg_ok "Saved app defaults: ${app_vars_path}"
fi
rm -f "$new_tmp" "$diff_tmp"
@@ -1676,7 +1676,7 @@ maybe_offer_save_app_defaults() {
case "$sel" in
"Update Defaults")
/usr/bin/install -m 0644 "$new_tmp" "$app_vars_path"
install -m 0644 "$new_tmp" "$app_vars_path"
msg_ok "Updated app defaults: ${app_vars_path}"
break
;;
@@ -4690,7 +4690,7 @@ EOF'
destroy_lxc() {
if [[ -z "$CT_ID" ]]; then
msg_error "No CT_ID found. Nothing to remove."
return 65
return 1
fi
# Abort on Ctrl-C / Ctrl-D / ESC
@@ -4729,12 +4729,12 @@ resolve_storage_preselect() {
case "$class" in
template) required_content="vztmpl" ;;
container) required_content="rootdir" ;;
*) return 65 ;;
*) return 1 ;;
esac
[[ -z "$preselect" ]] && return 1
if ! pvesm status -content "$required_content" | awk 'NR>1{print $1}' | grep -qx -- "$preselect"; then
msg_warn "Preselected storage '${preselect}' does not support content '${required_content}' (or not found)"
return 238
return 1
fi
local line total used free
@@ -4858,7 +4858,7 @@ select_storage() {
;;
*)
msg_error "Invalid storage class '$CLASS'"
return 65
return 1
;;
esac
@@ -4940,7 +4940,7 @@ validate_storage_space() {
# Check if storage exists and is active
if [[ -z "$storage_line" ]]; then
[[ "$show_dialog" == "yes" ]] && whiptail --msgbox "⚠️ Warning: Storage '$storage' not found!\n\nThe storage may be unavailable or disabled." 10 60
return 236
return 2
fi
# Check storage status (column 3)
@@ -4948,7 +4948,7 @@ validate_storage_space() {
status=$(awk '{print $3}' <<<"$storage_line")
if [[ "$status" == "disabled" ]]; then
[[ "$show_dialog" == "yes" ]] && whiptail --msgbox "⚠️ Warning: Storage '$storage' is disabled!\n\nPlease enable the storage first." 10 60
return 236
return 2
fi
# Get storage type and free space (column 6)
@@ -4971,7 +4971,7 @@ validate_storage_space() {
if [[ "$show_dialog" == "yes" ]]; then
whiptail --msgbox "⚠️ Warning: Storage '$storage' may not have enough space!\n\nStorage Type: ${storage_type}\nRequired: ${required_gb}GB\nAvailable: ${free_gb_fmt}\n\nYou can continue, but creation might fail." 14 70
fi
return 236
return 1
fi
return 0
@@ -5704,7 +5704,7 @@ description() {
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>

View File

@@ -319,11 +319,11 @@ function setup_cloud_init() {
if [ "$network_mode" = "static" ]; then
if [ -n "$static_ip" ] && ! validate_ip_cidr "$static_ip"; then
_ci_msg_error "Invalid static IP format: $static_ip (expected: x.x.x.x/xx)"
return 65
return 1
fi
if [ -n "$gateway" ] && ! validate_ip "$gateway"; then
_ci_msg_error "Invalid gateway IP format: $gateway"
return 65
return 1
fi
fi
@@ -433,7 +433,7 @@ function configure_cloud_init_interactive() {
if ! command -v whiptail >/dev/null 2>&1; then
echo "Warning: whiptail not available, skipping interactive configuration"
export CLOUDINIT_ENABLE="no"
return 127
return 1
fi
# Ask if user wants to enable Cloud-Init
@@ -603,7 +603,7 @@ function get_vm_ip() {
elapsed=$((elapsed + 2))
done
return 7
return 1
}
# ------------------------------------------------------------------------------
@@ -621,7 +621,7 @@ function wait_for_cloud_init() {
if [ -z "$vm_ip" ]; then
_ci_msg_warn "Unable to determine VM IP address"
return 7
return 1
fi
_ci_msg_info "Waiting for Cloud-Init to complete on ${vm_ip}"
@@ -638,7 +638,7 @@ function wait_for_cloud_init() {
done
_ci_msg_warn "Cloud-Init did not complete within ${timeout}s"
return 150
return 1
}
# ==============================================================================

View File

@@ -858,7 +858,7 @@ get_header() {
if [ ! -s "$local_header_path" ]; then
if ! curl -fsSL "$header_url" -o "$local_header_path"; then
msg_warn "Failed to download header: $header_url"
return 250
return 1
fi
fi
@@ -1358,7 +1358,7 @@ prompt_select() {
if [[ $num_options -eq 0 ]]; then
msg_warn "prompt_select called with no options"
echo "" >&2
return 65
return 1
fi
# Validate default
@@ -1600,7 +1600,7 @@ check_or_create_swap() {
swap_size_mb=$(prompt_input "Enter swap size in MB (e.g., 2048 for 2GB):" "2048" 60)
if ! [[ "$swap_size_mb" =~ ^[0-9]+$ ]]; then
msg_error "Invalid swap size: '${swap_size_mb}' (must be a number in MB)"
return 65
return 1
fi
local swap_file="/swapfile"
@@ -1608,19 +1608,19 @@ check_or_create_swap() {
msg_info "Creating ${swap_size_mb}MB swap file at $swap_file"
if ! dd if=/dev/zero of="$swap_file" bs=1M count="$swap_size_mb" status=progress; then
msg_error "Failed to allocate swap file (dd failed)"
return 150
return 1
fi
if ! chmod 600 "$swap_file"; then
msg_error "Failed to set permissions on $swap_file"
return 150
return 1
fi
if ! mkswap "$swap_file"; then
msg_error "Failed to format swap file (mkswap failed)"
return 150
return 1
fi
if ! swapon "$swap_file"; then
msg_error "Failed to activate swap (swapon failed)"
return 150
return 1
fi
msg_ok "Swap file created and activated successfully"
}
@@ -1699,13 +1699,13 @@ function get_lxc_ip() {
fi
done
return 6
return 1
}
LOCAL_IP="$(get_current_ip || true)"
if [[ -z "$LOCAL_IP" ]]; then
msg_error "Could not determine LOCAL_IP (checked: eth0, hostname -I, ip route, IPv6 targets)"
return 6
return 1
fi
fi

File diff suppressed because it is too large Load Diff

View File

@@ -42,7 +42,7 @@ get_header() {
if [ ! -s "$local_header_path" ]; then
if ! curl -fsSL "$header_url" -o "$local_header_path"; then
return 250
return 1
fi
fi
@@ -594,7 +594,7 @@ set_description() {
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>

View File

@@ -165,9 +165,9 @@ function install() {
else
read -rp "${TAB}Set admin username [admin]: " admin_user
admin_user=${admin_user:-admin}
read -rsp "${TAB}Set admin password [community-scripts.org]: " admin_pass
read -rsp "${TAB}Set admin password [community-scripts.com]: " admin_pass
echo ""
admin_pass=${admin_pass:-community-scripts.org}
admin_pass=${admin_pass:-community-scripts.com}
msg_ok "Configured with admin user: ${admin_user}"
fi

View File

@@ -201,9 +201,9 @@ server:
- neverWatchPath: "/lost+found"
auth:
adminUsername: admin
adminPassword: community-scripts.org
adminPassword: community-scripts.com
EOF
msg_ok "Configured with default admin (admin / community-scripts.org)"
msg_ok "Configured with default admin (admin / community-scripts.com)"
fi
msg_info "Creating service"

View File

@@ -140,8 +140,8 @@ if [[ "${install_prompt,,}" =~ ^(y|yes)$ ]]; then
cd /usr/local/community-scripts
filebrowser config init -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" &>/dev/null
filebrowser config set -a '0.0.0.0' -p "$PORT" -d "$DB_PATH" &>/dev/null
filebrowser users add admin community-scripts.org --perm.admin --database "$DB_PATH" &>/dev/null
msg_ok "Default authentication configured (admin:community-scripts.org)"
filebrowser users add admin community-scripts.com --perm.admin --database "$DB_PATH" &>/dev/null
msg_ok "Default authentication configured (admin:community-scripts.com)"
fi
msg_info "Creating service"

View File

@@ -1,173 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: Tom Frenzel (tomfrenzel)
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
# Source: https://github.com/CodeWithCJ/SparkyFitness
if ! command -v curl &>/dev/null; then
printf "\r\e[2K%b" '\033[93m Setup Source \033[m' >&2
apt-get update >/dev/null 2>&1
apt-get install -y curl >/dev/null 2>&1
fi
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func)
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func)
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func)
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) 2>/dev/null || true
declare -f init_tool_telemetry &>/dev/null && init_tool_telemetry "sparkyfitness-garmin" "addon"
# Enable error handling
set -Eeuo pipefail
trap 'error_handler' ERR
load_functions
# ==============================================================================
# CONFIGURATION
# ==============================================================================
APP="SparkyFitness Garmin Microservice"
APP_TYPE="addon"
INSTALL_PATH="/opt/sparkyfitness-garmin"
CONFIG_PATH="/etc/sparkyfitness-garmin/.env"
SERVICE_PATH="/etc/systemd/system/sparkyfitness-garmin.service"
DEFAULT_PORT=8000
# ==============================================================================
# OS DETECTION
# ==============================================================================
if ! grep -qE 'ID=debian|ID=ubuntu' /etc/os-release 2>/dev/null; then
echo -e "${CROSS} Unsupported OS detected. This script only supports Debian and Ubuntu."
exit 238
fi
# ==============================================================================
# SparkyFitness LXC DETECTION
# ==============================================================================
if [[ ! -d /opt/sparkyfitness ]]; then
echo -e "${CROSS} No SparkyFitness installation detected. This addon must be installed within a container that already has SparkyFitness installed."
exit 238
fi
# ==============================================================================
# UNINSTALL
# ==============================================================================
function uninstall() {
msg_info "Uninstalling ${APP}"
systemctl disable --now sparkyfitness-garmin.service &>/dev/null || true
rm -rf "$SERVICE_PATH" "$CONFIG_PATH" "$INSTALL_PATH" ~/.sparkyfitness-garmin
msg_ok "${APP} has been uninstalled"
}
# ==============================================================================
# UPDATE
# ==============================================================================
function update() {
if check_for_gh_release "sparkyfitness-garmin" "CodeWithCJ/SparkyFitness"; then
PYTHON_VERSION="3.13" setup_uv
msg_info "Stopping service"
systemctl stop sparkyfitness-garmin.service &>/dev/null || true
msg_ok "Stopped service"
CLEAN_INSTALL=1 fetch_and_deploy_gh_release "sparkyfitness-garmin" "CodeWithCJ/SparkyFitness" "tarball" "latest" $INSTALL_PATH
msg_info "Starting service"
systemctl start sparkyfitness-garmin
msg_ok "Started service"
msg_ok "Updated successfully"
exit
fi
}
# ==============================================================================
# INSTALL
# ==============================================================================
function install() {
PYTHON_VERSION="3.13" setup_uv
fetch_and_deploy_gh_release "sparkyfitness-garmin" "CodeWithCJ/SparkyFitness" "tarball" "latest" $INSTALL_PATH
msg_info "Setting up ${APP}"
mkdir -p "/etc/sparkyfitness-garmin"
cp "/opt/sparkyfitness-garmin/docker/.env.example" $CONFIG_PATH
cd $INSTALL_PATH/SparkyFitnessGarmin
$STD uv venv --clear .venv
$STD uv pip install -r requirements.txt
sed -i -e "s|^#\?GARMIN_MICROSERVICE_URL=.*|GARMIN_MICROSERVICE_URL=http://${LOCAL_IP}:${DEFAULT_PORT}|" $CONFIG_PATH
cat <<EOF >/etc/systemd/system/sparkyfitness-garmin.service
[Unit]
Description=${APP}
After=network.target sparkyfitness-server.service
Requires=sparkyfitness-server.service
[Service]
Type=simple
WorkingDirectory=$INSTALL_PATH/SparkyFitnessGarmin
EnvironmentFile=$CONFIG_PATH
ExecStart=$INSTALL_PATH/SparkyFitnessGarmin/.venv/bin/python3 -m uvicorn main:app --host 0.0.0.0 --port ${DEFAULT_PORT}
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now sparkyfitness-garmin
msg_ok "Set up ${APP} - reachable at http://${LOCAL_IP}:${DEFAULT_PORT}"
msg_ok "You might need to update the GARMIN_MICROSERVICE_URL in your SparkyFitness .env file to http://${LOCAL_IP}:${DEFAULT_PORT}"
}
# ==============================================================================
# MAIN
# ==============================================================================
header_info
ensure_usr_local_bin_persist
get_lxc_ip
# Handle type=update (called from update script)
if [[ "${type:-}" == "update" ]]; then
if [[ -d "$INSTALL_PATH" ]]; then
update
else
msg_error "${APP} is not installed. Nothing to update."
exit 233
fi
exit 0
fi
# Check if already installed
if [[ -d "$INSTALL_PATH" && -n "$(ls -A "$INSTALL_PATH" 2>/dev/null)" ]]; then
msg_warn "${APP} is already installed."
echo ""
echo -n "${TAB}Uninstall ${APP}? (y/N): "
read -r uninstall_prompt
if [[ "${uninstall_prompt,,}" =~ ^(y|yes)$ ]]; then
uninstall
exit 0
fi
echo -n "${TAB}Update ${APP}? (y/N): "
read -r update_prompt
if [[ "${update_prompt,,}" =~ ^(y|yes)$ ]]; then
update
exit 0
fi
msg_warn "No action selected. Exiting."
exit 0
fi
# Fresh installation
msg_warn "${APP} is not installed."
echo ""
echo -e "${TAB}${INFO} This will install:"
echo -e "${TAB} - UV (Python Version Manager)"
echo -e "${TAB} - SparkyFitness Garmin Microservice"
echo ""
echo -n "${TAB}Install ${APP}? (y/N): "
read -r install_prompt
if [[ "${install_prompt,,}" =~ ^(y|yes)$ ]]; then
install
else
msg_warn "Installation cancelled. Exiting."
exit 0
fi

View File

@@ -1,6 +0,0 @@
_____ __ _______ __ ______ _ __ ____ _
/ ___/____ ____ ______/ /____ __/ ____(_) /_____ ___ __________ / ____/___ __________ ___ (_)___ / |/ (_)_____________ ________ ______ __(_)_______
\__ \/ __ \/ __ `/ ___/ //_/ / / / /_ / / __/ __ \/ _ \/ ___/ ___/ / / __/ __ `/ ___/ __ `__ \/ / __ \ / /|_/ / / ___/ ___/ __ \/ ___/ _ \/ ___/ | / / / ___/ _ \
___/ / /_/ / /_/ / / / ,< / /_/ / __/ / / /_/ / / / __(__ |__ ) / /_/ / /_/ / / / / / / / / / / / / / / / / / /__/ / / /_/ (__ ) __/ / | |/ / / /__/ __/
/____/ .___/\__,_/_/ /_/|_|\__, /_/ /_/\__/_/ /_/\___/____/____/ \____/\__,_/_/ /_/ /_/ /_/_/_/ /_/ /_/ /_/_/\___/_/ \____/____/\___/_/ |___/_/\___/\___/
/_/ /____/

View File

@@ -551,7 +551,7 @@ qm set $VMID \
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>

View File

@@ -631,7 +631,7 @@ rm -f "$WORK_FILE"
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>

View File

@@ -568,7 +568,7 @@ fi
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>

View File

@@ -639,7 +639,7 @@ msg_ok "Resized disk"
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>

View File

@@ -622,7 +622,7 @@ qm set $VMID \
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>

View File

@@ -546,7 +546,7 @@ qm set $VMID \
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>

View File

@@ -605,7 +605,7 @@ msg_ok "Resized disk to ${DISK_SIZE}"
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>

View File

@@ -750,7 +750,7 @@ qm resize $VMID scsi0 20G >/dev/null
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/michelroegl-brunner/ProxmoxVE/refs/heads/develop/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>

View File

@@ -560,7 +560,7 @@ qm set $VMID \
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>

View File

@@ -462,7 +462,7 @@ qm set $VMID \
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>

View File

@@ -610,7 +610,7 @@ fi
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>

View File

@@ -542,7 +542,7 @@ qm set $VMID \
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>

View File

@@ -544,7 +544,7 @@ qm set $VMID \
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>

View File

@@ -543,7 +543,7 @@ qm set $VMID \
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>

View File

@@ -590,7 +590,7 @@ qm resize $VMID scsi0 ${DISK_SIZE} >/dev/null
DESCRIPTION=$(
cat <<EOF
<div align='center'>
<a href='https://community-scripts.org' target='_blank' rel='noopener noreferrer'>
<a href='https://community-scripts.com' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>