Compare commits

...

9 Commits

Author SHA1 Message Date
community-scripts-pr-app[bot]
37f2e0242d Update CHANGELOG.md (#13031)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-18 06:44:35 +00:00
CanbiZ (MickLesk)
7c62147a00 tools.func: Implement fetch_and_deploy_gh_tag function (#13000)
* tools.func: Implement fetch_and_deploy_gh_tag function

Adds function to fetch and deploy GitHub tag-based source tarballs.

* Refactor fetch_and_deploy_gh_tag function and comments

Updated the function to fetch and deploy GitHub tags, enhancing its description and usage instructions.

* cleanuo
2026-03-18 07:44:13 +01:00
community-scripts-pr-app[bot]
7d11f9acd6 Update CHANGELOG.md (#13029)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-17 23:00:07 +00:00
community-scripts-pr-app[bot]
55a877a3e2 Update CHANGELOG.md (#13028)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-17 22:59:55 +00:00
CanbiZ (MickLesk)
27c9d7fd07 fix(gluetun): add OpenVPN process user and cleanup stale config (#13016)
- Add OPENVPN_PROCESS_USER=root, PUID=0, PGID=0 to default .env
  to prevent gluetun from injecting 'user' directive into target.ovpn
  which causes 'Unrecognized option' errors on Debian
- Add ExecStartPre to remove stale /etc/openvpn/target.ovpn before start
- Fixes #12988
2026-03-17 23:59:40 +01:00
CanbiZ (MickLesk)
c907e10334 Frigate: check OpenVino model files exist before configuring detector and use curl_with_retry instead of default wget (#13019)
* fix(frigate): check OpenVino model files exist before configuring detector

When the OpenVino model build fails (e.g. TensorFlow import error),
the model files are not created but the config still references them
if the CPU supports avx/sse4_2, causing Frigate to crash on start
with FileNotFoundError.

Now also checks that ssdlite_mobilenet_v2.xml and coco_91cl_bkgr.txt
actually exist before configuring the OpenVino detector, falling back
to CPU model otherwise.

Fixes #12808

* fix(frigate): use curl_with_retry for all downloads

Replace all wget and bare curl calls with curl_with_retry from
tools.func for robust downloads with retry logic, exponential
backoff, and DNS pre-checks. This prevents install failures from
transient network issues during model and dependency downloads.
2026-03-17 23:59:28 +01:00
community-scripts-pr-app[bot]
804c462dd3 Update CHANGELOG.md (#13020)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-17 20:20:06 +00:00
Slaviša Arežina
9df9a2831e Update (#13008) 2026-03-17 21:19:36 +01:00
community-scripts-pr-app[bot]
4aa83fd98e Update CHANGELOG.md (#12996)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-17 07:32:12 +00:00
4 changed files with 99 additions and 85 deletions

View File

@@ -423,6 +423,29 @@ Exercise vigilance regarding copycat or coat-tailing sites that seek to exploit
</details> </details>
## 2026-03-18
### 💾 Core
- #### ✨ New Features
- tools.func: Implement fetch_and_deploy_gh_tag function [@MickLesk](https://github.com/MickLesk) ([#13000](https://github.com/community-scripts/ProxmoxVE/pull/13000))
## 2026-03-17
### 🚀 Updated Scripts
- #### 🐞 Bug Fixes
- Gluetun: add OpenVPN process user and cleanup stale config [@MickLesk](https://github.com/MickLesk) ([#13016](https://github.com/community-scripts/ProxmoxVE/pull/13016))
- Frigate: check OpenVino model files exist before configuring detector and use curl_with_retry instead of default wget [@MickLesk](https://github.com/MickLesk) ([#13019](https://github.com/community-scripts/ProxmoxVE/pull/13019))
### 💾 Core
- #### 🔧 Refactor
- tools.func: Update `create_self_signed_cert()` [@tremor021](https://github.com/tremor021) ([#13008](https://github.com/community-scripts/ProxmoxVE/pull/13008))
## 2026-03-16 ## 2026-03-16
### 🆕 New Scripts ### 🆕 New Scripts

View File

@@ -146,7 +146,7 @@ ldconfig
msg_ok "Built libUSB" msg_ok "Built libUSB"
msg_info "Bootstrapping pip" msg_info "Bootstrapping pip"
wget -q https://bootstrap.pypa.io/get-pip.py -O /tmp/get-pip.py curl_with_retry "https://bootstrap.pypa.io/get-pip.py" "/tmp/get-pip.py"
sed -i 's/args.append("setuptools")/args.append("setuptools==77.0.3")/' /tmp/get-pip.py sed -i 's/args.append("setuptools")/args.append("setuptools==77.0.3")/' /tmp/get-pip.py
$STD python3 /tmp/get-pip.py "pip" $STD python3 /tmp/get-pip.py "pip"
rm -f /tmp/get-pip.py rm -f /tmp/get-pip.py
@@ -169,13 +169,13 @@ NODE_VERSION="20" setup_nodejs
msg_info "Downloading Inference Models" msg_info "Downloading Inference Models"
mkdir -p /models /openvino-model mkdir -p /models /openvino-model
wget -q -O /edgetpu_model.tflite https://github.com/google-coral/test_data/raw/release-frogfish/ssdlite_mobiledet_coco_qat_postprocess_edgetpu.tflite curl_with_retry "https://github.com/google-coral/test_data/raw/release-frogfish/ssdlite_mobiledet_coco_qat_postprocess_edgetpu.tflite" "/edgetpu_model.tflite"
wget -q -O /models/cpu_model.tflite https://github.com/google-coral/test_data/raw/release-frogfish/ssdlite_mobiledet_coco_qat_postprocess.tflite curl_with_retry "https://github.com/google-coral/test_data/raw/release-frogfish/ssdlite_mobiledet_coco_qat_postprocess.tflite" "/models/cpu_model.tflite"
cp /opt/frigate/labelmap.txt /labelmap.txt cp /opt/frigate/labelmap.txt /labelmap.txt
msg_ok "Downloaded Inference Models" msg_ok "Downloaded Inference Models"
msg_info "Downloading Audio Model" msg_info "Downloading Audio Model"
wget -q -O /tmp/yamnet.tar.gz https://www.kaggle.com/api/v1/models/google/yamnet/tfLite/classification-tflite/1/download curl_with_retry "https://www.kaggle.com/api/v1/models/google/yamnet/tfLite/classification-tflite/1/download" "/tmp/yamnet.tar.gz"
$STD tar xzf /tmp/yamnet.tar.gz -C / $STD tar xzf /tmp/yamnet.tar.gz -C /
mv /1.tflite /cpu_audio_model.tflite mv /1.tflite /cpu_audio_model.tflite
cp /opt/frigate/audio-labelmap.txt /audio-labelmap.txt cp /opt/frigate/audio-labelmap.txt /audio-labelmap.txt
@@ -205,7 +205,7 @@ msg_ok "Installed OpenVino"
msg_info "Building OpenVino Model" msg_info "Building OpenVino Model"
cd /models cd /models
wget -q http://download.tensorflow.org/models/object_detection/ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz curl_with_retry "http://download.tensorflow.org/models/object_detection/ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz" "ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz"
$STD tar -zxf ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz --no-same-owner $STD tar -zxf ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz --no-same-owner
if python3 /opt/frigate/docker/main/build_ov_model.py &>/dev/null; then if python3 /opt/frigate/docker/main/build_ov_model.py &>/dev/null; then
mkdir -p /openvino-model mkdir -p /openvino-model
@@ -219,7 +219,7 @@ if python3 /opt/frigate/docker/main/build_ov_model.py &>/dev/null; then
if [[ -n "$OV_LABELS" ]]; then if [[ -n "$OV_LABELS" ]]; then
ln -sf "$OV_LABELS" /openvino-model/coco_91cl_bkgr.txt ln -sf "$OV_LABELS" /openvino-model/coco_91cl_bkgr.txt
else else
wget -q "https://raw.githubusercontent.com/openvinotoolkit/open_model_zoo/master/data/dataset_classes/coco_91cl_bkgr.txt" -O /openvino-model/coco_91cl_bkgr.txt curl_with_retry "https://raw.githubusercontent.com/openvinotoolkit/open_model_zoo/master/data/dataset_classes/coco_91cl_bkgr.txt" "/openvino-model/coco_91cl_bkgr.txt"
fi fi
fi fi
sed -i 's/truck/car/g' /openvino-model/coco_91cl_bkgr.txt sed -i 's/truck/car/g' /openvino-model/coco_91cl_bkgr.txt
@@ -246,7 +246,7 @@ msg_info "Configuring Frigate"
mkdir -p /config /media/frigate mkdir -p /config /media/frigate
cp -r /opt/frigate/config/. /config cp -r /opt/frigate/config/. /config
curl -fsSL "https://github.com/intel-iot-devkit/sample-videos/raw/master/person-bicycle-car-detection.mp4" -o "/media/frigate/person-bicycle-car-detection.mp4" curl_with_retry "https://github.com/intel-iot-devkit/sample-videos/raw/master/person-bicycle-car-detection.mp4" "/media/frigate/person-bicycle-car-detection.mp4"
echo "tmpfs /tmp/cache tmpfs defaults 0 0" >>/etc/fstab echo "tmpfs /tmp/cache tmpfs defaults 0 0" >>/etc/fstab
@@ -289,7 +289,7 @@ detect:
enabled: false enabled: false
EOF EOF
if grep -q -o -m1 -E 'avx[^ ]*|sse4_2' /proc/cpuinfo; then if grep -q -o -m1 -E 'avx[^ ]*|sse4_2' /proc/cpuinfo && [[ -f /openvino-model/ssdlite_mobilenet_v2.xml ]] && [[ -f /openvino-model/coco_91cl_bkgr.txt ]]; then
cat <<EOF >>/config/config.yml cat <<EOF >>/config/config.yml
ffmpeg: ffmpeg:
hwaccel_args: auto hwaccel_args: auto

View File

@@ -46,6 +46,9 @@ VPN_TYPE=openvpn
OPENVPN_CUSTOM_CONFIG=/opt/gluetun-data/custom.ovpn OPENVPN_CUSTOM_CONFIG=/opt/gluetun-data/custom.ovpn
OPENVPN_USER= OPENVPN_USER=
OPENVPN_PASSWORD= OPENVPN_PASSWORD=
OPENVPN_PROCESS_USER=root
PUID=0
PGID=0
HTTP_CONTROL_SERVER_ADDRESS=:8000 HTTP_CONTROL_SERVER_ADDRESS=:8000
HTTPPROXY=off HTTPPROXY=off
SHADOWSOCKS=off SHADOWSOCKS=off
@@ -76,6 +79,7 @@ User=root
WorkingDirectory=/opt/gluetun-data WorkingDirectory=/opt/gluetun-data
EnvironmentFile=/opt/gluetun-data/.env EnvironmentFile=/opt/gluetun-data/.env
UnsetEnvironment=USER UnsetEnvironment=USER
ExecStartPre=/bin/sh -c 'rm -f /etc/openvpn/target.ovpn'
ExecStart=/usr/local/bin/gluetun ExecStart=/usr/local/bin/gluetun
Restart=on-failure Restart=on-failure
RestartSec=5 RestartSec=5

View File

@@ -2077,100 +2077,85 @@ verify_gpg_fingerprint() {
} }
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Get latest GitHub tag for a repository. # Fetches and deploys a GitHub tag-based source tarball.
# #
# Description: # Description:
# - Queries the GitHub API for tags (not releases) # - Downloads the source tarball for a given tag from GitHub
# - Useful for repos that only create tags, not full releases # - Extracts to the target directory
# - Supports optional prefix filter and version-only extraction # - Writes the version to ~/.<app>
# - Returns the latest tag name (printed to stdout)
# #
# Usage: # Usage:
# MONGO_VERSION=$(get_latest_gh_tag "mongodb/mongo-tools") # fetch_and_deploy_gh_tag "guacd" "apache/guacamole-server"
# LATEST=$(get_latest_gh_tag "owner/repo" "v") # only tags starting with "v" # fetch_and_deploy_gh_tag "guacd" "apache/guacamole-server" "latest" "/opt/guacamole-server"
# LATEST=$(get_latest_gh_tag "owner/repo" "" "true") # strip leading "v"
# #
# Arguments: # Arguments:
# $1 - GitHub repo (owner/repo) # $1 - App name (used for version file ~/.<app>)
# $2 - Tag prefix filter (optional, e.g. "v" or "100.") # $2 - GitHub repo (owner/repo)
# $3 - Strip prefix from result (optional, "true" to strip $2 prefix) # $3 - Tag version (default: "latest" → auto-detect via get_latest_gh_tag)
# # $4 - Target directory (default: /opt/$app)
# Returns:
# 0 on success (tag printed to stdout), 1 on failure
# #
# Notes: # Notes:
# - Skips tags containing "rc", "alpha", "beta", "dev", "test" # - Supports CLEAN_INSTALL=1 to wipe target before extracting
# - Sorts by version number (sort -V) to find the latest # - For repos that only publish tags, not GitHub Releases
# - Respects GITHUB_TOKEN for rate limiting
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
get_latest_gh_tag() { fetch_and_deploy_gh_tag() {
local repo="$1" local app="$1"
local prefix="${2:-}" local repo="$2"
local strip_prefix="${3:-false}" local version="${3:-latest}"
local target="${4:-/opt/$app}"
local app_lc=""
app_lc="$(echo "${app,,}" | tr -d ' ')"
local version_file="$HOME/.${app_lc}"
local header_args=() if [[ "$version" == "latest" ]]; then
[[ -n "${GITHUB_TOKEN:-}" ]] && header_args=(-H "Authorization: Bearer $GITHUB_TOKEN") version=$(get_latest_gh_tag "$repo") || {
msg_error "Failed to determine latest tag for ${repo}"
return 1
}
fi
local http_code="" local current_version=""
http_code=$(curl -sSL --max-time 20 -w "%{http_code}" -o /tmp/gh_tags.json \ [[ -f "$version_file" ]] && current_version=$(<"$version_file")
-H 'Accept: application/vnd.github+json' \
-H 'X-GitHub-Api-Version: 2022-11-28' \
"${header_args[@]}" \
"https://api.github.com/repos/${repo}/tags?per_page=100" 2>/dev/null) || true
if [[ "$http_code" == "401" ]]; then if [[ "$current_version" == "$version" ]]; then
msg_error "GitHub API authentication failed (HTTP 401)." msg_ok "$app is already up-to-date ($version)"
if [[ -n "${GITHUB_TOKEN:-}" ]]; then return 0
msg_error "Your GITHUB_TOKEN appears to be invalid or expired." fi
else
msg_error "The repository may require authentication. Try: export GITHUB_TOKEN=\"ghp_your_token\"" local tmpdir
fi tmpdir=$(mktemp -d) || return 1
rm -f /tmp/gh_tags.json local tarball_url="https://github.com/${repo}/archive/refs/tags/${version}.tar.gz"
local filename="${app_lc}-${version}.tar.gz"
msg_info "Fetching GitHub tag: ${app} (${version})"
download_file "$tarball_url" "$tmpdir/$filename" || {
msg_error "Download failed: $tarball_url"
rm -rf "$tmpdir"
return 1 return 1
}
mkdir -p "$target"
if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then
rm -rf "${target:?}/"*
fi fi
if [[ "$http_code" == "403" ]]; then tar --no-same-owner -xzf "$tmpdir/$filename" -C "$tmpdir" || {
msg_error "GitHub API rate limit exceeded (HTTP 403)." msg_error "Failed to extract tarball"
msg_error "To increase the limit, export a GitHub token before running the script:" rm -rf "$tmpdir"
msg_error " export GITHUB_TOKEN=\"ghp_your_token_here\""
rm -f /tmp/gh_tags.json
return 1 return 1
fi }
if [[ "$http_code" == "000" || -z "$http_code" ]]; then local unpack_dir
msg_error "GitHub API connection failed (no response)." unpack_dir=$(find "$tmpdir" -mindepth 1 -maxdepth 1 -type d | head -n1)
msg_error "Check your network/DNS: curl -sSL https://api.github.com/rate_limit"
rm -f /tmp/gh_tags.json
return 1
fi
if [[ "$http_code" != "200" ]] || [[ ! -s /tmp/gh_tags.json ]]; then shopt -s dotglob nullglob
msg_error "Unable to fetch tags for ${repo} (HTTP ${http_code})" cp -r "$unpack_dir"/* "$target/"
rm -f /tmp/gh_tags.json shopt -u dotglob nullglob
return 1
fi
local tags_json rm -rf "$tmpdir"
tags_json=$(</tmp/gh_tags.json) echo "$version" >"$version_file"
rm -f /tmp/gh_tags.json msg_ok "Deployed ${app} ${version} to ${target}"
# Extract tag names, filter by prefix, exclude pre-release patterns, sort by version
local latest=""
latest=$(echo "$tags_json" | grep -oP '"name":\s*"\K[^"]+' |
{ [[ -n "$prefix" ]] && grep "^${prefix}" || cat; } |
grep -viE '(rc|alpha|beta|dev|test|preview|snapshot)' |
sort -V | tail -n1)
if [[ -z "$latest" ]]; then
msg_warn "No matching tags found for ${repo}${prefix:+ (prefix: $prefix)}"
return 1
fi
if [[ "$strip_prefix" == "true" && -n "$prefix" ]]; then
latest="${latest#"$prefix"}"
fi
echo "$latest"
return 0 return 0
} }
@@ -2519,6 +2504,8 @@ check_for_codeberg_release() {
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
create_self_signed_cert() { create_self_signed_cert() {
local APP_NAME="${1:-${APPLICATION}}" local APP_NAME="${1:-${APPLICATION}}"
local HOSTNAME="$(hostname -f)"
local IP="$(hostname -I | awk '{print $1}')"
local APP_NAME_LC=$(echo "${APP_NAME,,}" | tr -d ' ') local APP_NAME_LC=$(echo "${APP_NAME,,}" | tr -d ' ')
local CERT_DIR="/etc/ssl/${APP_NAME_LC}" local CERT_DIR="/etc/ssl/${APP_NAME_LC}"
local CERT_KEY="${CERT_DIR}/${APP_NAME_LC}.key" local CERT_KEY="${CERT_DIR}/${APP_NAME_LC}.key"
@@ -2536,8 +2523,8 @@ create_self_signed_cert() {
mkdir -p "$CERT_DIR" mkdir -p "$CERT_DIR"
$STD openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 \ $STD openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 \
-subj "/CN=${APP_NAME}" \ -subj "/CN=${HOSTNAME}" \
-addext "subjectAltName=DNS:${APP_NAME}" \ -addext "subjectAltName=DNS:${HOSTNAME},DNS:localhost,IP:${IP},IP:127.0.0.1" \
-keyout "$CERT_KEY" \ -keyout "$CERT_KEY" \
-out "$CERT_CRT" || { -out "$CERT_CRT" || {
msg_error "Failed to create self-signed certificate" msg_error "Failed to create self-signed certificate"