From df62d357d85a4a67231498ef616ad6a54fabeb39 Mon Sep 17 00:00:00 2001 From: alexbelgium <44178713+alexbelgium@users.noreply.github.com> Date: Sun, 6 Sep 2026 00:51:57 +0000 Subject: [PATCH] fix: auto-fix linting issues --- .../scripts/env_trace.sh | 19 +- .../hassio-addon-workflow/scripts/measure.sh | 14 +- .../scripts/pr_review.sh | 209 +++-- .../scripts/preflight.sh | 9 +- .../hassio-addon-workflow/scripts/validate.sh | 76 +- .github/prompts/issue-classify.md | 2 +- .github/prompts/issue-fix.md | 2 +- .github/scripts/ai_guard_paths.sh | 2 +- .github/scripts/ai_triage_context.sh | 172 ++-- .templates/00-banner.sh | 14 +- .templates/00-global_var.sh | 13 +- .templates/00-smb_mounts.sh | 780 +++++++++--------- .templates/01-config_yaml.sh | 6 +- .templates/01-custom_script.sh | 210 ++--- .templates/90-dns_set.sh | 6 +- .templates/bashio-standalone.sh | 441 +++++----- .templates/ha_autoapps.sh | 4 +- .templates/ha_automatic_packages.sh | 4 +- .templates/ha_entrypoint.sh | 568 ++++++------- CLAUDE.md | 4 +- addons_updater/README.md | 2 +- aurral/CHANGELOG.md | 20 +- aurral/README.md | 2 +- autobrr/CHANGELOG.md | 10 +- autobrr/README.md | 2 +- bazarr/README.md | 2 +- bazarr/rootfs/etc/services.d/nginx/run | 0 bentopdf/README.md | 12 +- .../etc/s6-overlay/s6-rc.d/bentopdf/run | 0 .../rootfs/etc/cont-init.d/01-structure.sh | 6 +- .../rootfs/etc/cont-init.d/33-mariadb.sh | 6 +- birdnet-go/CHANGELOG.md | 10 +- .../rootfs/etc/cont-init.d/01-structure.sh | 6 +- birdnet-pi-zach/DOCS.md | 6 +- .../rootfs/helpers/birdnet_to_mqtt.py | 1 + birdnet-pi/DOCS.md | 6 +- birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py | 1 + birdnet-pipy/CHANGELOG.md | 14 +- birdnet-pipy/config.yaml | 2 +- .../rootfs/etc/cont-init.d/01-structure.sh | 26 +- .../rootfs/etc/cont-init.d/10-config.sh | 12 +- .../rootfs/etc/cont-init.d/15-audio_perms.sh | 48 +- birdnet-pipy/rootfs/etc/services.d/api/run | 14 +- .../rootfs/etc/services.d/icecast/run | 0 birdnet-pipy/rootfs/etc/services.d/main/run | 0 birdnet-pipy/rootfs/etc/services.d/model/run | 0 birdnet-pipy/rootfs/etc/services.d/nginx/run | 0 bitwarden/CHANGELOG.md | 6 +- .../etc/s6-overlay/s6-rc.d/init-nginx/run | 0 .../rootfs/etc/s6-overlay/s6-rc.d/nginx/run | 0 .../etc/s6-overlay/s6-rc.d/vaultwarden/run | 6 +- booksonic_air/README.md | 2 +- browser_brave/CHANGELOG.md | 30 +- browser_chromium/CHANGELOG.md | 20 +- .../rootfs/etc/cont-init.d/20-folders.sh | 1 - .../rootfs/etc/usr/bin/wrapped-chromium | 34 +- browserless_chrome/CHANGELOG.md | 24 +- calibre/CHANGELOG.md | 10 +- calibre/README.md | 2 +- calibre_web/CHANGELOG.md | 2 +- calibre_web/README.md | 4 +- .../etc/cont-init.d/80-configuration.sh | 8 +- changedetection.io/CHANGELOG.md | 4 +- changedetection.io/README.md | 2 +- .../rootfs/etc/services.d/nginx/run | 0 claude_desktop/CHANGELOG.md | 24 +- claude_desktop/rootfs/defaults/autostart | 4 +- .../rootfs/etc/cont-init.d/81-codex_cli.sh | 7 +- .../rootfs/etc/cont-init.d/82-claude_tools.sh | 28 +- .../etc/cont-init.d/83-claude_permissions.sh | 2 +- .../etc/cont-init.d/86-claude_safestorage.sh | 2 +- .../usr/local/bin/claude-tools-doctor.sh | 6 +- .../rootfs/usr/local/bin/codex-login | 0 claude_desktop/rootfs/usr/local/bin/ha-cli | 14 +- .../bin/headroom-posttooluse-compress.py | 14 +- cleanuparr/CHANGELOG.md | 10 +- cleanuparr/README.md | 2 +- cleanuparr/config.yaml | 3 +- cleanuparr/rootfs/ha_entrypoint.sh | 2 +- cloudcommander/CHANGELOG.md | 8 +- cloudcommander/README.md | 2 +- .../rootfs/etc/cont-init.d/99-run.sh | 2 +- codex/CHANGELOG.md | 24 +- codex/README.md | 2 +- collabora/CHANGELOG.md | 14 +- collabora/README.md | 2 +- collabora/rootfs/etc/cont-init.d/99-run.sh | 6 +- comicarr/CHANGELOG.md | 4 +- comicarr/README.md | 2 +- comicarr/rootfs/etc/services.d/comicarr/run | 0 comicarr/rootfs/etc/services.d/nginx/run | 0 comixed/README.md | 2 +- elasticsearch/CHANGELOG.md | 6 +- .../rootfs/usr/local/bin/addon-init.sh | 18 +- emby/README.md | 2 +- emby/rootfs/etc/services.d/nginx/run | 0 emby_beta/CHANGELOG.md | 28 +- enedisgateway2mqtt/README.md | 2 +- enedisgateway2mqtt_dev/README.md | 2 +- ente/CHANGELOG.md | 4 +- ente/README.md | 4 +- epicgamesfree/CHANGELOG.md | 16 +- epicgamesfree/README.md | 2 +- .../rootfs/etc/cont-init.d/99-run.sh | 2 +- filebrowser/CHANGELOG.md | 8 +- filebrowser/README.md | 2 +- filebrowser_quantum/CHANGELOG.md | 18 +- filebrowser_quantum/README.md | 2 +- .../rootfs/etc/cont-init.d/99-run.sh | 36 +- fireflyiii/CHANGELOG.md | 2 +- fireflyiii/README.md | 2 +- fireflyiii/rootfs/etc/cont-init.d/99-run.sh | 2 +- fireflyiii_data_importer/CHANGELOG.md | 2 +- fireflyiii_data_importer/README.md | 2 +- .../rootfs/templates/cronupdate | 26 +- flexget/CHANGELOG.md | 24 +- flexget/README.md | 2 +- free_games_claimer/README.md | 2 +- .../rootfs/etc/cont-init.d/99-run.sh | 8 +- .../rootfs/templates/config.env | 8 +- .../usr/local/bin/migrate_vogler_data.py | 19 +- gazpar2mqtt/CHANGELOG.md | 2 +- gazpar2mqtt/README.md | 2 +- gitea/CHANGELOG.md | 10 +- gitea/README.md | 2 +- grampsweb/CHANGELOG.md | 12 +- grampsweb/README.md | 4 +- grav/CHANGELOG.md | 24 +- grav/README.md | 2 +- guacamole/CHANGELOG.md | 2 +- guacamole/README.md | 2 +- immich/CHANGELOG.md | 6 +- immich/README.md | 2 +- immich_cuda/CHANGELOG.md | 4 +- immich_cuda/README.md | 2 +- immich_cuda/config.yaml | 3 +- immich_frame/CHANGELOG.md | 4 +- immich_frame/README.md | 6 +- immich_frame/rootfs/etc/cont-init.d/99-run.sh | 24 +- immich_noml/CHANGELOG.md | 4 +- immich_noml/README.md | 2 +- immich_noml/config.yaml | 3 +- immich_openvino/CHANGELOG.md | 4 +- immich_openvino/README.md | 2 +- immich_power_tools/CHANGELOG.md | 4 +- immich_power_tools/README.md | 2 +- inadyn/README.md | 4 +- jackett/CHANGELOG.md | 36 +- jackett/README.md | 2 +- jellyfin/CHANGELOG.md | 2 +- jellyfin/README.md | 2 +- jellyfin/config.yaml | 2 +- .../rootfs/etc/cont-init.d/25-video_fix.sh | 12 +- jellyfin/rootfs/etc/services.d/nginx/run | 0 joal/README.md | 2 +- joplin/README.md | 2 +- joplin/rootfs/etc/cont-init.d/99-run.sh | 25 +- kometa/CHANGELOG.md | 12 +- komga/README.md | 2 +- librespeed/CHANGELOG.md | 4 +- lidarr/README.md | 2 +- linkwarden/CHANGELOG.md | 4 +- linkwarden/README.md | 2 +- linkwarden/rootfs/etc/cont-init.d/99-run.sh | 2 +- maintainerr/CHANGELOG.md | 30 +- maintainerr/config.yaml | 3 +- maintainerr/rootfs/ha_entrypoint.sh | 4 +- manyfold/CHANGELOG.md | 14 +- manyfold/README.md | 4 +- .../etc/s6-overlay/s6-rc.d/manyfold/finish | 0 manyfold/run.sh | 339 ++++---- mealie/CHANGELOG.md | 12 +- mealie/README.md | 2 +- monica/README.md | 2 +- monica/rootfs/etc/cont-init.d/99-run.sh | 18 +- mylar3/CHANGELOG.md | 4 +- mylar3/README.md | 2 +- navidrome/CHANGELOG.md | 4 +- navidrome/README.md | 2 +- netalertx/CHANGELOG.md | 6 +- netalertx_fa/CHANGELOG.md | 6 +- .../rootfs/etc/cont-init.d/00-config.sh | 82 +- .../rootfs/etc/services.d/caddy/run | 4 +- .../rootfs/etc/services.d/dashboard/run | 12 +- .../rootfs/etc/services.d/management/run | 22 +- .../rootfs/etc/services.d/relay/run | 12 +- .../rootfs/etc/services.d/signal/run | 8 +- nextcloud/CHANGELOG.md | 8 +- nextcloud/README.md | 8 +- nginx_webserver_proxy/README.md | 2 +- nzbget/CHANGELOG.md | 28 +- nzbget/README.md | 2 +- nzbget/rootfs/etc/services.d/nginx/run | 0 .../etc/s6-overlay/s6-rc.d/addon-init/script | 12 +- .../etc/s6-overlay/s6-rc.d/addon-init/up | 0 .../etc/s6-overlay/s6-rc.d/couchdb/finish | 0 obsidian_syncserver_solo/CHANGELOG.md | 2 +- obsidian_syncserver_ssl/CHANGELOG.md | 2 +- openproject/CHANGELOG.md | 12 +- photoprism/CHANGELOG.md | 4 +- photoprism/README.md | 2 +- piwigo/README.md | 2 +- plex/CHANGELOG.md | 18 +- plex/README.md | 2 +- plex/rootfs/etc/cont-init.d/21-folders.sh | 4 +- portainer/CHANGELOG.md | 8 +- portainer/README.md | 2 +- portainer_agent/CHANGELOG.md | 4 +- .../rootfs/etc/services.d/portainer_agent/run | 2 +- portainer_agent/rootfs/usr/sbin/healthcheck | 6 +- portainer_be/CHANGELOG.md | 2 +- portainer_be/README.md | 2 +- postgres_15/README.md | 2 +- postgres_15/rootfs/etc/cont-init.d/99-run.sh | 2 +- prowlarr/CHANGELOG.md | 30 +- prowlarr/README.md | 2 +- qbittorrent/README.md | 2 +- .../rootfs/etc/cont-init.d/93-openvpn.sh | 4 +- .../rootfs/etc/cont-init.d/94-wireguard.sh | 4 +- .../rootfs/etc/cont-init.d/95-vpn-monitor.sh | 2 +- .../s6-overlay/s6-rc.d/svc-qbittorrent/run | 0 qbittorrent/rootfs/etc/services.d/timer/run | 0 .../rootfs/etc/services.d/vpn-monitor/run | 9 +- .../rootfs/etc/services.d/vpn-upnp/run | 12 +- qbittorrent/rootfs/usr/local/sbin/vpn | 0 radarr/CHANGELOG.md | 4 +- radarr/README.md | 2 +- readarr/README.md | 2 +- readarr/rootfs/etc/services.d/nginx/run | 0 requestrr/README.md | 2 +- sabnzbd/CHANGELOG.md | 8 +- sabnzbd/README.md | 2 +- sabnzbd/rootfs/etc/services.d/nginx/finish | 0 scrutiny/CHANGELOG.md | 20 +- scrutiny/README.md | 2 +- .../local/bin/scrutiny-ha-influxdb-preflight | 304 +++---- scrutiny_fa/CHANGELOG.md | 20 +- scrutiny_fa/README.md | 2 +- .../etc/services.d/nginx/finish | 0 scrutiny_fa/scrutiny-ha-influxdb-preflight | 304 +++---- scrutiny_fa_original/CHANGELOG.md | 10 +- scrutiny_fa_original/README.md | 2 +- scrutiny_original/CHANGELOG.md | 10 +- scrutiny_original/README.md | 2 +- seafile/CHANGELOG.md | 2 +- seafile/README.md | 2 +- seafile/rootfs/etc/cont-init.d/99-run.sh | 16 +- seerr/README.md | 2 +- seerr/config.yaml | 3 +- seerr/rootfs/etc/services.d/nginx/run | 0 seerr/rootfs/etc/services.d/seerr/finish | 0 signalk/CHANGELOG.md | 8 +- signalk/rootfs/etc/cont-init.d/99-run.sh | 1 - social_to_mealie/CHANGELOG.md | 4 +- social_to_mealie/README.md | 2 +- sonarr/CHANGELOG.md | 14 +- sonarr/README.md | 2 +- sponsorblockcast/README.md | 2 +- spotify_to_plex/CHANGELOG.md | 2 +- spotify_to_plex/README.md | 2 +- tandoor_recipes/CHANGELOG.md | 6 +- tandoor_recipes/README.md | 2 +- tdarr/CHANGELOG.md | 16 +- tdarr/README.md | 2 +- teamspeak/README.md | 2 +- transmission/CHANGELOG.md | 2 +- transmission/README.md | 2 +- transmission_openvpn/CHANGELOG.md | 6 +- transmission_openvpn/config.yaml | 2 +- .../rootfs/etc/openvpn/update-resolv-conf | 82 +- ubooquity/README.md | 2 +- unpackerr/CHANGELOG.md | 2 +- unpackerr/README.md | 2 +- unpackerr/rootfs/etc/cont-init.d/90-vpn.sh | 2 +- webtop/README.md | 2 +- webtop_kde/CHANGELOG.md | 18 +- whoogle/README.md | 2 +- zoneminder/CHANGELOG.md | 2 +- zoneminder/rootfs/etc/cont-init.d/99-run.sh | 18 +- zoraxy/CHANGELOG.md | 2 +- zoraxy/rootfs/etc/services.d/zoraxy/run | 0 zzz_archived_code-server/CHANGELOG.md | 20 +- zzz_archived_jellyseerr/CHANGELOG.md | 2 +- zzz_archived_jellyseerr/config.yaml | 3 +- zzz_archived_kapowarr/README.md | 2 +- .../rootfs/etc/services.d/kapowarr/run | 0 .../rootfs/etc/services.d/nginx/run | 0 .../rootfs/etc/cont-init.d/99-run.sh | 0 zzz_archived_omada_v3/CHANGELOG.md | 2 +- zzz_archived_overseerr/README.md | 2 +- .../etc/cont-init.d/00-config_location.sh | 0 .../rootfs/etc/cont-init.d/20-folders.sh | 0 zzz_archived_paperless_ngx/CHANGELOG.md | 10 +- .../rootfs/etc/cont-init.d/99-run.sh | 5 +- .../etc/s6-overlay/s6-rc.d/init-tor/run | 38 +- .../rootfs/etc/s6-overlay/s6-rc.d/tor/run | 0 296 files changed, 2783 insertions(+), 2634 deletions(-) mode change 100644 => 100755 bazarr/rootfs/etc/services.d/nginx/run mode change 100644 => 100755 bentopdf/rootfs/etc/s6-overlay/s6-rc.d/bentopdf/run mode change 100644 => 100755 birdnet-pipy/rootfs/etc/services.d/api/run mode change 100644 => 100755 birdnet-pipy/rootfs/etc/services.d/icecast/run mode change 100644 => 100755 birdnet-pipy/rootfs/etc/services.d/main/run mode change 100644 => 100755 birdnet-pipy/rootfs/etc/services.d/model/run mode change 100644 => 100755 birdnet-pipy/rootfs/etc/services.d/nginx/run mode change 100644 => 100755 bitwarden/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/run mode change 100644 => 100755 bitwarden/rootfs/etc/s6-overlay/s6-rc.d/nginx/run mode change 100644 => 100755 bitwarden/rootfs/etc/s6-overlay/s6-rc.d/vaultwarden/run mode change 100755 => 100644 browser_chromium/rootfs/etc/cont-init.d/20-folders.sh mode change 100644 => 100755 changedetection.io/rootfs/etc/services.d/nginx/run mode change 100755 => 100644 claude_desktop/rootfs/usr/local/bin/codex-login mode change 100755 => 100644 claude_desktop/rootfs/usr/local/bin/ha-cli mode change 100755 => 100644 claude_desktop/rootfs/usr/local/bin/headroom-posttooluse-compress.py mode change 100644 => 100755 comicarr/rootfs/etc/services.d/comicarr/run mode change 100644 => 100755 comicarr/rootfs/etc/services.d/nginx/run mode change 100644 => 100755 emby/rootfs/etc/services.d/nginx/run mode change 100644 => 100755 jellyfin/rootfs/etc/services.d/nginx/run mode change 100755 => 100644 manyfold/rootfs/etc/s6-overlay/s6-rc.d/manyfold/finish mode change 100644 => 100755 netbird-server/rootfs/etc/services.d/caddy/run mode change 100644 => 100755 netbird-server/rootfs/etc/services.d/dashboard/run mode change 100644 => 100755 netbird-server/rootfs/etc/services.d/management/run mode change 100644 => 100755 netbird-server/rootfs/etc/services.d/relay/run mode change 100644 => 100755 netbird-server/rootfs/etc/services.d/signal/run mode change 100644 => 100755 nzbget/rootfs/etc/services.d/nginx/run mode change 100755 => 100644 obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/addon-init/script mode change 100755 => 100644 obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/addon-init/up mode change 100755 => 100644 obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/couchdb/finish mode change 100644 => 100755 qbittorrent/rootfs/etc/s6-overlay/s6-rc.d/svc-qbittorrent/run mode change 100644 => 100755 qbittorrent/rootfs/etc/services.d/timer/run mode change 100644 => 100755 qbittorrent/rootfs/etc/services.d/vpn-upnp/run mode change 100755 => 100644 qbittorrent/rootfs/usr/local/sbin/vpn mode change 100644 => 100755 readarr/rootfs/etc/services.d/nginx/run mode change 100755 => 100644 sabnzbd/rootfs/etc/services.d/nginx/finish mode change 100755 => 100644 scrutiny_fa/rootfs_overlay/etc/services.d/nginx/finish mode change 100644 => 100755 seerr/rootfs/etc/services.d/nginx/run mode change 100755 => 100644 seerr/rootfs/etc/services.d/seerr/finish mode change 100755 => 100644 transmission_openvpn/rootfs/etc/openvpn/update-resolv-conf mode change 100644 => 100755 zoraxy/rootfs/etc/services.d/zoraxy/run mode change 100644 => 100755 zzz_archived_kapowarr/rootfs/etc/services.d/kapowarr/run mode change 100644 => 100755 zzz_archived_kapowarr/rootfs/etc/services.d/nginx/run mode change 100644 => 100755 zzz_archived_omada/rootfs/etc/cont-init.d/99-run.sh mode change 100644 => 100755 zzz_archived_overseerr/rootfs/etc/cont-init.d/00-config_location.sh mode change 100644 => 100755 zzz_archived_overseerr/rootfs/etc/cont-init.d/20-folders.sh mode change 100644 => 100755 zzz_archived_tor/rootfs/etc/s6-overlay/s6-rc.d/tor/run diff --git a/.claude/skills/hassio-addon-workflow/scripts/env_trace.sh b/.claude/skills/hassio-addon-workflow/scripts/env_trace.sh index b092ff2720..92df333179 100755 --- a/.claude/skills/hassio-addon-workflow/scripts/env_trace.sh +++ b/.claude/skills/hassio-addon-workflow/scripts/env_trace.sh @@ -30,8 +30,14 @@ VAR="${1:?usage: env_trace.sh [process-name-or-pid]}" TARGET="${2:-}" # VAR is interpolated into grep/sed patterns below — restrict it to a valid env var name case "$VAR" in - [A-Za-z_]*) [ -z "${VAR//[A-Za-z0-9_]/}" ] || { echo "invalid env var name: $VAR" >&2; exit 1; } ;; - *) echo "invalid env var name: $VAR" >&2; exit 1 ;; + [A-Za-z_]*) [ -z "${VAR//[A-Za-z0-9_]/}" ] || { + echo "invalid env var name: $VAR" >&2 + exit 1 + } ;; + *) + echo "invalid env var name: $VAR" >&2 + exit 1 + ;; esac echo "== tracing ${VAR} ==" @@ -39,7 +45,7 @@ echo echo "1. /data/options.json (the user's saved options)" if [ -f /data/options.json ]; then - python3 - "$VAR" <<'PY' + python3 - "$VAR" << 'PY' import json, sys var = sys.argv[1] try: @@ -80,7 +86,8 @@ echo "3. s6 container_environment (only read by services using #!/usr/bin/with-c seen3=0 for d in /var/run/s6/container_environment /run/s6/container_environment; do if [ -f "$d/$VAR" ]; then - echo " $d/$VAR = [$(cat "$d/$VAR")]"; seen3=1 + echo " $d/$VAR = [$(cat "$d/$VAR")]" + seen3=1 fi done [ "$seen3" -eq 0 ] && echo " not present in either envdir" @@ -122,8 +129,8 @@ else done fi # What it was actually launched with beats any theory about its environment. - tr '\0' '\n' < "/proc/$pid/cmdline" 2> /dev/null | tail -n +2 | - grep -iE "res|screen|${VAR}" | head -3 | sed 's/^/ argv: /' + tr '\0' '\n' < "/proc/$pid/cmdline" 2> /dev/null | tail -n +2 \ + | grep -iE "res|screen|${VAR}" | head -3 | sed 's/^/ argv: /' done fi fi diff --git a/.claude/skills/hassio-addon-workflow/scripts/measure.sh b/.claude/skills/hassio-addon-workflow/scripts/measure.sh index d5c060154d..a0021851a8 100755 --- a/.claude/skills/hassio-addon-workflow/scripts/measure.sh +++ b/.claude/skills/hassio-addon-workflow/scripts/measure.sh @@ -31,7 +31,7 @@ awk '{t+=$2} END{printf " threads=%d\n", t}' <(ps -eo pid,nlwp --no-headers 2> echo echo "== per-process memory (top 20 by PSS) ==" printf ' %-28s %8s %8s %8s\n' COMMAND RSS PSS PRIVATE -python3 - "$OUT" <<'PY' +python3 - "$OUT" << 'PY' import os, sys rows = [] for pid in filter(str.isdigit, os.listdir('/proc')): @@ -62,17 +62,17 @@ PY echo echo "== reserved-but-not-resident (lazy allocations, NOT leaks) ==" -ipcs -m 2>/dev/null | awk 'NR>3 && $5 ~ /^[0-9]+$/ && $5 > 50000000 {printf " SysV shm %.0f MB (owner %s) — check Rss in /proc//smaps before calling it used\n", $5/1048576, $3}' +ipcs -m 2> /dev/null | awk 'NR>3 && $5 ~ /^[0-9]+$/ && $5 > 50000000 {printf " SysV shm %.0f MB (owner %s) — check Rss in /proc//smaps before calling it used\n", $5/1048576, $3}' echo echo "== CPU over ${SAMPLE}s (idle unless you are driving the UI) ==" # utime+stime. Parsed after the LAST ')' because field 2 is (comm) and may contain spaces — # a plain $14+$15 is wrong for anything like 'npm exec @foo' and silently reports a fabricated # number rather than failing. -jiffies() { awk -F') ' '{n=split($NF,a," "); print a[12]+a[13]}' "/proc/$1/stat" 2>/dev/null; } +jiffies() { awk -F') ' '{n=split($NF,a," "); print a[12]+a[13]}' "/proc/$1/stat" 2> /dev/null; } # jiffies are USER_HZ units — almost always 100, but read it rather than assume it -HZ=$(getconf CLK_TCK 2>/dev/null) && [ "$HZ" -gt 0 ] 2>/dev/null || HZ=100 +HZ=$(getconf CLK_TCK 2> /dev/null) && [ "$HZ" -gt 0 ] 2> /dev/null || HZ=100 # Sample EVERY readable process, not the top-N of ps.txt: that list is sorted by RSS, # and the busiest process is not necessarily a big one. @@ -86,14 +86,14 @@ for pid in "${!t0[@]}"; do [ -r "/proc/$pid/stat" ] || continue t1=$(jiffies "$pid") || continue [ -n "$t1" ] && [ -n "${t0[$pid]}" ] || continue - delta=$(( t1 - ${t0[$pid]} )) + delta=$((t1 - ${t0[$pid]})) [ "$delta" -gt 0 ] || continue pct=$(awk -v d="$delta" -v s="$SAMPLE" -v hz="$HZ" 'BEGIN{printf "%.2f", d*100/(hz*s)}') - comm=$(tr -d '\0' < "/proc/$pid/comm" 2>/dev/null) + comm=$(tr -d '\0' < "/proc/$pid/comm" 2> /dev/null) echo "$pct $pid $comm" done | sort -rn | head -12 | awk '{printf " %6s%% %-8s %s\n", $1, $2, $3}' echo -echo " established conns on :8082/:3000/:3001 = $(ss -tn 2>/dev/null | grep -cE 'ESTAB.*:(8082|3000|3001)')" +echo " established conns on :8082/:3000/:3001 = $(ss -tn 2> /dev/null | grep -cE 'ESTAB.*:(8082|3000|3001)')" echo " (those are claude_desktop/webtop viewer ports; 0 here means CPU above is idle burn)" echo " raw ps: $OUT/ps.txt" diff --git a/.claude/skills/hassio-addon-workflow/scripts/pr_review.sh b/.claude/skills/hassio-addon-workflow/scripts/pr_review.sh index 56fa01e982..dcc0be02bc 100755 --- a/.claude/skills/hassio-addon-workflow/scripts/pr_review.sh +++ b/.claude/skills/hassio-addon-workflow/scripts/pr_review.sh @@ -18,99 +18,126 @@ set -uo pipefail REPO="${HASSIO_REPO:-}" [ -z "$REPO" ] && REPO=$(gh repo view --json nameWithOwner --jq .nameWithOwner 2> /dev/null) -[ -z "$REPO" ] && { echo "cannot determine repo; set HASSIO_REPO=owner/name" >&2; exit 1; } +[ -z "$REPO" ] && { + echo "cannot determine repo; set HASSIO_REPO=owner/name" >&2 + exit 1 +} echo "repo: $REPO" >&2 -CMD="${1:-}"; PR="${2:-}" -[ -z "$CMD" ] || [ -z "$PR" ] && { sed -n '2,16p' "$0" | sed 's/^# \?//'; exit 1; } +CMD="${1:-}" +PR="${2:-}" +[ -z "$CMD" ] || [ -z "$PR" ] && { + sed -n '2,16p' "$0" | sed 's/^# \?//' + exit 1 +} case "$CMD" in -list) - echo "== inline comments on #$PR ==" - gh api "repos/$REPO/pulls/$PR/comments" --paginate \ - --jq 'sort_by(.created_at)[] | "=== [\(.id)] \(.user.login) | \(.path):\(.line // .original_line) ===\n\(.body)\n"' - echo "== review bodies ==" - gh api "repos/$REPO/pulls/$PR/reviews" \ - --jq '.[] | select(.body != "") | "--- \(.user.login) (\(.state)) ---\n\(.body[0:4000])\n"' - ;; -status) - gh pr checks "$PR" 2>&1 | head -15 - echo - gh api graphql -f query="{repository(owner:\"${REPO%%/*}\",name:\"${REPO##*/}\"){pullRequest(number:$PR){reviewThreads(first:50){nodes{id isResolved path comments(first:1){nodes{author{login}}}}}}}}" \ - --jq '.data.repository.pullRequest.reviewThreads.nodes[] | "\(if .isResolved then "resolved" else "OPEN " end) \(.id) \(.comments.nodes[0].author.login) \(.path)"' - ;; -reply) - ID="${3:?comment id}"; BODY="${4:?text or @file}" - if [ "${BODY#@}" != "$BODY" ]; then - out=$(gh api "repos/$REPO/pulls/$PR/comments/$ID/replies" -F body=@"${BODY#@}" --jq '.id' 2>&1) - rc=$? - else - out=$(gh api "repos/$REPO/pulls/$PR/comments/$ID/replies" -f body="$BODY" --jq '.id' 2>&1) - rc=$? - fi - # Silently "succeeding" here is worse than failing: a later session reads the transcript and - # believes a reviewer was answered when they were not. - if [ "$rc" -eq 0 ] && [ -n "$out" ]; then - echo "replied to $ID (comment $out)" - else - echo "FAILED to reply to $ID: $out" >&2 - echo " (top-level review bodies have different ids and cannot take replies here)" >&2 - exit 1 - fi - ;; -resolve) - shift 2 - ids="$*" - if [ "${ids:-}" = "--all" ]; then - echo "About to resolve EVERY unresolved thread. Only do this if you have read and" - echo "answered each one — a resolved-but-wrong thread is worse than an open one." - gh api graphql -f query="{repository(owner:\"${REPO%%/*}\",name:\"${REPO##*/}\"){pullRequest(number:$PR){reviewThreads(first:100){nodes{isResolved path comments(first:1){nodes{author{login} body}}}}}}}" \ - --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved==false) | " - \(.comments.nodes[0].author.login) \(.path): \(.comments.nodes[0].body[0:90])"' - printf 'Type "yes" to resolve all: '; read -r ok - [ "$ok" = "yes" ] || { echo "aborted"; exit 1; } - ids="" - elif [ -z "$ids" ]; then - echo "usage: pr_review.sh resolve (or --all, with confirmation)" >&2 - echo "resolve each thread as you answer it; get ids from: pr_review.sh status $PR" >&2 - exit 1 - fi - if [ -z "$ids" ]; then - ids=$(gh api graphql -f query="{repository(owner:\"${REPO%%/*}\",name:\"${REPO##*/}\"){pullRequest(number:$PR){reviewThreads(first:50){nodes{id isResolved}}}}}" \ - --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved==false) | .id') - fi - [ -z "$ids" ] && { echo "nothing unresolved"; exit 0; } - rfail=0 - for id in $ids; do - r=$(gh api graphql -f query="mutation{resolveReviewThread(input:{threadId:\"$id\"}){thread{isResolved}}}" \ - --jq '.data.resolveReviewThread.thread.isResolved' 2>&1) - echo " $id -> $r" - [ "$r" = "true" ] || rfail=1 - done - # exiting 0 on a failed mutation would let a session believe threads were resolved - exit "$rfail" - ;; -watch) - MINS="${3:-180}" # the addon build alone has taken ~3h; 20 was far too short - wfail=2 # not 0: running out of minutes with checks still pending is not a pass - for i in $(seq 1 "$MINS"); do - c=$(gh pr checks "$PR" 2> /dev/null | awk '{print $1"="$2}' | tr '\n' ' ') - if [ -z "$c" ]; then - # Normal in the first minutes after `gh pr create`, and also whenever gh errors. - # Calling that "settled" would report success for checks that never ran. - echo "[$i] no checks reported yet (gh returned nothing) — still waiting" - sleep 60; continue + list) + echo "== inline comments on #$PR ==" + gh api "repos/$REPO/pulls/$PR/comments" --paginate \ + --jq 'sort_by(.created_at)[] | "=== [\(.id)] \(.user.login) | \(.path):\(.line // .original_line) ===\n\(.body)\n"' + echo "== review bodies ==" + gh api "repos/$REPO/pulls/$PR/reviews" \ + --jq '.[] | select(.body != "") | "--- \(.user.login) (\(.state)) ---\n\(.body[0:4000])\n"' + ;; + status) + gh pr checks "$PR" 2>&1 | head -15 + echo + gh api graphql -f query="{repository(owner:\"${REPO%%/*}\",name:\"${REPO##*/}\"){pullRequest(number:$PR){reviewThreads(first:50){nodes{id isResolved path comments(first:1){nodes{author{login}}}}}}}}" \ + --jq '.data.repository.pullRequest.reviewThreads.nodes[] | "\(if .isResolved then "resolved" else "OPEN " end) \(.id) \(.comments.nodes[0].author.login) \(.path)"' + ;; + reply) + ID="${3:?comment id}" + BODY="${4:?text or @file}" + if [ "${BODY#@}" != "$BODY" ]; then + out=$(gh api "repos/$REPO/pulls/$PR/comments/$ID/replies" -F body=@"${BODY#@}" --jq '.id' 2>&1) + rc=$? + else + out=$(gh api "repos/$REPO/pulls/$PR/comments/$ID/replies" -f body="$BODY" --jq '.id' 2>&1) + rc=$? fi - echo "[$i] $c" - case "$c" in - *pending*) sleep 60 ;; - *fail* | *error* | *cancel*) echo "settled — with FAILURES (see above)"; wfail=1; break ;; - *) echo "settled — all passing"; wfail=0; break ;; - esac - done - [ "$wfail" -eq 2 ] && echo "gave up after ${MINS}m, checks still unsettled — NOT a pass" - # A PR touching no */config.* skips the CHANGELOG, linter and build jobs outright (#3018). - case "${c:-}" in *skipping*) echo " ...of which some were SKIPPED — a skipped job tested nothing" ;; esac - echo "note: long queues here are usually account runner contention, not your diff." - exit "$wfail" - ;; -*) echo "unknown: $CMD"; exit 1 ;; + # Silently "succeeding" here is worse than failing: a later session reads the transcript and + # believes a reviewer was answered when they were not. + if [ "$rc" -eq 0 ] && [ -n "$out" ]; then + echo "replied to $ID (comment $out)" + else + echo "FAILED to reply to $ID: $out" >&2 + echo " (top-level review bodies have different ids and cannot take replies here)" >&2 + exit 1 + fi + ;; + resolve) + shift 2 + ids="$*" + if [ "${ids:-}" = "--all" ]; then + echo "About to resolve EVERY unresolved thread. Only do this if you have read and" + echo "answered each one — a resolved-but-wrong thread is worse than an open one." + gh api graphql -f query="{repository(owner:\"${REPO%%/*}\",name:\"${REPO##*/}\"){pullRequest(number:$PR){reviewThreads(first:100){nodes{isResolved path comments(first:1){nodes{author{login} body}}}}}}}" \ + --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved==false) | " - \(.comments.nodes[0].author.login) \(.path): \(.comments.nodes[0].body[0:90])"' + printf 'Type "yes" to resolve all: ' + read -r ok + [ "$ok" = "yes" ] || { + echo "aborted" + exit 1 + } + ids="" + elif [ -z "$ids" ]; then + echo "usage: pr_review.sh resolve (or --all, with confirmation)" >&2 + echo "resolve each thread as you answer it; get ids from: pr_review.sh status $PR" >&2 + exit 1 + fi + if [ -z "$ids" ]; then + ids=$(gh api graphql -f query="{repository(owner:\"${REPO%%/*}\",name:\"${REPO##*/}\"){pullRequest(number:$PR){reviewThreads(first:50){nodes{id isResolved}}}}}" \ + --jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved==false) | .id') + fi + [ -z "$ids" ] && { + echo "nothing unresolved" + exit 0 + } + rfail=0 + for id in $ids; do + r=$(gh api graphql -f query="mutation{resolveReviewThread(input:{threadId:\"$id\"}){thread{isResolved}}}" \ + --jq '.data.resolveReviewThread.thread.isResolved' 2>&1) + echo " $id -> $r" + [ "$r" = "true" ] || rfail=1 + done + # exiting 0 on a failed mutation would let a session believe threads were resolved + exit "$rfail" + ;; + watch) + MINS="${3:-180}" # the addon build alone has taken ~3h; 20 was far too short + wfail=2 # not 0: running out of minutes with checks still pending is not a pass + for i in $(seq 1 "$MINS"); do + c=$(gh pr checks "$PR" 2> /dev/null | awk '{print $1"="$2}' | tr '\n' ' ') + if [ -z "$c" ]; then + # Normal in the first minutes after `gh pr create`, and also whenever gh errors. + # Calling that "settled" would report success for checks that never ran. + echo "[$i] no checks reported yet (gh returned nothing) — still waiting" + sleep 60 + continue + fi + echo "[$i] $c" + case "$c" in + *pending*) sleep 60 ;; + *fail* | *error* | *cancel*) + echo "settled — with FAILURES (see above)" + wfail=1 + break + ;; + *) + echo "settled — all passing" + wfail=0 + break + ;; + esac + done + [ "$wfail" -eq 2 ] && echo "gave up after ${MINS}m, checks still unsettled — NOT a pass" + # A PR touching no */config.* skips the CHANGELOG, linter and build jobs outright (#3018). + case "${c:-}" in *skipping*) echo " ...of which some were SKIPPED — a skipped job tested nothing" ;; esac + echo "note: long queues here are usually account runner contention, not your diff." + exit "$wfail" + ;; + *) + echo "unknown: $CMD" + exit 1 + ;; esac diff --git a/.claude/skills/hassio-addon-workflow/scripts/preflight.sh b/.claude/skills/hassio-addon-workflow/scripts/preflight.sh index a61495b00d..76367647a7 100755 --- a/.claude/skills/hassio-addon-workflow/scripts/preflight.sh +++ b/.claude/skills/hassio-addon-workflow/scripts/preflight.sh @@ -47,7 +47,10 @@ if [ -n "${BUILD_VERSION:-}" ]; then if [ -z "$SLUG" ] && [ -n "${HOSTNAME:-}" ]; then base=$(printf '%s' "$HOSTNAME" | sed 's/^[0-9a-f]\{8\}-//') for cand in "$(printf '%s' "$base" | tr '-' '_')" "$base"; do - [ -f "$REPO/$cand/config.yaml" ] && { SLUG="$cand"; break; } + [ -f "$REPO/$cand/config.yaml" ] && { + SLUG="$cand" + break + } done [ -z "$SLUG" ] && SLUG="$base" fi @@ -69,8 +72,8 @@ if [ -n "${BUILD_VERSION:-}" ]; then else echo " MISMATCH — this branch is NOT what is running." git fetch origin master --quiet 2> /dev/null - master=$(git show origin/master:"$SLUG/config.yaml" 2> /dev/null | - grep -E '^version:' | head -1 | tr -d "\"'" | awk '{print $2}') + master=$(git show origin/master:"$SLUG/config.yaml" 2> /dev/null \ + | grep -E '^version:' | head -1 | tr -d "\"'" | awk '{print $2}') echo " origin/master version = ${master:-unknown}" echo " -> work from origin/master; analysing this branch will mislead you." echo diff --git a/.claude/skills/hassio-addon-workflow/scripts/validate.sh b/.claude/skills/hassio-addon-workflow/scripts/validate.sh index 442f5361ae..794dc97c87 100755 --- a/.claude/skills/hassio-addon-workflow/scripts/validate.sh +++ b/.claude/skills/hassio-addon-workflow/scripts/validate.sh @@ -13,22 +13,31 @@ set -uo pipefail if root=$(git rev-parse --show-toplevel 2> /dev/null); then cd "$root" || exit 1; fi ADDON="${1:-}" -[ "${ADDON:-}" = "--vs-master" ] && { ADDON=""; set -- --vs-master; } +[ "${ADDON:-}" = "--vs-master" ] && { + ADDON="" + set -- --vs-master +} VS_MASTER=false for a in "$@"; do [ "$a" = "--vs-master" ] && VS_MASTER=true; done if [ -z "$ADDON" ]; then - mapfile -t _dirs < <(git diff --name-only origin/master...HEAD 2> /dev/null | - cut -d/ -f1 | sort -u | grep -vE '^\.' ) + mapfile -t _dirs < <(git diff --name-only origin/master...HEAD 2> /dev/null \ + | cut -d/ -f1 | sort -u | grep -vE '^\.') if [ "${#_dirs[@]}" -gt 1 ]; then echo "several changed dirs: ${_dirs[*]}" - echo "pass one explicitly: validate.sh "; exit 1 + echo "pass one explicitly: validate.sh " + exit 1 fi ADDON="${_dirs[0]:-}" fi -[ -z "$ADDON" ] && { echo "usage: validate.sh [--vs-master]"; exit 1; } +[ -z "$ADDON" ] && { + echo "usage: validate.sh [--vs-master]" + exit 1 +} git rev-parse --verify origin/master > /dev/null 2>&1 || { - echo "origin/master missing — run: git fetch origin master"; exit 1; } + echo "origin/master missing — run: git fetch origin master" + exit 1 +} export PYTHONDONTWRITEBYTECODE=1 echo "== validating $ADDON ==" @@ -36,14 +45,22 @@ fail=0 note() { printf ' %-13s %s\n' "$1" "$2"; } # execline `run`/`finish` files are not shell (25 of them here, across 21 add-ons). Neither # linter below can read one, so anything either says about it is noise. -is_execline() { local l; IFS= read -r l < "$1" 2> /dev/null; [[ $l == '#!'*execlineb* ]]; } +is_execline() { + local l + IFS= read -r l < "$1" 2> /dev/null + [[ $l == '#!'*execlineb* ]] +} # Shell: bash -n then shellcheck -x (follows sourced files, as CI does). One list for both. files=() while IFS= read -r f; do is_execline "$f" || files+=("$f"); done \ < <(find "$ADDON" -type f \( -name '*.sh' -o -name 'run' -o -name 'finish' -o -name 'autostart' \) 2> /dev/null) for f in "${files[@]}"; do - if ! out=$(bash -n "$f" 2>&1); then note "bash -n" "FAIL $f"; echo "$out" | sed 's/^/ /'; fail=1; fi + if ! out=$(bash -n "$f" 2>&1); then + note "bash -n" "FAIL $f" + echo "$out" | sed 's/^/ /' + fail=1 + fi done [ "$fail" -eq 0 ] && note "bash -n" "${#files[@]} file(s) checked" @@ -65,13 +82,16 @@ command -v hadolint > /dev/null 2>&1 && [ -f "$ADDON/Dockerfile" ] && { if [ -f "$ADDON/config.yaml" ]; then # path passed as argv, never interpolated into Python source - python3 - "$ADDON/config.yaml" <<'PY' || { note "config.yaml" "FAIL parse"; fail=1; } + python3 - "$ADDON/config.yaml" << 'PY' || { import yaml,sys d=yaml.safe_load(open(sys.argv[1])) print(' %-13s ok (version=%s, %d options)' % ('config.yaml', d.get('version'), len(d.get('options') or {}))) missing=[k for k in (d.get('options') or {}) if k not in (d.get('schema') or {})] if missing: print(' %-13s options with no schema entry: %s' % ('WARN', missing)); sys.exit(0) PY + note "config.yaml" "FAIL parse" + fail=1 + } command -v yamllint > /dev/null 2>&1 && { yl=$(yamllint -f parsable "$ADDON/config.yaml" 2>&1 | grep -c .) note "yamllint" "$yl finding(s) (compare with --vs-master)" @@ -79,7 +99,10 @@ PY fi while IFS= read -r f; do - python3 -m py_compile "$f" 2> /dev/null || { note "py_compile" "FAIL $f"; fail=1; } + python3 -m py_compile "$f" 2> /dev/null || { + note "py_compile" "FAIL $f" + fail=1 + } done < <(find "$ADDON" -type f -name '*.py' 2> /dev/null) $VS_MASTER && command -v npx > /dev/null 2>&1 && [ -f "$ADDON/CHANGELOG.md" ] && { @@ -96,7 +119,8 @@ if git diff --name-only origin/master...HEAD 2> /dev/null | grep -Fxq "$ADDON/CH note "CHANGELOG" "updated" else # This one IS gated: onpr_check-pr.yaml exits 1 without it. - note "CHANGELOG" "NOT UPDATED for $ADDON — CI hard-gates this"; fail=1 + note "CHANGELOG" "NOT UPDATED for $ADDON — CI hard-gates this" + fail=1 fi if git diff origin/master...HEAD -- "$ADDON/config.yaml" 2> /dev/null | grep -q '^+version:'; then note "version" "bumped" @@ -110,7 +134,8 @@ note "docker build" "NOT tested locally (dockerd unavailable) — CI is the only if $VS_MASTER; then echo echo "== findings ADDED by this diff (pre-existing ones filtered out) ==" - tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT + tmp=$(mktemp -d) + trap 'rm -rf "$tmp"' EXIT added=0 # Fed by process substitution, not a pipe: a pipeline runs this in a subshell, where the # findings below could never reach $fail and the verdict would contradict the list. @@ -125,14 +150,26 @@ if $VS_MASTER; then # cancel it out and report a false clean. case "$f" in *.sh | *autostart | */run | */finish) - command -v shellcheck > /dev/null 2>&1 || { echo " $f: SKIPPED (shellcheck not installed)"; continue; } - cmd() { shellcheck -x -f gcc "$1" 2>&1 | sed 's/^[^:]*:[0-9]*:[0-9]*://'; } ;; + command -v shellcheck > /dev/null 2>&1 || { + echo " $f: SKIPPED (shellcheck not installed)" + continue + } + cmd() { shellcheck -x -f gcc "$1" 2>&1 | sed 's/^[^:]*:[0-9]*:[0-9]*://'; } + ;; *.yaml | *.yml) - command -v yamllint > /dev/null 2>&1 || { echo " $f: SKIPPED (yamllint not installed)"; continue; } - cmd() { yamllint -f parsable "$1" 2>&1 | sed 's/^[^:]*//; s/^:[0-9]*:[0-9]*//'; } ;; + command -v yamllint > /dev/null 2>&1 || { + echo " $f: SKIPPED (yamllint not installed)" + continue + } + cmd() { yamllint -f parsable "$1" 2>&1 | sed 's/^[^:]*//; s/^:[0-9]*:[0-9]*//'; } + ;; *Dockerfile) - command -v hadolint > /dev/null 2>&1 || { echo " $f: SKIPPED (hadolint not installed)"; continue; } - cmd() { hadolint "$1" 2>&1 | sed 's/^[^:]*//; s/^:[0-9]*//'; } ;; + command -v hadolint > /dev/null 2>&1 || { + echo " $f: SKIPPED (hadolint not installed)" + continue + } + cmd() { hadolint "$1" 2>&1 | sed 's/^[^:]*//; s/^:[0-9]*//'; } + ;; *) continue ;; esac b=$(cmd "$tmp/base" | sort) @@ -141,7 +178,8 @@ if $VS_MASTER; then [ -n "$new" ] && { echo " $f: $(printf '%s\n' "$new" | grep -c .) NEW finding(s)" printf '%s\n' "$new" | sed 's/^/ /' | head -5 - added=1; fail=1 + added=1 + fail=1 } done < <(git diff --name-only origin/master...HEAD -- "$ADDON" 2> /dev/null) [ "$added" -eq 0 ] && echo " (none — this diff introduced no new lint findings)" diff --git a/.github/prompts/issue-classify.md b/.github/prompts/issue-classify.md index fe2e7d9562..4ff92a0865 100644 --- a/.github/prompts/issue-classify.md +++ b/.github/prompts/issue-classify.md @@ -40,7 +40,7 @@ the check is a guard, not a common case.) ## Rule 1 — pick exactly one verdict | verdict | when | -|---|---| +| --- | --- | | `duplicate` | An existing open or closed issue reports the same thing. Set `duplicate_of`. | | `needs-info` | You cannot tell what is wrong without the add-on version, HA version, architecture, config, or the actual log output. | | `question` | A usage question answerable from `DOCS.md`, the wiki, or the add-on config. Not a defect. | diff --git a/.github/prompts/issue-fix.md b/.github/prompts/issue-fix.md index d0cfbfa1c2..1d710dfda5 100644 --- a/.github/prompts/issue-fix.md +++ b/.github/prompts/issue-fix.md @@ -39,7 +39,7 @@ rest are on you: nothing checks them, so breaking one ships silently. that value, and compare: | `version` vs `U` | what to do | example | - |---|---|---| + | --- | --- | --- | | identical | **append** `.1` | sonarr `4.0.19.3001` -> `4.0.19.3001.1` | | `U` + `.` + digits | **increment** those digits | radarr `6.3.0.10514.1` -> `6.3.0.10514.2` | | anything else | **leave it alone** | plex, readarr, joal | diff --git a/.github/scripts/ai_guard_paths.sh b/.github/scripts/ai_guard_paths.sh index 6e37523c82..94468b2d2d 100755 --- a/.github/scripts/ai_guard_paths.sh +++ b/.github/scripts/ai_guard_paths.sh @@ -44,7 +44,7 @@ for pr in $PRS; do echo "$BAD" # Ensure the label exists before adding it — with set -e a missing # label would abort the whole loop and skip any PRs behind this one. - gh label create "ai:blocked" --repo "$REPO" --color ededed >/dev/null 2>&1 || true + gh label create "ai:blocked" --repo "$REPO" --color ededed > /dev/null 2>&1 || true gh pr ready "$pr" --repo "$REPO" --undo || true gh pr edit "$pr" --repo "$REPO" --add-label "ai:blocked" gh pr comment "$pr" --repo "$REPO" --body \ diff --git a/.github/scripts/ai_triage_context.sh b/.github/scripts/ai_triage_context.sh index 9d08d3a984..c8d1a71a31 100755 --- a/.github/scripts/ai_triage_context.sh +++ b/.github/scripts/ai_triage_context.sh @@ -15,110 +15,116 @@ CTX="$OUT/context.md" : > "$CTX" gh issue view "$ISSUE_NUMBER" --repo "$REPO" \ - --json number,title,body,author,labels,createdAt,comments > "$OUT/issue.json" + --json number,title,body,author,labels,createdAt,comments > "$OUT/issue.json" TITLE=$(jq -r '.title' "$OUT/issue.json") # ---------------------------------------------------------------- addon slug # Titles follow "🐛 [Immich Frame] ENV_VARS arent being picked up". -RAW=$(sed -n 's/.*\[\([^]]*\)\].*/\1/p' <<<"$TITLE" | head -n1) +RAW=$(sed -n 's/.*\[\([^]]*\)\].*/\1/p' <<< "$TITLE" | head -n1) ADDON="" if [ -n "$RAW" ]; then - CAND=$(tr '[:upper:] ' '[:lower:]_' <<<"$RAW") - # Directory list without checking out any of them. - git ls-tree -d --name-only HEAD > "$OUT/dirs.txt" - for guess in "$CAND" "${CAND//_/-}" "${CAND//_/.}"; do - if grep -qxF "$guess" "$OUT/dirs.txt"; then ADDON="$guess"; break; fi - done - # Separator-insensitive exact match: a title like "[Calibre-web]" (hyphen) - # against a directory named calibre_web (underscore) matches neither exact - # guess above, and would otherwise fall through to the substring fallback - # below, which picks the shorter "calibre" instead — the wrong add-on. - # Stripping -, _, . from both sides before comparing catches this case. - if [ -z "$ADDON" ]; then - CAND_STRIPPED=$(tr -d '_.-' <<<"$CAND") - while IFS= read -r dir; do - if [ "$(tr -d '_.-' <<<"$dir")" = "$CAND_STRIPPED" ]; then ADDON="$dir"; break; fi - done < "$OUT/dirs.txt" - fi - # Last resort: longest directory name contained in the candidate. - if [ -z "$ADDON" ]; then - ADDON=$(awk -v c="$CAND" 'length($0)>2 && index(c,$0){print length($0)"\t"$0}' \ + CAND=$(tr '[:upper:] ' '[:lower:]_' <<< "$RAW") + # Directory list without checking out any of them. + git ls-tree -d --name-only HEAD > "$OUT/dirs.txt" + for guess in "$CAND" "${CAND//_/-}" "${CAND//_/.}"; do + if grep -qxF "$guess" "$OUT/dirs.txt"; then + ADDON="$guess" + break + fi + done + # Separator-insensitive exact match: a title like "[Calibre-web]" (hyphen) + # against a directory named calibre_web (underscore) matches neither exact + # guess above, and would otherwise fall through to the substring fallback + # below, which picks the shorter "calibre" instead — the wrong add-on. + # Stripping -, _, . from both sides before comparing catches this case. + if [ -z "$ADDON" ]; then + CAND_STRIPPED=$(tr -d '_.-' <<< "$CAND") + while IFS= read -r dir; do + if [ "$(tr -d '_.-' <<< "$dir")" = "$CAND_STRIPPED" ]; then + ADDON="$dir" + break + fi + done < "$OUT/dirs.txt" + fi + # Last resort: longest directory name contained in the candidate. + if [ -z "$ADDON" ]; then + ADDON=$(awk -v c="$CAND" 'length($0)>2 && index(c,$0){print length($0)"\t"$0}' \ "$OUT/dirs.txt" | sort -rn | head -n1 | cut -f2) - fi + fi fi { - echo "# Issue #${ISSUE_NUMBER}" - echo - echo "Repo: ${REPO}" - echo "Addon resolved from title: ${ADDON:-UNRESOLVED}" - echo - echo "## Title" - echo "$TITLE" - echo - echo "## Author" - jq -r '.author.login' "$OUT/issue.json" - echo - echo "## Body" - echo '```' - jq -r '.body // "(empty)"' "$OUT/issue.json" - echo '```' - echo - echo "## Existing comments (in order)" - jq -r '.comments[]? | "### @\(.author.login)\n\(.body)\n"' "$OUT/issue.json" - echo - echo "## Existing labels" - jq -r '[.labels[]?.name] | join(", ")' "$OUT/issue.json" + echo "# Issue #${ISSUE_NUMBER}" + echo + echo "Repo: ${REPO}" + echo "Addon resolved from title: ${ADDON:-UNRESOLVED}" + echo + echo "## Title" + echo "$TITLE" + echo + echo "## Author" + jq -r '.author.login' "$OUT/issue.json" + echo + echo "## Body" + echo '```' + jq -r '.body // "(empty)"' "$OUT/issue.json" + echo '```' + echo + echo "## Existing comments (in order)" + jq -r '.comments[]? | "### @\(.author.login)\n\(.body)\n"' "$OUT/issue.json" + echo + echo "## Existing labels" + jq -r '[.labels[]?.name] | join(", ")' "$OUT/issue.json" } >> "$CTX" # ------------------------------------------------------------- addon sources if [ -n "$ADDON" ]; then - { - echo - echo "## Addon files: ${ADDON}/" - # `set` REPLACES the checkout list, so .templates has to be repeated here - # or the workflow's sparse-checkout of it is silently undone at this point - # — which is exactly the state that starved #2949 of its turn budget. - if ! git sparse-checkout set --no-cone .github/prompts .github/scripts .templates "$ADDON" 2>&1; then - # Swallowing this used to leave ADDON resolved with no files behind it, - # so the classifier could still reach high confidence off the addon - # name alone. Say so explicitly, in the same word Rule 2 already keys - # its low-confidence check on. - echo - echo "**Could not check out this add-on's source. Treat as UNRESOLVED for confidence purposes.**" - else - for f in config.yaml config.json Dockerfile CHANGELOG.md DOCS.md README.md; do - [ -f "$ADDON/$f" ] || continue + { echo - echo "### ${ADDON}/${f}" - echo '```' - head -c 8000 "$ADDON/$f" - echo '```' - done + echo "## Addon files: ${ADDON}/" + # `set` REPLACES the checkout list, so .templates has to be repeated here + # or the workflow's sparse-checkout of it is silently undone at this point + # — which is exactly the state that starved #2949 of its turn budget. + if ! git sparse-checkout set --no-cone .github/prompts .github/scripts .templates "$ADDON" 2>&1; then + # Swallowing this used to leave ADDON resolved with no files behind it, + # so the classifier could still reach high confidence off the addon + # name alone. Say so explicitly, in the same word Rule 2 already keys + # its low-confidence check on. + echo + echo "**Could not check out this add-on's source. Treat as UNRESOLVED for confidence purposes.**" + else + for f in config.yaml config.json Dockerfile CHANGELOG.md DOCS.md README.md; do + [ -f "$ADDON/$f" ] || continue + echo + echo "### ${ADDON}/${f}" + echo '```' + head -c 8000 "$ADDON/$f" + echo '```' + done - echo - echo "## Recent commits touching ${ADDON}/" - git log -n 15 --date=short --pretty='- %ad %h %s' -- "$ADDON" 2>/dev/null || true - fi - } >> "$CTX" + echo + echo "## Recent commits touching ${ADDON}/" + git log -n 15 --date=short --pretty='- %ad %h %s' -- "$ADDON" 2> /dev/null || true + fi + } >> "$CTX" fi # -------------------------------------------------------- possible duplicates { - echo - echo "## Similar existing issues (candidate duplicates)" - KEYWORDS=$(tr -cs '[:alnum:]' ' ' <<<"$TITLE" \ - | tr '[:upper:]' '[:lower:]' \ - | tr ' ' '\n' | awk 'length($0)>3' | head -n6 | paste -sd' ') - # Excludes the issue being triaged: if it's already indexed by GitHub search - # by the time this runs, keyword overlap with its own title would otherwise - # list it as a "candidate duplicate" of itself. - gh search issues --repo "$REPO" --limit 15 \ - --json number,title,state,url -- "$KEYWORDS" 2>/dev/null \ - | jq -r --argjson self "$ISSUE_NUMBER" \ - '.[] | select(.number != $self) | "- #\(.number) [\(.state)] \(.title)"' \ - || echo "(search unavailable)" + echo + echo "## Similar existing issues (candidate duplicates)" + KEYWORDS=$(tr -cs '[:alnum:]' ' ' <<< "$TITLE" \ + | tr '[:upper:]' '[:lower:]' \ + | tr ' ' '\n' | awk 'length($0)>3' | head -n6 | paste -sd' ') + # Excludes the issue being triaged: if it's already indexed by GitHub search + # by the time this runs, keyword overlap with its own title would otherwise + # list it as a "candidate duplicate" of itself. + gh search issues --repo "$REPO" --limit 15 \ + --json number,title,state,url -- "$KEYWORDS" 2> /dev/null \ + | jq -r --argjson self "$ISSUE_NUMBER" \ + '.[] | select(.number != $self) | "- #\(.number) [\(.state)] \(.title)"' \ + || echo "(search unavailable)" } >> "$CTX" echo "context bundle: $(wc -c < "$CTX") bytes, addon=${ADDON:-none}" diff --git a/.templates/00-banner.sh b/.templates/00-banner.sh index 60483f96e2..e33b16b241 100755 --- a/.templates/00-banner.sh +++ b/.templates/00-banner.sh @@ -6,7 +6,7 @@ set -e # Banner # ====================================================================== -if ! bashio::supervisor.ping 2>/dev/null; then +if ! bashio::supervisor.ping 2> /dev/null; then # Source standalone bashio first to provide function definitions if [ -f /usr/local/lib/bashio-standalone.sh ]; then source /usr/local/lib/bashio-standalone.sh @@ -19,11 +19,11 @@ if ! bashio::supervisor.ping 2>/dev/null; then if [ ! -f /usr/bin/bashio ]; then cp -rf /usr/local/lib/bashio-standalone.sh /usr/bin/bashio fi - grep -rl "^#!.*bashio" /etc | - while IFS= read -r f; do - grep -qF "source /usr/local/lib/bashio-standalone.sh" "$f" && continue - sed -i '1a source /usr/local/lib/bashio-standalone.sh' "$f" - done + grep -rl "^#!.*bashio" /etc \ + | while IFS= read -r f; do + grep -qF "source /usr/local/lib/bashio-standalone.sh" "$f" && continue + sed -i '1a source /usr/local/lib/bashio-standalone.sh' "$f" + done else bashio::log.blue '-----------------------------------------------------------' bashio::log.blue " Add-on: $(bashio::addon.name)" @@ -49,7 +49,7 @@ bashio::log.green ' Provided by: https://github.com/alexbelgium/hassio-addons ' bashio::log.blue '-----------------------------------------------------------' # Adapt user abc -if command -v id &>/dev/null && id abc &>/dev/null; then +if command -v id &> /dev/null && id abc &> /dev/null; then if bashio::config.has_value "PUID" && bashio::config.has_value "PGID"; then PUID="$(bashio::config "PUID")" PGID="$(bashio::config "PGID")" diff --git a/.templates/00-global_var.sh b/.templates/00-global_var.sh index 711c65c82d..11dc64b91b 100755 --- a/.templates/00-global_var.sh +++ b/.templates/00-global_var.sh @@ -152,15 +152,15 @@ if [[ "${1:-}" == "--self-test" ]]; then done fi - [[ "$self_test_rc" -eq 0 ]] && - echo "${#self_test_values[@]} values round-tripped unchanged (export block + dotenv)" + [[ "$self_test_rc" -eq 0 ]] \ + && echo "${#self_test_values[@]} values round-tripped unchanged (export block + dotenv)" exit "$self_test_rc" fi ################################################################################ # Guard: only run inside Supervisor-managed add-ons ################################################################################ -if ! bashio::supervisor.ping 2>/dev/null; then +if ! bashio::supervisor.ping 2> /dev/null; then echo "..." exit 0 fi @@ -179,7 +179,7 @@ ENV_FILE="/.env" ETC_ENV_FILE="/etc/environment" [[ -f "$JSONSOURCE" ]] || bashio::exit.nok "Missing $JSONSOURCE" -command -v jq >/dev/null || bashio::exit.nok "jq is required" +command -v jq > /dev/null || bashio::exit.nok "jq is required" mkdir -p /etc touch "$ETC_ENV_FILE" @@ -193,7 +193,10 @@ SECRETSOURCE="" resolve_secret() { local v="$1" name line - [[ "$v" =~ ^[[:space:]]*\!secret[[:space:]]+(.+)$ ]] || { printf '%s' "$v"; return; } + [[ "$v" =~ ^[[:space:]]*\!secret[[:space:]]+(.+)$ ]] || { + printf '%s' "$v" + return + } name="${BASH_REMATCH[1]}" [[ -n "$SECRETSOURCE" ]] || bashio::exit.nok "Secrets not mounted" diff --git a/.templates/00-smb_mounts.sh b/.templates/00-smb_mounts.sh index 50d902710e..3e714ecc7d 100755 --- a/.templates/00-smb_mounts.sh +++ b/.templates/00-smb_mounts.sh @@ -4,9 +4,9 @@ set -e -if ! bashio::supervisor.ping 2>/dev/null; then - bashio::log.blue "Disabled : please use another method" - exit 0 +if ! bashio::supervisor.ping 2> /dev/null; then + bashio::log.blue "Disabled : please use another method" + exit 0 fi bashio::log.notice "This script is used to mount remote smb/cifs/nfs shares. Instructions here : https://github.com/alexbelgium/hassio-addons/wiki/Mounting-remote-shares-in-Addons" @@ -16,167 +16,167 @@ bashio::log.notice "This script is used to mount remote smb/cifs/nfs shares. Ins #################### cleanup_cred() { - if [[ -n "${CRED_FILE:-}" && -f "${CRED_FILE:-}" ]]; then - rm -f "$CRED_FILE" || true - fi - CRED_FILE="" + if [[ -n "${CRED_FILE:-}" && -f "${CRED_FILE:-}" ]]; then + rm -f "$CRED_FILE" || true + fi + CRED_FILE="" } test_mount() { - MOUNTED=false - ERROR_MOUNT=false - mountpoint="/mnt/$diskname" - - if ! mountpoint -q "$mountpoint"; then - return 0 - fi - - _test_write() { - local testfile="$mountpoint/.writetest_$$" - if : >"$testfile" 2>/dev/null; then - rm -f "$testfile" 2>/dev/null || true - return 0 - else - rm -f "$testfile" 2>/dev/null || true - return 1 - fi - } - - if _test_write 2>/dev/null; then - MOUNTED=true - return 0 - fi - - local orig_mountoptions="$MOUNTOPTIONS" - - if [[ "$FSTYPE" == "cifs" && "$orig_mountoptions" != *"noserverino"* ]]; then - echo "... retrying mount with noserverino" - MOUNTOPTIONS="${orig_mountoptions},noserverino" - - umount "$mountpoint" 2>/dev/null || true - if mount_drive "$MOUNTOPTIONS"; then - if _test_write 2>/dev/null; then - MOUNTED=true - return 0 - fi - fi - fi - - if [[ "$FSTYPE" == "cifs" && "$orig_mountoptions" != *"noperm"* ]]; then - echo "... retrying mount with noperm" - MOUNTOPTIONS="${orig_mountoptions},noperm" - - umount "$mountpoint" 2>/dev/null || true - if mount_drive "$MOUNTOPTIONS"; then - if _test_write 2>/dev/null; then - MOUNTED=true - return 0 - fi - fi - fi - - if mountpoint -q "$mountpoint"; then - MOUNTED="readonly" - else MOUNTED=false - fi - return 0 + ERROR_MOUNT=false + mountpoint="/mnt/$diskname" + + if ! mountpoint -q "$mountpoint"; then + return 0 + fi + + _test_write() { + local testfile="$mountpoint/.writetest_$$" + if : > "$testfile" 2> /dev/null; then + rm -f "$testfile" 2> /dev/null || true + return 0 + else + rm -f "$testfile" 2> /dev/null || true + return 1 + fi + } + + if _test_write 2> /dev/null; then + MOUNTED=true + return 0 + fi + + local orig_mountoptions="$MOUNTOPTIONS" + + if [[ "$FSTYPE" == "cifs" && "$orig_mountoptions" != *"noserverino"* ]]; then + echo "... retrying mount with noserverino" + MOUNTOPTIONS="${orig_mountoptions},noserverino" + + umount "$mountpoint" 2> /dev/null || true + if mount_drive "$MOUNTOPTIONS"; then + if _test_write 2> /dev/null; then + MOUNTED=true + return 0 + fi + fi + fi + + if [[ "$FSTYPE" == "cifs" && "$orig_mountoptions" != *"noperm"* ]]; then + echo "... retrying mount with noperm" + MOUNTOPTIONS="${orig_mountoptions},noperm" + + umount "$mountpoint" 2> /dev/null || true + if mount_drive "$MOUNTOPTIONS"; then + if _test_write 2> /dev/null; then + MOUNTED=true + return 0 + fi + fi + fi + + if mountpoint -q "$mountpoint"; then + MOUNTED="readonly" + else + MOUNTED=false + fi + return 0 } mount_drive() { - MOUNTED=true - MOUNTOPTIONS="$1" + MOUNTED=true + MOUNTOPTIONS="$1" - if [[ "$FSTYPE" == "cifs" ]]; then - mount -t cifs -o "$MOUNTOPTIONS" "$disk" "/mnt/$diskname" 2>"$ERRORCODE_FILE" || MOUNTED=false - elif [[ "$FSTYPE" == "nfs" ]]; then - mount -t nfs -o "$MOUNTOPTIONS" "$disk" "/mnt/$diskname" 2>"$ERRORCODE_FILE" || MOUNTED=false - fi + if [[ "$FSTYPE" == "cifs" ]]; then + mount -t cifs -o "$MOUNTOPTIONS" "$disk" "/mnt/$diskname" 2> "$ERRORCODE_FILE" || MOUNTED=false + elif [[ "$FSTYPE" == "nfs" ]]; then + mount -t nfs -o "$MOUNTOPTIONS" "$disk" "/mnt/$diskname" 2> "$ERRORCODE_FILE" || MOUNTED=false + fi - if [[ "$MOUNTED" == "true" ]]; then - test_mount - fi + if [[ "$MOUNTED" == "true" ]]; then + test_mount + fi } # Retry ladder: SMB3 -> SMB2 when mount fails due to dialect/negotiation issues retry_cifs_with_vers_ladder_on_dialect_failure() { - [[ "${FSTYPE:-}" == "cifs" ]] || return 0 - [[ "${MOUNTED:-false}" == "false" ]] || return 0 - [[ "${CIFS_LADDER_ATTEMPTED:-false}" == "false" ]] || return 0 + [[ "${FSTYPE:-}" == "cifs" ]] || return 0 + [[ "${MOUNTED:-false}" == "false" ]] || return 0 + [[ "${CIFS_LADDER_ATTEMPTED:-false}" == "false" ]] || return 0 - local err mountpoint - mountpoint="/mnt/$diskname" - err="$(cat "$ERRORCODE_FILE" 2>/dev/null || true)" + local err mountpoint + mountpoint="/mnt/$diskname" + err="$(cat "$ERRORCODE_FILE" 2> /dev/null || true)" - if echo "$err" | grep -Eq 'mount error\(13\)|Permission denied|NT_STATUS_(LOGON_FAILURE|ACCESS_DENIED)|STATUS_(LOGON_FAILURE|ACCESS_DENIED)'; then - return 0 - fi + if echo "$err" | grep -Eq 'mount error\(13\)|Permission denied|NT_STATUS_(LOGON_FAILURE|ACCESS_DENIED)|STATUS_(LOGON_FAILURE|ACCESS_DENIED)'; then + return 0 + fi - if ! echo "$err" | grep -Eq 'mount error\(22\)|mount error\(95\)|mount error\(112\)|Server abruptly closed the connection|does not support the SMB version|Protocol negotiation|NT_STATUS_CONNECTION_DISCONNECTED'; then - return 0 - fi + if ! echo "$err" | grep -Eq 'mount error\(22\)|mount error\(95\)|mount error\(112\)|Server abruptly closed the connection|does not support the SMB version|Protocol negotiation|NT_STATUS_CONNECTION_DISCONNECTED'; then + return 0 + fi - CIFS_LADDER_ATTEMPTED=true - bashio::log.warning "...... CIFS negotiation/dialect failure: trying SMB dialect ladder (3.x -> 2.x -> 1.0)." + CIFS_LADDER_ATTEMPTED=true + bashio::log.warning "...... CIFS negotiation/dialect failure: trying SMB dialect ladder (3.x -> 2.x -> 1.0)." - local base_opts try_opts vers vopt sectry + local base_opts try_opts vers vopt sectry - base_opts="$MOUNTOPTIONS" - base_opts="$(echo "$base_opts" | sed -E 's/,vers=[^,]+//g; s/,sec=[^,]+//g')" - - local -a opt_variants=("" ",nounix" ",noserverino" ",nounix,noserverino") - local -a sec_variants=("" ",sec=ntlmssp" ",sec=ntlmv2" ",sec=ntlm") - local -a vers_variants=("3.1.1" "3.02" "3.0" "2.1" "2.0" "1.0") - - for vopt in "${opt_variants[@]}"; do - for vers in "${vers_variants[@]}"; do - for sectry in "${sec_variants[@]}"; do - [[ "$MOUNTED" == "false" ]] || break - umount "$mountpoint" 2>/dev/null || true - try_opts="${base_opts}${vopt},vers=${vers}${sectry}" - mount_drive "$try_opts" - done - [[ "$MOUNTED" == "false" ]] || break - done - [[ "$MOUNTED" == "false" ]] || break - done - - if [[ "$MOUNTED" == "false" ]]; then - bashio::log.warning "...... still failing after vers ladder; retrying with reduced CIFS options." base_opts="$MOUNTOPTIONS" base_opts="$(echo "$base_opts" | sed -E 's/,vers=[^,]+//g; s/,sec=[^,]+//g')" - base_opts="${base_opts//,mfsymlinks/}" - base_opts="${base_opts//,nobrl/}" - base_opts="$(echo "$base_opts" | sed -E 's/,iocharset=[^,]+//g')" - local -a vers_variants2=("2.1" "2.0" "1.0") + local -a opt_variants=("" ",nounix" ",noserverino" ",nounix,noserverino") + local -a sec_variants=("" ",sec=ntlmssp" ",sec=ntlmv2" ",sec=ntlm") + local -a vers_variants=("3.1.1" "3.02" "3.0" "2.1" "2.0" "1.0") + for vopt in "${opt_variants[@]}"; do - for vers in "${vers_variants2[@]}"; do - for sectry in "${sec_variants[@]}"; do - [[ "$MOUNTED" == "false" ]] || break - umount "$mountpoint" 2>/dev/null || true - try_opts="${base_opts}${vopt},vers=${vers}${sectry}" - mount_drive "$try_opts" + for vers in "${vers_variants[@]}"; do + for sectry in "${sec_variants[@]}"; do + [[ "$MOUNTED" == "false" ]] || break + umount "$mountpoint" 2> /dev/null || true + try_opts="${base_opts}${vopt},vers=${vers}${sectry}" + mount_drive "$try_opts" + done + [[ "$MOUNTED" == "false" ]] || break done [[ "$MOUNTED" == "false" ]] || break - done - [[ "$MOUNTED" == "false" ]] || break done if [[ "$MOUNTED" == "false" ]]; then - for vopt in "${opt_variants[@]}"; do - for vers in "${vers_variants2[@]}"; do - [[ "$MOUNTED" == "false" ]] || break - umount "$mountpoint" 2>/dev/null || true - try_opts="${base_opts}${vopt},vers=${vers},sec=ntlmssp" - mount_drive "$try_opts" - done - [[ "$MOUNTED" == "false" ]] || break - done - fi - fi + bashio::log.warning "...... still failing after vers ladder; retrying with reduced CIFS options." + base_opts="$MOUNTOPTIONS" + base_opts="$(echo "$base_opts" | sed -E 's/,vers=[^,]+//g; s/,sec=[^,]+//g')" + base_opts="${base_opts//,mfsymlinks/}" + base_opts="${base_opts//,nobrl/}" + base_opts="$(echo "$base_opts" | sed -E 's/,iocharset=[^,]+//g')" - return 0 + local -a vers_variants2=("2.1" "2.0" "1.0") + for vopt in "${opt_variants[@]}"; do + for vers in "${vers_variants2[@]}"; do + for sectry in "${sec_variants[@]}"; do + [[ "$MOUNTED" == "false" ]] || break + umount "$mountpoint" 2> /dev/null || true + try_opts="${base_opts}${vopt},vers=${vers}${sectry}" + mount_drive "$try_opts" + done + [[ "$MOUNTED" == "false" ]] || break + done + [[ "$MOUNTED" == "false" ]] || break + done + + if [[ "$MOUNTED" == "false" ]]; then + for vopt in "${opt_variants[@]}"; do + for vers in "${vers_variants2[@]}"; do + [[ "$MOUNTED" == "false" ]] || break + umount "$mountpoint" 2> /dev/null || true + try_opts="${base_opts}${vopt},vers=${vers},sec=ntlmssp" + mount_drive "$try_opts" + done + [[ "$MOUNTED" == "false" ]] || break + done + fi + fi + + return 0 } ######################## @@ -185,289 +185,289 @@ retry_cifs_with_vers_ladder_on_dialect_failure() { if bashio::config.has_value 'networkdisks'; then - echo "Mounting network share(s)..." + echo "Mounting network share(s)..." - MOREDISKS="$(bashio::config 'networkdisks')" - USERNAME="$(bashio::config 'cifsusername')" - PASSWORD="$(bashio::config 'cifspassword')" + MOREDISKS="$(bashio::config 'networkdisks')" + USERNAME="$(bashio::config 'cifsusername')" + PASSWORD="$(bashio::config 'cifspassword')" - SMBVERS="" - SECVERS="" - CHARSET=",iocharset=utf8" - - MOREDISKS="${MOREDISKS//$'\r'/}" - MOREDISKS="${MOREDISKS//$'\n'/,}" - MOREDISKS="$(echo "$MOREDISKS" | sed -E 's/[[:space:]]*,[[:space:]]*/,/g; s/^[[:space:]]+//; s/[[:space:]]+$//')" - - DOMAINCLIENT="" - CIFSDOMAIN="" - if bashio::config.has_value 'cifsdomain'; then - CIFSDOMAIN="$(bashio::config 'cifsdomain')" - echo "... using domain $CIFSDOMAIN" - DOMAINCLIENT="--workgroup=$CIFSDOMAIN" - fi - - PUID=",uid=$(id -u)" - PGID=",gid=$(id -g)" - if bashio::config.has_value 'PUID' && bashio::config.has_value 'PGID'; then - echo "... using PUID $(bashio::config 'PUID') and PGID $(bashio::config 'PGID')" - PUID=",uid=$(bashio::config 'PUID')" - PGID=",gid=$(bashio::config 'PGID')" - fi - - IFS=',' read -r -a DISK_LIST <<< "$MOREDISKS" - - for disk in "${DISK_LIST[@]}"; do - CRED_FILE="" - cleanup_cred - - disk="${disk//$'\r'/}" - disk="$(echo "$disk" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')" - [[ -z "$disk" ]] && continue - - disk="$(echo "$disk" | sed 's,/$,,')" - disk="${disk//"\040"/ }" - - FSTYPE="cifs" - if [[ "$disk" =~ ^nfs:// ]]; then - FSTYPE="nfs" - disk="${disk#nfs://}" - elif [[ "$disk" =~ ^[^/:]+:/.+ ]]; then - FSTYPE="nfs" - fi - - if [[ "$FSTYPE" == "cifs" ]]; then - server="$(echo "$disk" | grep -E -o "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | head -n 1)" - else - server="${disk%%:*}" - fi - - diskname="$disk" - diskname="${diskname//\\//}" - diskname="${diskname##*/}" - - if mountpoint -q "/mnt/$diskname" 2>/dev/null; then - bashio::log.warning "...... mount point /mnt/$diskname already in use (name collision for $disk). Skipping this share." - continue - fi - - ERRORCODE_FILE="/tmp/mount_error_${diskname//[^a-zA-Z0-9._-]/_}.log" - : >"$ERRORCODE_FILE" || true - - MOUNTED=false - CIFS_LADDER_ATTEMPTED=false - SMBVERS_FORCE="" - SECVERS_FORCE="" SMBVERS="" SECVERS="" + CHARSET=",iocharset=utf8" - echo "... mounting ($FSTYPE) $disk" + MOREDISKS="${MOREDISKS//$'\r'/}" + MOREDISKS="${MOREDISKS//$'\n'/,}" + MOREDISKS="$(echo "$MOREDISKS" | sed -E 's/[[:space:]]*,[[:space:]]*/,/g; s/^[[:space:]]+//; s/[[:space:]]+$//')" - if [[ "$FSTYPE" == "cifs" ]]; then - if [[ ! "$disk" =~ ^//[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/.+ ]]; then - bashio::log.fatal "...... invalid CIFS path \"$disk\". Use //123.12.12.12/sharedfolder,//123.12.12.12/sharedfolder2" - echo "Invalid CIFS path structure: $disk" >"$ERRORCODE_FILE" || true - continue - fi - else - if [[ ! "$disk" =~ ^[^/:]+:/.+ ]]; then - bashio::log.fatal "...... invalid NFS path \"$disk\". Use server:/export/path or 123.12.12.12:/export/path" - echo "Invalid NFS path structure: $disk" >"$ERRORCODE_FILE" || true - continue - fi + DOMAINCLIENT="" + CIFSDOMAIN="" + if bashio::config.has_value 'cifsdomain'; then + CIFSDOMAIN="$(bashio::config 'cifsdomain')" + echo "... using domain $CIFSDOMAIN" + DOMAINCLIENT="--workgroup=$CIFSDOMAIN" fi - mkdir -p "/mnt/$diskname" - chown root:root "/mnt/$diskname" + PUID=",uid=$(id -u)" + PGID=",gid=$(id -g)" + if bashio::config.has_value 'PUID' && bashio::config.has_value 'PGID'; then + echo "... using PUID $(bashio::config 'PUID') and PGID $(bashio::config 'PGID')" + PUID=",uid=$(bashio::config 'PUID')" + PGID=",gid=$(bashio::config 'PGID')" + fi - if [[ "$FSTYPE" == "cifs" ]]; then - CRED_FILE="$(mktemp /tmp/cifs-cred.XXXXXX)" - chmod 600 "$CRED_FILE" - { - printf 'username=%s\n' "$USERNAME" - printf 'password=%s\n' "$PASSWORD" - if [[ -n "${CIFSDOMAIN:-}" ]]; then - printf 'domain=%s\n' "$CIFSDOMAIN" + IFS=',' read -r -a DISK_LIST <<< "$MOREDISKS" + + for disk in "${DISK_LIST[@]}"; do + CRED_FILE="" + cleanup_cred + + disk="${disk//$'\r'/}" + disk="$(echo "$disk" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')" + [[ -z "$disk" ]] && continue + + disk="$(echo "$disk" | sed 's,/$,,')" + disk="${disk//"\040"/ }" + + FSTYPE="cifs" + if [[ "$disk" =~ ^nfs:// ]]; then + FSTYPE="nfs" + disk="${disk#nfs://}" + elif [[ "$disk" =~ ^[^/:]+:/.+ ]]; then + FSTYPE="nfs" fi - } >"$CRED_FILE" - fi - if [[ "$FSTYPE" == "cifs" ]]; then - mount_drive "rw,file_mode=0775,dir_mode=0775,credentials=${CRED_FILE},nobrl,mfsymlinks${SMBVERS}${SECVERS}${PUID}${PGID}${CHARSET}" - if [[ "$MOUNTED" == "false" ]]; then - retry_cifs_with_vers_ladder_on_dialect_failure - fi - else - mount_drive "rw,nfsvers=4.2,proto=tcp,hard,timeo=600,retrans=2" - fi + if [[ "$FSTYPE" == "cifs" ]]; then + server="$(echo "$disk" | grep -E -o "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | head -n 1)" + else + server="${disk%%:*}" + fi - if [[ "$MOUNTED" == "false" ]]; then - if [[ "$FSTYPE" == "cifs" ]]; then - if command -v nmap >/dev/null 2>&1; then - output="$(nmap -F "$server" -T5 -oG - 2>/dev/null || true)" - if ! echo "$output" | grep -q "445/open"; then - if echo "$output" | grep -q "/open"; then - bashio::log.fatal "...... $server is reachable but SMB port not opened, stopping script" - else - bashio::log.fatal "...... fatal : $server not reachable, is it correct" - fi - cleanup_cred - rm -f "$ERRORCODE_FILE" 2>/dev/null || true + diskname="$disk" + diskname="${diskname//\\//}" + diskname="${diskname##*/}" + + if mountpoint -q "/mnt/$diskname" 2> /dev/null; then + bashio::log.warning "...... mount point /mnt/$diskname already in use (name collision for $disk). Skipping this share." continue - fi - echo "...... $server is confirmed reachable" - else - bashio::log.warning "...... nmap not available; skipping SMB port reachability test" fi - if command -v smbclient >/dev/null 2>&1; then - OUTPUT="$(smbclient -t 2 -L "$server" -U "$USERNAME%$PASSWORD" -c "exit" $DOMAINCLIENT 2>&1 || true)" - - if echo "$OUTPUT" | grep -q "LOGON_FAILURE"; then - bashio::log.fatal "...... incorrect Username, Password, or Domain! Script will stop." - cleanup_cred - rm -f "$ERRORCODE_FILE" 2>/dev/null || true - bashio::addon.stop - elif echo "$OUTPUT" | grep -q "tree connect failed" || echo "$OUTPUT" | grep -q "NT_STATUS_CONNECTION_DISCONNECTED"; then - echo "... using SMBv1" - bashio::log.warning "...... share reachable only with legacy SMBv1 (NT1) negotiation. Forcing SMBv1 options." - SMBVERS_FORCE=",vers=1.0" - SECVERS_FORCE=",sec=ntlm" - elif ! echo "$OUTPUT" | grep -q "Disk"; then - bashio::log.fatal "...... no shares found. Invalid or inaccessible SMB path?" - else - echo "...... credentials are valid" - fi - else - bashio::log.warning "...... smbclient not available; skipping SMB credential test" - fi - - SMBRAW="" - SMB1_DETECTED=false - if command -v nmap >/dev/null 2>&1; then - NMAP_OUTPUT="$(nmap --script smb-protocols -p 445 "$server" 2>/dev/null || true)" - SMBRAW="$( - echo "$NMAP_OUTPUT" \ - | awk '/SMB2_DIALECT_/ {print $NF}' \ - | sed 's/SMB2_DIALECT_//' \ - | tr -d '_' \ - | sort -V | tail -n 1 || true - )" - if [[ -z "$SMBRAW" ]] && echo "$NMAP_OUTPUT" | grep -Eiq 'NT LM 0\.12|SMBv1|NT1'; then - SMB1_DETECTED=true - fi - fi + ERRORCODE_FILE="/tmp/mount_error_${diskname//[^a-zA-Z0-9._-]/_}.log" + : > "$ERRORCODE_FILE" || true + MOUNTED=false + CIFS_LADDER_ATTEMPTED=false + SMBVERS_FORCE="" + SECVERS_FORCE="" SMBVERS="" - case "$SMBRAW" in - 311) SMBVERS=",vers=3.1.1" ;; - 302) SMBVERS=",vers=3.02" ;; - 300) SMBVERS=",vers=3.0" ;; - 210) SMBVERS=",vers=2.1" ;; - 202|200) SMBVERS=",vers=2.0" ;; - *) SMBVERS="" ;; - esac + SECVERS="" - if [[ -z "$SMBVERS" && "$SMB1_DETECTED" == "true" ]]; then - echo "...... SMB version detected via nmap : SMBv1 (NT LM 0.12)" - SMBVERS=",vers=1.0" - SECVERS=",sec=ntlm" - fi + echo "... mounting ($FSTYPE) $disk" - if [[ -n "$SMBVERS" ]]; then - echo "...... SMB version detected : ${SMBVERS#,vers=}" - elif command -v smbclient >/dev/null 2>&1 && smbclient -t 2 -L "$server" -m NT1 -U "$USERNAME%$PASSWORD" $DOMAINCLIENT -c "exit" &>/dev/null; then - echo "...... SMB version : only SMBv1 is supported, this can lead to issues" - SECVERS=",sec=ntlm" - SMBVERS=",vers=1.0" + if [[ "$FSTYPE" == "cifs" ]]; then + if [[ ! "$disk" =~ ^//[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/.+ ]]; then + bashio::log.fatal "...... invalid CIFS path \"$disk\". Use //123.12.12.12/sharedfolder,//123.12.12.12/sharedfolder2" + echo "Invalid CIFS path structure: $disk" > "$ERRORCODE_FILE" || true + continue + fi else - echo "...... SMB version : couldn't detect, falling back to SMB3->SMB2->SMB1 ladder on negotiation/dialect failure" - SMBVERS=",vers=3.1.1" + if [[ ! "$disk" =~ ^[^/:]+:/.+ ]]; then + bashio::log.fatal "...... invalid NFS path \"$disk\". Use server:/export/path or 123.12.12.12:/export/path" + echo "Invalid NFS path structure: $disk" > "$ERRORCODE_FILE" || true + continue + fi fi - if [[ -n "$SMBVERS_FORCE" ]]; then - if [[ -n "$SMBVERS" && "$SMBVERS" != "$SMBVERS_FORCE" ]]; then - bashio::log.warning "...... overriding detected SMB version ${SMBVERS#,vers=} with forced ${SMBVERS_FORCE#,vers=} (server requires legacy protocol)" - fi - SMBVERS="$SMBVERS_FORCE" - [[ -z "$SECVERS" ]] && SECVERS="$SECVERS_FORCE" + mkdir -p "/mnt/$diskname" + chown root:root "/mnt/$diskname" + + if [[ "$FSTYPE" == "cifs" ]]; then + CRED_FILE="$(mktemp /tmp/cifs-cred.XXXXXX)" + chmod 600 "$CRED_FILE" + { + printf 'username=%s\n' "$USERNAME" + printf 'password=%s\n' "$PASSWORD" + if [[ -n "${CIFSDOMAIN:-}" ]]; then + printf 'domain=%s\n' "$CIFSDOMAIN" + fi + } > "$CRED_FILE" fi - SECVERS_BASE="$SECVERS" - for SECTRY in "$SECVERS_BASE" ",sec=ntlmv2" ",sec=ntlmssp" ",sec=ntlmsspi" ",sec=krb5i" ",sec=krb5" ",sec=ntlm" ",sec=ntlmv2i"; do - if [[ "$MOUNTED" == "false" ]]; then - mount_drive "rw,file_mode=0775,dir_mode=0775,credentials=${CRED_FILE},nobrl,mfsymlinks${SMBVERS}${SECTRY}${PUID}${PGID}${CHARSET}" - fi - done + if [[ "$FSTYPE" == "cifs" ]]; then + mount_drive "rw,file_mode=0775,dir_mode=0775,credentials=${CRED_FILE},nobrl,mfsymlinks${SMBVERS}${SECVERS}${PUID}${PGID}${CHARSET}" + if [[ "$MOUNTED" == "false" ]]; then + retry_cifs_with_vers_ladder_on_dialect_failure + fi + else + mount_drive "rw,nfsvers=4.2,proto=tcp,hard,timeo=600,retrans=2" + fi if [[ "$MOUNTED" == "false" ]]; then - retry_cifs_with_vers_ladder_on_dialect_failure + if [[ "$FSTYPE" == "cifs" ]]; then + if command -v nmap > /dev/null 2>&1; then + output="$(nmap -F "$server" -T5 -oG - 2> /dev/null || true)" + if ! echo "$output" | grep -q "445/open"; then + if echo "$output" | grep -q "/open"; then + bashio::log.fatal "...... $server is reachable but SMB port not opened, stopping script" + else + bashio::log.fatal "...... fatal : $server not reachable, is it correct" + fi + cleanup_cred + rm -f "$ERRORCODE_FILE" 2> /dev/null || true + continue + fi + echo "...... $server is confirmed reachable" + else + bashio::log.warning "...... nmap not available; skipping SMB port reachability test" + fi + + if command -v smbclient > /dev/null 2>&1; then + OUTPUT="$(smbclient -t 2 -L "$server" -U "$USERNAME%$PASSWORD" -c "exit" $DOMAINCLIENT 2>&1 || true)" + + if echo "$OUTPUT" | grep -q "LOGON_FAILURE"; then + bashio::log.fatal "...... incorrect Username, Password, or Domain! Script will stop." + cleanup_cred + rm -f "$ERRORCODE_FILE" 2> /dev/null || true + bashio::addon.stop + elif echo "$OUTPUT" | grep -q "tree connect failed" || echo "$OUTPUT" | grep -q "NT_STATUS_CONNECTION_DISCONNECTED"; then + echo "... using SMBv1" + bashio::log.warning "...... share reachable only with legacy SMBv1 (NT1) negotiation. Forcing SMBv1 options." + SMBVERS_FORCE=",vers=1.0" + SECVERS_FORCE=",sec=ntlm" + elif ! echo "$OUTPUT" | grep -q "Disk"; then + bashio::log.fatal "...... no shares found. Invalid or inaccessible SMB path?" + else + echo "...... credentials are valid" + fi + else + bashio::log.warning "...... smbclient not available; skipping SMB credential test" + fi + + SMBRAW="" + SMB1_DETECTED=false + if command -v nmap > /dev/null 2>&1; then + NMAP_OUTPUT="$(nmap --script smb-protocols -p 445 "$server" 2> /dev/null || true)" + SMBRAW="$( + echo "$NMAP_OUTPUT" \ + | awk '/SMB2_DIALECT_/ {print $NF}' \ + | sed 's/SMB2_DIALECT_//' \ + | tr -d '_' \ + | sort -V | tail -n 1 || true + )" + if [[ -z "$SMBRAW" ]] && echo "$NMAP_OUTPUT" | grep -Eiq 'NT LM 0\.12|SMBv1|NT1'; then + SMB1_DETECTED=true + fi + fi + + SMBVERS="" + case "$SMBRAW" in + 311) SMBVERS=",vers=3.1.1" ;; + 302) SMBVERS=",vers=3.02" ;; + 300) SMBVERS=",vers=3.0" ;; + 210) SMBVERS=",vers=2.1" ;; + 202 | 200) SMBVERS=",vers=2.0" ;; + *) SMBVERS="" ;; + esac + + if [[ -z "$SMBVERS" && "$SMB1_DETECTED" == "true" ]]; then + echo "...... SMB version detected via nmap : SMBv1 (NT LM 0.12)" + SMBVERS=",vers=1.0" + SECVERS=",sec=ntlm" + fi + + if [[ -n "$SMBVERS" ]]; then + echo "...... SMB version detected : ${SMBVERS#,vers=}" + elif command -v smbclient > /dev/null 2>&1 && smbclient -t 2 -L "$server" -m NT1 -U "$USERNAME%$PASSWORD" $DOMAINCLIENT -c "exit" &> /dev/null; then + echo "...... SMB version : only SMBv1 is supported, this can lead to issues" + SECVERS=",sec=ntlm" + SMBVERS=",vers=1.0" + else + echo "...... SMB version : couldn't detect, falling back to SMB3->SMB2->SMB1 ladder on negotiation/dialect failure" + SMBVERS=",vers=3.1.1" + fi + + if [[ -n "$SMBVERS_FORCE" ]]; then + if [[ -n "$SMBVERS" && "$SMBVERS" != "$SMBVERS_FORCE" ]]; then + bashio::log.warning "...... overriding detected SMB version ${SMBVERS#,vers=} with forced ${SMBVERS_FORCE#,vers=} (server requires legacy protocol)" + fi + SMBVERS="$SMBVERS_FORCE" + [[ -z "$SECVERS" ]] && SECVERS="$SECVERS_FORCE" + fi + + SECVERS_BASE="$SECVERS" + for SECTRY in "$SECVERS_BASE" ",sec=ntlmv2" ",sec=ntlmssp" ",sec=ntlmsspi" ",sec=krb5i" ",sec=krb5" ",sec=ntlm" ",sec=ntlmv2i"; do + if [[ "$MOUNTED" == "false" ]]; then + mount_drive "rw,file_mode=0775,dir_mode=0775,credentials=${CRED_FILE},nobrl,mfsymlinks${SMBVERS}${SECTRY}${PUID}${PGID}${CHARSET}" + fi + done + + if [[ "$MOUNTED" == "false" ]]; then + retry_cifs_with_vers_ladder_on_dialect_failure + fi + + else + if command -v nmap > /dev/null 2>&1; then + output="$(nmap -F "$server" -T5 -oG - 2> /dev/null || true)" + if ! echo "$output" | grep -Eq '(2049|111)/open'; then + bashio::log.fatal "...... $server is reachable but NFS ports not open" + fi + else + bashio::log.warning "...... nmap not available; skipping NFS port reachability test" + fi + + for NFVER in 4.2 4.1 4 3; do + if [[ "$MOUNTED" == "false" ]]; then + mount_drive "rw,nfsvers=${NFVER},proto=tcp" + fi + done + fi fi - else - if command -v nmap >/dev/null 2>&1; then - output="$(nmap -F "$server" -T5 -oG - 2>/dev/null || true)" - if ! echo "$output" | grep -Eq '(2049|111)/open'; then - bashio::log.fatal "...... $server is reachable but NFS ports not open" - fi + if [[ "$MOUNTED" == "true" ]]; then + bashio::log.info "...... $disk successfully mounted to /mnt/$diskname with options ${MOUNTOPTIONS/$PASSWORD/XXXXXXXXXX}" + rm -f "$ERRORCODE_FILE" 2> /dev/null || true + + if [[ "$FSTYPE" == "cifs" && "$MOUNTOPTIONS" == *"vers=1.0"* ]]; then + bashio::log.warning "" + bashio::log.warning "Your SMB system requires SMBv1. This is an obsolete protocol. Please correct this to prevent issues." + bashio::log.warning "" + fi + + cleanup_cred + + elif [[ "$MOUNTED" == "readonly" ]]; then + bashio::log.warning "...... $disk mounted to /mnt/$diskname but is READ-ONLY or not writable by UID/GID ${PUID#,uid=}:${PGID#,gid=}." + bashio::log.warning "...... Check Samba share permissions, or try setting PUID/PGID to 0/0 (root), or adjust server ACLs." + rm -f "$ERRORCODE_FILE" 2> /dev/null || true + cleanup_cred + else - bashio::log.warning "...... nmap not available; skipping NFS port reachability test" + if [[ "$FSTYPE" == "cifs" ]]; then + bashio::log.fatal "Error, unable to mount $disk to /mnt/$diskname with username $USERNAME. Please check share path, username/password/domain; try UID/GID 0." + bashio::log.fatal "Here is some debugging info :" + if command -v smbclient > /dev/null 2>&1; then + smbclient -t 2 -L "$server" -U "$USERNAME%$PASSWORD" -c "exit" $DOMAINCLIENT || true + else + bashio::log.warning "smbclient not available; cannot print SMB debugging info" + fi + + mount_drive "rw,credentials=${CRED_FILE}${PUID}${PGID}" + if [[ "$MOUNTED" == "false" ]]; then + retry_cifs_with_vers_ladder_on_dialect_failure + fi + else + bashio::log.fatal "Error, unable to mount NFS share $disk to /mnt/$diskname. Please check export path and allowlist for this client." + mount_drive "rw" + fi + + ERR_READ="$(cat "$ERRORCODE_FILE" 2> /dev/null || true)" + bashio::log.fatal "Error read : ${ERR_READ:-unknown error}, addon will stop in 1 min" + + umount "/mnt/$diskname" 2> /dev/null || true + rmdir "/mnt/$diskname" 2> /dev/null || true + cleanup_cred + rm -f "$ERRORCODE_FILE" 2> /dev/null || true + + bashio::addon.stop fi - - for NFVER in 4.2 4.1 4 3; do - if [[ "$MOUNTED" == "false" ]]; then - mount_drive "rw,nfsvers=${NFVER},proto=tcp" - fi - done - fi - fi - - if [[ "$MOUNTED" == "true" ]]; then - bashio::log.info "...... $disk successfully mounted to /mnt/$diskname with options ${MOUNTOPTIONS/$PASSWORD/XXXXXXXXXX}" - rm -f "$ERRORCODE_FILE" 2>/dev/null || true - - if [[ "$FSTYPE" == "cifs" && "$MOUNTOPTIONS" == *"vers=1.0"* ]]; then - bashio::log.warning "" - bashio::log.warning "Your SMB system requires SMBv1. This is an obsolete protocol. Please correct this to prevent issues." - bashio::log.warning "" - fi - - cleanup_cred - - elif [[ "$MOUNTED" == "readonly" ]]; then - bashio::log.warning "...... $disk mounted to /mnt/$diskname but is READ-ONLY or not writable by UID/GID ${PUID#,uid=}:${PGID#,gid=}." - bashio::log.warning "...... Check Samba share permissions, or try setting PUID/PGID to 0/0 (root), or adjust server ACLs." - rm -f "$ERRORCODE_FILE" 2>/dev/null || true - cleanup_cred - - else - if [[ "$FSTYPE" == "cifs" ]]; then - bashio::log.fatal "Error, unable to mount $disk to /mnt/$diskname with username $USERNAME. Please check share path, username/password/domain; try UID/GID 0." - bashio::log.fatal "Here is some debugging info :" - if command -v smbclient >/dev/null 2>&1; then - smbclient -t 2 -L "$server" -U "$USERNAME%$PASSWORD" -c "exit" $DOMAINCLIENT || true - else - bashio::log.warning "smbclient not available; cannot print SMB debugging info" - fi - - mount_drive "rw,credentials=${CRED_FILE}${PUID}${PGID}" - if [[ "$MOUNTED" == "false" ]]; then - retry_cifs_with_vers_ladder_on_dialect_failure - fi - else - bashio::log.fatal "Error, unable to mount NFS share $disk to /mnt/$diskname. Please check export path and allowlist for this client." - mount_drive "rw" - fi - - ERR_READ="$(cat "$ERRORCODE_FILE" 2>/dev/null || true)" - bashio::log.fatal "Error read : ${ERR_READ:-unknown error}, addon will stop in 1 min" - - umount "/mnt/$diskname" 2>/dev/null || true - rmdir "/mnt/$diskname" 2>/dev/null || true - cleanup_cred - rm -f "$ERRORCODE_FILE" 2>/dev/null || true - - bashio::addon.stop - fi - done + done fi diff --git a/.templates/01-config_yaml.sh b/.templates/01-config_yaml.sh index c2ccbd6de5..b7182b8489 100755 --- a/.templates/01-config_yaml.sh +++ b/.templates/01-config_yaml.sh @@ -138,9 +138,9 @@ append_unique_line() { # $1=file, $2=line local _file="$1" local _line="$2" - mkdir -p "$(dirname "$_file")" 2>/dev/null || true - touch "$_file" 2>/dev/null || true - grep -qxF -- "$_line" "$_file" 2>/dev/null || echo "$_line" >> "$_file" + mkdir -p "$(dirname "$_file")" 2> /dev/null || true + touch "$_file" 2> /dev/null || true + grep -qxF -- "$_line" "$_file" 2> /dev/null || echo "$_line" >> "$_file" } while IFS= read -r line; do diff --git a/.templates/01-custom_script.sh b/.templates/01-custom_script.sh index 639f86604b..b1fbda32fc 100755 --- a/.templates/01-custom_script.sh +++ b/.templates/01-custom_script.sh @@ -7,27 +7,33 @@ set -e ########################################## pick_exec_dir() { - local d - for d in /dev/shm /run /var/run /mnt /root /; do - if [ -d "$d" ] && [ -w "$d" ]; then - local t="${d%/}/.exec_test_$$" - printf '#!/bin/sh\necho ok\n' >"$t" 2>/dev/null || { rm -f "$t" 2>/dev/null || true; continue; } - chmod 700 "$t" 2>/dev/null || { rm -f "$t" 2>/dev/null || true; continue; } - if "$t" >/dev/null 2>&1; then - rm -f "$t" 2>/dev/null || true - echo "$d" - return 0 - fi - rm -f "$t" 2>/dev/null || true - fi - done - return 1 + local d + for d in /dev/shm /run /var/run /mnt /root /; do + if [ -d "$d" ] && [ -w "$d" ]; then + local t="${d%/}/.exec_test_$$" + printf '#!/bin/sh\necho ok\n' > "$t" 2> /dev/null || { + rm -f "$t" 2> /dev/null || true + continue + } + chmod 700 "$t" 2> /dev/null || { + rm -f "$t" 2> /dev/null || true + continue + } + if "$t" > /dev/null 2>&1; then + rm -f "$t" 2> /dev/null || true + echo "$d" + return 0 + fi + rm -f "$t" 2> /dev/null || true + fi + done + return 1 } EXEC_DIR="$(pick_exec_dir || true)" if [ -z "${EXEC_DIR:-}" ]; then - echo "ERROR: Could not find an exec-capable writable directory." - exit 1 + echo "ERROR: Could not find an exec-capable writable directory." + exit 1 fi ###################### @@ -35,14 +41,14 @@ fi ###################### candidate_shebangs=( - "/command/with-contenv bashio" - "/usr/bin/with-contenv bashio" - "/usr/bin/env bashio" - "/usr/bin/bashio" - "/usr/bin/bash" - "/bin/bash" - "/usr/bin/sh" - "/bin/sh" + "/command/with-contenv bashio" + "/usr/bin/with-contenv bashio" + "/usr/bin/env bashio" + "/usr/bin/bashio" + "/usr/bin/bash" + "/bin/bash" + "/usr/bin/sh" + "/bin/sh" ) SHEBANG_ERRORS=() @@ -85,76 +91,76 @@ echo "${_bv:-PROBE_OK}" ' validate_shebang() { - local candidate="$1" - local tmp out rc - local errfile msg + local candidate="$1" + local tmp out rc + local errfile msg - # shellcheck disable=SC2206 - local cmd=( $candidate ) - local exe="${cmd[0]}" + # shellcheck disable=SC2206 + local cmd=($candidate) + local exe="${cmd[0]}" - if [ ! -x "$exe" ]; then - SHEBANG_ERRORS+=(" - FAIL (not executable): #!$candidate") + if [ ! -x "$exe" ]; then + SHEBANG_ERRORS+=(" - FAIL (not executable): #!$candidate") + return 1 + fi + + tmp="${EXEC_DIR%/}/shebang_test.$$.$RANDOM" + errfile="${EXEC_DIR%/}/shebang_probe_err.$$" + { + printf '#!%s\n' "$candidate" + printf '%s\n' "$probe_script_content" + } > "$tmp" + chmod 700 "$tmp" 2> /dev/null || true + + set +e + out="$("$tmp" 2> "$errfile")" + rc=$? + set -e + + rm -f "$tmp" 2> /dev/null || true + + if [ "$rc" -eq 0 ] && [ -n "${out:-}" ] && [ "$out" != "null" ]; then + rm -f "$errfile" 2> /dev/null || true + return 0 + fi + + msg=$' - FAIL: #!'"$candidate"$'\n'" rc=$rc, stdout='${out:-}'"$'\n' + if [ -s "$errfile" ]; then + msg+=$' stderr:\n' + msg+="$(sed -n '1,8p' "$errfile")"$'\n' + else + msg+=$' stderr: \n' + fi + SHEBANG_ERRORS+=("$msg") + rm -f "$errfile" 2> /dev/null || true return 1 - fi - - tmp="${EXEC_DIR%/}/shebang_test.$$.$RANDOM" - errfile="${EXEC_DIR%/}/shebang_probe_err.$$" - { - printf '#!%s\n' "$candidate" - printf '%s\n' "$probe_script_content" - } >"$tmp" - chmod 700 "$tmp" 2>/dev/null || true - - set +e - out="$("$tmp" 2>"$errfile")" - rc=$? - set -e - - rm -f "$tmp" 2>/dev/null || true - - if [ "$rc" -eq 0 ] && [ -n "${out:-}" ] && [ "$out" != "null" ]; then - rm -f "$errfile" 2>/dev/null || true - return 0 - fi - - msg=$' - FAIL: #!'"$candidate"$'\n'" rc=$rc, stdout='${out:-}'"$'\n' - if [ -s "$errfile" ]; then - msg+=$' stderr:\n' - msg+="$(sed -n '1,8p' "$errfile")"$'\n' - else - msg+=$' stderr: \n' - fi - SHEBANG_ERRORS+=("$msg") - rm -f "$errfile" 2>/dev/null || true - return 1 } shebang="" for candidate in "${candidate_shebangs[@]}"; do - if validate_shebang "$candidate"; then - shebang="$candidate" - break - fi + if validate_shebang "$candidate"; then + shebang="$candidate" + break + fi done if [ -z "$shebang" ]; then - echo "ERROR: No valid shebang found." >&2 - printf ' - %s\n' "${candidate_shebangs[@]}" >&2 - if [ "${#SHEBANG_ERRORS[@]}" -gt 0 ]; then - printf '%s\n' "${SHEBANG_ERRORS[@]}" >&2 - fi - exit 1 + echo "ERROR: No valid shebang found." >&2 + printf ' - %s\n' "${candidate_shebangs[@]}" >&2 + if [ "${#SHEBANG_ERRORS[@]}" -gt 0 ]; then + printf '%s\n' "${SHEBANG_ERRORS[@]}" >&2 + fi + exit 1 fi -if ! command -v bashio::addon.version >/dev/null 2>&1; then - for f in /usr/lib/bashio/bashio.sh /usr/lib/bashio/lib.sh /usr/src/bashio/bashio.sh /usr/local/lib/bashio/bashio.sh /usr/local/lib/bashio-standalone.sh; do - if [ -f "$f" ]; then - # shellcheck disable=SC1090 - . "$f" - break - fi - done +if ! command -v bashio::addon.version > /dev/null 2>&1; then + for f in /usr/lib/bashio/bashio.sh /usr/lib/bashio/lib.sh /usr/src/bashio/bashio.sh /usr/local/lib/bashio/bashio.sh /usr/local/lib/bashio-standalone.sh; do + if [ -f "$f" ]; then + # shellcheck disable=SC1090 + . "$f" + break + fi + done fi ################## @@ -162,9 +168,9 @@ fi ################## # Exit if /config is not mounted or HA not used -if [ ! -d /config ] || ! bashio::supervisor.ping 2>/dev/null; then - echo "..." - exit 0 +if [ ! -d /config ] || ! bashio::supervisor.ping 2> /dev/null; then + echo "..." + exit 0 fi # Define slug @@ -173,11 +179,11 @@ slug="${slug#*_}" # Check type of config folder if [ ! -f /config/configuration.yaml ] && [ ! -f /config/configuration.json ]; then - CONFIGLOCATION="/config" - CONFIGFILEBROWSER="/addon_configs/${HOSTNAME/-/_}/$slug.sh" + CONFIGLOCATION="/config" + CONFIGFILEBROWSER="/addon_configs/${HOSTNAME/-/_}/$slug.sh" else - CONFIGLOCATION="/config/addons_autoscripts" - CONFIGFILEBROWSER="/homeassistant/addons_autoscripts/$slug.sh" + CONFIGLOCATION="/config/addons_autoscripts" + CONFIGFILEBROWSER="/homeassistant/addons_autoscripts/$slug.sh" fi # Default location @@ -189,28 +195,28 @@ bashio::log.green "Execute $CONFIGFILEBROWSER if existing" # Download template if no script found and exit if [ ! -f "$CONFIGSOURCE" ]; then - TEMPLATESOURCE="https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/script.template" - curl -f -L -s -S "$TEMPLATESOURCE" --output "$CONFIGSOURCE" || true - exit 0 + TEMPLATESOURCE="https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/script.template" + curl -f -L -s -S "$TEMPLATESOURCE" --output "$CONFIGSOURCE" || true + exit 0 fi # Convert scripts to linux -dos2unix "$CONFIGSOURCE" >/dev/null 2>&1 || true +dos2unix "$CONFIGSOURCE" > /dev/null 2>&1 || true chmod +x "$CONFIGSOURCE" if grep -q 'bashio' "$CONFIGSOURCE"; then - sed -i "1s|^.*|#!$shebang|" "$CONFIGSOURCE" + sed -i "1s|^.*|#!$shebang|" "$CONFIGSOURCE" else - sed -i '1s|^.*|#!/bin/bash|' "$CONFIGSOURCE" + sed -i '1s|^.*|#!/bin/bash|' "$CONFIGSOURCE" fi # Check if there is actual commands while IFS= read -r line; do - line="$(echo "$line" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + line="$(echo "$line" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" - if [[ -n "$line" ]] && [[ ! "$line" =~ ^# ]]; then - bashio::log.green "... script found, executing" - "$CONFIGSOURCE" - break - fi + if [[ -n "$line" ]] && [[ ! "$line" =~ ^# ]]; then + bashio::log.green "... script found, executing" + "$CONFIGSOURCE" + break + fi done < "$CONFIGSOURCE" diff --git a/.templates/90-dns_set.sh b/.templates/90-dns_set.sh index e75afe87f4..6ae50eb459 100755 --- a/.templates/90-dns_set.sh +++ b/.templates/90-dns_set.sh @@ -9,12 +9,12 @@ set -e # Avoid usage of local dns such as adguard home or pihole\n" if bashio::config.has_value 'DNS_server'; then - if ! bashio::config.true "openvpn_enabled" && ! bashio::config.true "wireguard_enabled"; then + if ! bashio::config.true "openvpn_enabled" && ! bashio::config.true "wireguard_enabled"; then # Define variables DNSSERVER=$(bashio::config 'DNS_server') DNS="" DNSLIST="" - + # Get DNS servers # shellcheck disable=SC2086 for server in ${DNSSERVER//,/ }; do # Separate comma separated values @@ -26,7 +26,7 @@ if bashio::config.has_value 'DNS_server'; then bashio::log.warning "DNS $server was requested but can't be pinged. It won't be used" fi done - + # Only add DNS if there are DNS set # shellcheck disable=SC2236 if [[ -n "${DNS:-}" ]]; then diff --git a/.templates/bashio-standalone.sh b/.templates/bashio-standalone.sh index 5489976a98..b9da4f1c73 100755 --- a/.templates/bashio-standalone.sh +++ b/.templates/bashio-standalone.sh @@ -33,293 +33,297 @@ _BASHIO_COLOR=1 [ "${TERM:-}" = "dumb" ] && _BASHIO_COLOR=0 _bashio_color() { - [ "$_BASHIO_COLOR" = "1" ] || return 0 - case "${1:-}" in - blue) printf '\033[34m' ;; - green) printf '\033[32m' ;; - yellow) printf '\033[33m' ;; - red) printf '\033[31m' ;; - magenta) printf '\033[35m' ;; - reset) printf '\033[0m' ;; - *) printf '' ;; - esac + [ "$_BASHIO_COLOR" = "1" ] || return 0 + case "${1:-}" in + blue) printf '\033[34m' ;; + green) printf '\033[32m' ;; + yellow) printf '\033[33m' ;; + red) printf '\033[31m' ;; + magenta) printf '\033[35m' ;; + reset) printf '\033[0m' ;; + *) printf '' ;; + esac } _bashio_log() { - local c="${1:-}"; shift || true - printf '%s%s%s\n' "$(_bashio_color "$c")" "$*" "$(_bashio_color reset)" + local c="${1:-}" + shift || true + printf '%s%s%s\n' "$(_bashio_color "$c")" "$*" "$(_bashio_color reset)" } # ----------------------------------------------------------------------------- # Helpers # ----------------------------------------------------------------------------- _bashio_is_true() { - case "${1:-}" in - 1|true|TRUE|True|yes|YES|Yes|on|ON|On) return 0 ;; - *) return 1 ;; - esac + case "${1:-}" in + 1 | true | TRUE | True | yes | YES | Yes | on | ON | On) return 0 ;; + *) return 1 ;; + esac } # ENV mapping helper: # tries variants + prefixes and prints the value if env var is defined (even empty), # returning 0 when found, 1 when not found. _bashio_env_get() { - local key="${1:-}" - [ -n "$key" ] || return 1 + local key="${1:-}" + [ -n "$key" ] || return 1 - local norm norm_uc raw_uc - norm="$(printf '%s' "$key" | tr '.-' '__')" - norm_uc="$(printf '%s' "$norm" | tr '[:lower:]' '[:upper:]')" - raw_uc="$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')" + local norm norm_uc raw_uc + norm="$(printf '%s' "$key" | tr '.-' '__')" + norm_uc="$(printf '%s' "$norm" | tr '[:lower:]' '[:upper:]')" + raw_uc="$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')" - local variants=( - "$key" - "$raw_uc" - "$norm" - "$norm_uc" - ) + local variants=( + "$key" + "$raw_uc" + "$norm" + "$norm_uc" + ) - local prefixes=("" "CFG_" "CONFIG_" "ADDON_" "OPTION_" "OPT_") + local prefixes=("" "CFG_" "CONFIG_" "ADDON_" "OPTION_" "OPT_") - local v p name - for v in "${variants[@]}"; do - for p in "${prefixes[@]}"; do - name="${p}${v}" - if [ -n "${!name+x}" ]; then - printf '%s' "${!name}" - return 0 - fi + local v p name + for v in "${variants[@]}"; do + for p in "${prefixes[@]}"; do + name="${p}${v}" + if [ -n "${!name+x}" ]; then + printf '%s' "${!name}" + return 0 + fi + done done - done - return 1 + return 1 } # env presence (even if empty) used by config.exists _bashio_env_has() { - local key="${1:-}" - [ -n "$key" ] || return 1 - _bashio_env_get "$key" >/dev/null 2>&1 + local key="${1:-}" + [ -n "$key" ] || return 1 + _bashio_env_get "$key" > /dev/null 2>&1 } # JSON options source (jq required). Prints value or empty; returns 0 always. _bashio_json_get() { - local key="${1:-}" - local file="${STANDALONE_OPTIONS_JSON:-}" + local key="${1:-}" + local file="${STANDALONE_OPTIONS_JSON:-}" - [ -n "$key" ] || return 0 - [ -n "$file" ] || return 0 - [ -f "$file" ] || return 0 - command -v jq >/dev/null 2>&1 || return 0 + [ -n "$key" ] || return 0 + [ -n "$file" ] || return 0 + [ -f "$file" ] || return 0 + command -v jq > /dev/null 2>&1 || return 0 - # getpath(split(".")) supports nested access; missing => empty - jq -er --arg k "$key" 'getpath(($k|split("."))) // empty' "$file" 2>/dev/null || true + # getpath(split(".")) supports nested access; missing => empty + jq -er --arg k "$key" 'getpath(($k|split("."))) // empty' "$file" 2> /dev/null || true } # Net wait using /dev/tcp with a timeout _bashio_tcp_wait() { - local host="${1:-}" port="${2:-}" to="${3:-30}" - [ -n "$host" ] && [ -n "$port" ] || return 1 + local host="${1:-}" port="${2:-}" to="${3:-30}" + [ -n "$host" ] && [ -n "$port" ] || return 1 - local start now - start="$(date +%s)" - while :; do - if exec 3<>"/dev/tcp/${host}/${port}" 2>/dev/null; then - exec 3>&- 3<&- - return 0 - fi - now="$(date +%s)" - if [ $((now - start)) -ge "$to" ]; then - return 1 - fi - sleep 1 - done + local start now + start="$(date +%s)" + while :; do + if exec 3<> "/dev/tcp/${host}/${port}" 2> /dev/null; then + exec 3>&- 3<&- + return 0 + fi + now="$(date +%s)" + if [ $((now - start)) -ge "$to" ]; then + return 1 + fi + sleep 1 + done } # Prefer nc if present, fallback to /dev/tcp _bashio_tcp_wait_nc() { - command -v nc >/dev/null 2>&1 || return 1 - local host="${1:-}" port="${2:-}" to="${3:-30}" - # BusyBox and OpenBSD nc differ; cover both styles - nc -z -w "$to" "$host" "$port" 2>/dev/null || nc -z "$host" "$port" 2>/dev/null + command -v nc > /dev/null 2>&1 || return 1 + local host="${1:-}" port="${2:-}" to="${3:-30}" + # BusyBox and OpenBSD nc differ; cover both styles + nc -z -w "$to" "$host" "$port" 2> /dev/null || nc -z "$host" "$port" 2> /dev/null } # ----------------------------------------------------------------------------- # Logging API # ----------------------------------------------------------------------------- -bashio::log.blue() { _bashio_log blue "$*"; } -bashio::log.green() { _bashio_log green "$*"; } -bashio::log.yellow() { _bashio_log yellow "$*"; } -bashio::log.red() { _bashio_log red "$*"; } +bashio::log.blue() { _bashio_log blue "$*"; } +bashio::log.green() { _bashio_log green "$*"; } +bashio::log.yellow() { _bashio_log yellow "$*"; } +bashio::log.red() { _bashio_log red "$*"; } bashio::log.magenta() { _bashio_log magenta "$*"; } # Common aliases -bashio::log.info() { bashio::log.blue "$@"; } +bashio::log.info() { bashio::log.blue "$@"; } bashio::log.warning() { bashio::log.yellow "$@"; } -bashio::log.error() { bashio::log.red "$@"; } -bashio::log.debug() { printf '%s\n' "$*"; } +bashio::log.error() { bashio::log.red "$@"; } +bashio::log.debug() { printf '%s\n' "$*"; } # ----------------------------------------------------------------------------- # Supervisor shim # ----------------------------------------------------------------------------- bashio::supervisor.ping() { - _bashio_is_true "${STANDALONE_FORCE_SUPERVISOR_PING:-}" && return 0 - return 1 + _bashio_is_true "${STANDALONE_FORCE_SUPERVISOR_PING:-}" && return 0 + return 1 } # ----------------------------------------------------------------------------- # Add-on metadata # ----------------------------------------------------------------------------- -bashio::addon.name() { printf '%s' "${ADDON_NAME:-Standalone container}"; } -bashio::addon.description() { printf '%s' "${ADDON_DESCRIPTION:-Running without Home Assistant Supervisor}"; } -bashio::addon.version() { printf '%s' "${BUILD_VERSION:-1.0}"; } -bashio::addon.version_latest(){ printf '%s' "${ADDON_VERSION_LATEST:-${BUILD_VERSION:-1.0}}"; } +bashio::addon.name() { printf '%s' "${ADDON_NAME:-Standalone container}"; } +bashio::addon.description() { printf '%s' "${ADDON_DESCRIPTION:-Running without Home Assistant Supervisor}"; } +bashio::addon.version() { printf '%s' "${BUILD_VERSION:-1.0}"; } +bashio::addon.version_latest() { printf '%s' "${ADDON_VERSION_LATEST:-${BUILD_VERSION:-1.0}}"; } bashio::addon.update_available() { - if [ -n "${ADDON_VERSION_LATEST:-}" ] && [ "${ADDON_VERSION_LATEST:-}" != "${BUILD_VERSION:-}" ]; then - printf '%s' "true" - else - printf '%s' "false" - fi + if [ -n "${ADDON_VERSION_LATEST:-}" ] && [ "${ADDON_VERSION_LATEST:-}" != "${BUILD_VERSION:-}" ]; then + printf '%s' "true" + else + printf '%s' "false" + fi } -bashio::addon.ingress_port() { printf '%s' "${ADDON_INGRESS_PORT:-}"; } +bashio::addon.ingress_port() { printf '%s' "${ADDON_INGRESS_PORT:-}"; } bashio::addon.ingress_entry() { printf '%s' "${ADDON_INGRESS_ENTRY:-}"; } -bashio::addon.ip_address() { printf '%s' "${ADDON_IP_ADDRESS:-}"; } +bashio::addon.ip_address() { printf '%s' "${ADDON_IP_ADDRESS:-}"; } # Ports: # - numeric arg "8080" -> env PORT_8080 or ADDON_PORT_8080, fallback to the number # - non-numeric "WEB_PORT" -> resolve as config/env key bashio::addon.port() { - local arg="${1:-}" - if [[ "$arg" =~ ^[0-9]+$ ]]; then - local v="" - v="$(_bashio_env_get "PORT_${arg}" 2>/dev/null || true)" - [ -z "$v" ] && v="$(_bashio_env_get "ADDON_PORT_${arg}" 2>/dev/null || true)" - printf '%s' "${v:-$arg}" - else - printf '%s' "$(_bashio_env_get "$arg" 2>/dev/null || true)" - fi + local arg="${1:-}" + if [[ "$arg" =~ ^[0-9]+$ ]]; then + local v="" + v="$(_bashio_env_get "PORT_${arg}" 2> /dev/null || true)" + [ -z "$v" ] && v="$(_bashio_env_get "ADDON_PORT_${arg}" 2> /dev/null || true)" + printf '%s' "${v:-$arg}" + else + printf '%s' "$(_bashio_env_get "$arg" 2> /dev/null || true)" + fi } # addon.option : write/delete option in JSON when possible; fallback export env bashio::addon.option() { - local key="${1:-}" value="${2-__BASHIO_UNSET__}" file="${STANDALONE_OPTIONS_JSON:-}" - [ -n "$key" ] || return 0 + local key="${1:-}" value="${2-__BASHIO_UNSET__}" file="${STANDALONE_OPTIONS_JSON:-}" + [ -n "$key" ] || return 0 - if [ -n "$file" ] && [ -f "$file" ] && command -v jq >/dev/null 2>&1; then - local tmp - tmp="$(mktemp)" - if [ "$value" = "__BASHIO_UNSET__" ]; then - jq --arg k "$key" 'delpath(($k|split(".")))' "$file" >"$tmp" && mv "$tmp" "$file" - else - jq --arg k "$key" --arg v "$value" 'setpath(($k|split(".")); $v)' "$file" >"$tmp" && mv "$tmp" "$file" + if [ -n "$file" ] && [ -f "$file" ] && command -v jq > /dev/null 2>&1; then + local tmp + tmp="$(mktemp)" + if [ "$value" = "__BASHIO_UNSET__" ]; then + jq --arg k "$key" 'delpath(($k|split(".")))' "$file" > "$tmp" && mv "$tmp" "$file" + else + jq --arg k "$key" --arg v "$value" 'setpath(($k|split(".")); $v)' "$file" > "$tmp" && mv "$tmp" "$file" + fi + return 0 fi - return 0 - fi - # Fallback: export as env (dot/dash -> underscore). Delete becomes no-op. - if [ "$value" != "__BASHIO_UNSET__" ]; then - export "$(printf '%s' "$key" | tr '.-' '__')"="$value" - fi + # Fallback: export as env (dot/dash -> underscore). Delete becomes no-op. + if [ "$value" != "__BASHIO_UNSET__" ]; then + export "$(printf '%s' "$key" | tr '.-' '__')"="$value" + fi } # ----------------------------------------------------------------------------- # System info # ----------------------------------------------------------------------------- bashio::info.operating_system() { - if [ -r /etc/os-release ]; then - # shellcheck disable=SC1091 - . /etc/os-release - printf '%s' "${PRETTY_NAME:-${NAME:-Linux}}" - else - printf '%s' "Linux" - fi + if [ -r /etc/os-release ]; then + # shellcheck disable=SC1091 + . /etc/os-release + printf '%s' "${PRETTY_NAME:-${NAME:-Linux}}" + else + printf '%s' "Linux" + fi } -bashio::info.arch() { uname -m; } -bashio::info.machine() { uname -m; } -bashio::info.homeassistant(){ printf '%s' "standalone"; } -bashio::info.supervisor() { printf '%s' "standalone"; } +bashio::info.arch() { uname -m; } +bashio::info.machine() { uname -m; } +bashio::info.homeassistant() { printf '%s' "standalone"; } +bashio::info.supervisor() { printf '%s' "standalone"; } # ----------------------------------------------------------------------------- # Config API # ----------------------------------------------------------------------------- bashio::config() { - local key="${1:-}" - [ -n "$key" ] || { printf '%s' ""; return 0; } + local key="${1:-}" + [ -n "$key" ] || { + printf '%s' "" + return 0 + } - local v="" - if _bashio_env_get "$key" >/dev/null 2>&1; then - v="$(_bashio_env_get "$key" 2>/dev/null || true)" - fi - [ -z "$v" ] && v="$(_bashio_json_get "$key")" - printf '%s' "${v:-}" + local v="" + if _bashio_env_get "$key" > /dev/null 2>&1; then + v="$(_bashio_env_get "$key" 2> /dev/null || true)" + fi + [ -z "$v" ] && v="$(_bashio_json_get "$key")" + printf '%s' "${v:-}" } bashio::config.has_value() { [ -n "$(bashio::config "$1")" ]; } bashio::config.true() { - _bashio_is_true "$(bashio::config "$1")" + _bashio_is_true "$(bashio::config "$1")" } # config.exists : key is present (env or JSON), even if value is empty bashio::config.exists() { - local key="${1:-}" file="${STANDALONE_OPTIONS_JSON:-}" - [ -n "$key" ] || return 1 + local key="${1:-}" file="${STANDALONE_OPTIONS_JSON:-}" + [ -n "$key" ] || return 1 - if _bashio_env_has "$key"; then - return 0 - fi + if _bashio_env_has "$key"; then + return 0 + fi - if [ -n "$file" ] && [ -f "$file" ] && command -v jq >/dev/null 2>&1; then - jq -e --arg k "$key" 'haspath(($k|split(".")))' "$file" >/dev/null 2>&1 - return $? - fi + if [ -n "$file" ] && [ -f "$file" ] && command -v jq > /dev/null 2>&1; then + jq -e --arg k "$key" 'haspath(($k|split(".")))' "$file" > /dev/null 2>&1 + return $? + fi - return 1 + return 1 } # Common "require.*" shims (advisory/no-op in standalone) -bashio::config.require.ssl() { printf '%s' "${REQUIRE_SSL:-true}"; } +bashio::config.require.ssl() { printf '%s' "${REQUIRE_SSL:-true}"; } bashio::config.require.username() { :; } bashio::config.require.password() { :; } -bashio::config.require.port() { :; } +bashio::config.require.port() { :; } # config.array: # Accepts CSV ("a,b,c"), space/newline-separated text, or JSON array ["a","b"]. # Prints one item per line. bashio::config.array() { - local key="${1:-}" raw - raw="$(bashio::config "$key")" - [ -n "$raw" ] || return 0 + local key="${1:-}" raw + raw="$(bashio::config "$key")" + [ -n "$raw" ] || return 0 - if command -v jq >/dev/null 2>&1 && printf '%s' "$raw" | jq -e . >/dev/null 2>&1; then - printf '%s' "$raw" | jq -r '.[]' 2>/dev/null && return 0 - fi + if command -v jq > /dev/null 2>&1 && printf '%s' "$raw" | jq -e . > /dev/null 2>&1; then + printf '%s' "$raw" | jq -r '.[]' 2> /dev/null && return 0 + fi - if printf '%s' "$raw" | grep -q ','; then - printf '%s' "$raw" | tr ',' '\n' - return 0 - fi + if printf '%s' "$raw" | grep -q ','; then + printf '%s' "$raw" | tr ',' '\n' + return 0 + fi - printf '%s\n' "$raw" + printf '%s\n' "$raw" } # ----------------------------------------------------------------------------- # var helpers # ----------------------------------------------------------------------------- -bashio::var.true() { _bashio_is_true "${1:-}"; } -bashio::var.false() { ! _bashio_is_true "${1:-}"; } +bashio::var.true() { _bashio_is_true "${1:-}"; } +bashio::var.false() { ! _bashio_is_true "${1:-}"; } bashio::var.has_value() { [ -n "${1:-}" ]; } # ----------------------------------------------------------------------------- # Filesystem helpers # ----------------------------------------------------------------------------- -bashio::fs.file_exists() { [ -f "${1:-}" ]; } +bashio::fs.file_exists() { [ -f "${1:-}" ]; } bashio::fs.directory_exists() { [ -d "${1:-}" ]; } bashio::fs.file_contains() { - local f="${1:-}" p="${2:-}" - [ -f "$f" ] && grep -q -- "$p" "$f" 2>/dev/null + local f="${1:-}" p="${2:-}" + [ -f "$f" ] && grep -q -- "$p" "$f" 2> /dev/null } # ----------------------------------------------------------------------------- @@ -327,25 +331,25 @@ bashio::fs.file_contains() { # ----------------------------------------------------------------------------- # Wait for TCP service: bashio::net.wait_for host port [timeout] bashio::net.wait_for() { - local host="${1:-}" port="${2:-}" to="${3:-30}" - _bashio_tcp_wait_nc "$host" "$port" "$to" && return 0 - _bashio_tcp_wait "$host" "$port" "$to" + local host="${1:-}" port="${2:-}" to="${3:-30}" + _bashio_tcp_wait_nc "$host" "$port" "$to" && return 0 + _bashio_tcp_wait "$host" "$port" "$to" } # DNS helper: bashio::dns.host -> prints an IP (or empty) bashio::dns.host() { - local h="${1:-}" - [ -n "$h" ] || return 1 - if command -v getent >/dev/null 2>&1; then - getent ahostsv4 "$h" | awk '{print $1; exit}' - else - nslookup "$h" 2>/dev/null | awk '/^Address: /{print $2; exit}' - fi + local h="${1:-}" + [ -n "$h" ] || return 1 + if command -v getent > /dev/null 2>&1; then + getent ahostsv4 "$h" | awk '{print $1; exit}' + else + nslookup "$h" 2> /dev/null | awk '/^Address: /{print $2; exit}' + fi } # Hostname bashio::host.hostname() { - command -v hostname >/dev/null 2>&1 && hostname || printf '%s' "${HOSTNAME:-unknown}" + command -v hostname > /dev/null 2>&1 && hostname || printf '%s' "${HOSTNAME:-unknown}" } # ----------------------------------------------------------------------------- @@ -355,40 +359,43 @@ bashio::host.hostname() { # bashio::services "mqtt" "host" # bashio::services.available "mqtt" bashio::services() { - local svc="${1:-}" key="${2:-}" - [ -n "$svc" ] && [ -n "$key" ] || { printf '%s' ""; return 0; } + local svc="${1:-}" key="${2:-}" + [ -n "$svc" ] && [ -n "$key" ] || { + printf '%s' "" + return 0 + } - local upper svc_upper var v="" - upper="$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')" - svc_upper="$(printf '%s' "$svc" | tr '[:lower:]' '[:upper:]')" + local upper svc_upper var v="" + upper="$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')" + svc_upper="$(printf '%s' "$svc" | tr '[:lower:]' '[:upper:]')" - # Common mappings - case "$svc_upper:$upper" in - MQTT:HOST) var="MQTT_HOST" ;; - MQTT:PORT) var="MQTT_PORT" ;; - MQTT:USERNAME) var="MQTT_USER" ;; - MQTT:PASSWORD) var="MQTT_PASSWORD" ;; - MQTT:TLS) var="MQTT_TLS" ;; - MYSQL:HOST|MARIADB:HOST) var="DB_HOST" ;; - MYSQL:PORT|MARIADB:PORT) var="DB_PORT" ;; - MYSQL:USERNAME|MARIADB:USERNAME) var="DB_USER" ;; - MYSQL:PASSWORD|MARIADB:PASSWORD) var="DB_PASSWORD" ;; - MYSQL:DATABASE|MARIADB:DATABASE) var="DB_NAME" ;; - *) var="${svc_upper}_${upper}" ;; - esac + # Common mappings + case "$svc_upper:$upper" in + MQTT:HOST) var="MQTT_HOST" ;; + MQTT:PORT) var="MQTT_PORT" ;; + MQTT:USERNAME) var="MQTT_USER" ;; + MQTT:PASSWORD) var="MQTT_PASSWORD" ;; + MQTT:TLS) var="MQTT_TLS" ;; + MYSQL:HOST | MARIADB:HOST) var="DB_HOST" ;; + MYSQL:PORT | MARIADB:PORT) var="DB_PORT" ;; + MYSQL:USERNAME | MARIADB:USERNAME) var="DB_USER" ;; + MYSQL:PASSWORD | MARIADB:PASSWORD) var="DB_PASSWORD" ;; + MYSQL:DATABASE | MARIADB:DATABASE) var="DB_NAME" ;; + *) var="${svc_upper}_${upper}" ;; + esac - v="$(_bashio_env_get "$var" 2>/dev/null || true)" - if [ -z "$v" ]; then - v="$(_bashio_json_get "services.${svc}.${key}")" - [ -z "$v" ] && v="$(_bashio_json_get "${svc}.${key}")" - fi - printf '%s' "${v:-}" + v="$(_bashio_env_get "$var" 2> /dev/null || true)" + if [ -z "$v" ]; then + v="$(_bashio_json_get "services.${svc}.${key}")" + [ -z "$v" ] && v="$(_bashio_json_get "${svc}.${key}")" + fi + printf '%s' "${v:-}" } bashio::services.available() { - local svc="${1:-}" host - host="$(bashio::services "$svc" "host")" - [ -n "$host" ] + local svc="${1:-}" host + host="$(bashio::services "$svc" "host")" + [ -n "$host" ] } # ----------------------------------------------------------------------------- @@ -396,39 +403,43 @@ bashio::services.available() { # ----------------------------------------------------------------------------- mkdir -p "$BASHIO_CACHE_DIR" bashio::cache.exists() { [ -f "$BASHIO_CACHE_DIR/${1}.cache" ]; } -bashio::cache.get() { [ -f "$BASHIO_CACHE_DIR/${1}.cache" ] && cat "$BASHIO_CACHE_DIR/${1}.cache"; } -bashio::cache.set() { printf '%s' "${2:-}" > "$BASHIO_CACHE_DIR/${1}.cache"; } +bashio::cache.get() { [ -f "$BASHIO_CACHE_DIR/${1}.cache" ] && cat "$BASHIO_CACHE_DIR/${1}.cache"; } +bashio::cache.set() { printf '%s' "${2:-}" > "$BASHIO_CACHE_DIR/${1}.cache"; } # ----------------------------------------------------------------------------- # jq wrapper (some add-ons call bashio::jq) # ----------------------------------------------------------------------------- -bashio::jq() { command -v jq >/dev/null 2>&1 && jq "$@"; } +bashio::jq() { command -v jq > /dev/null 2>&1 && jq "$@"; } # ----------------------------------------------------------------------------- # Home Assistant token # ----------------------------------------------------------------------------- bashio::homeassistant.token() { - local t="${HOMEASSISTANT_TOKEN:-${HASS_TOKEN:-}}" - if [ -z "$t" ] && [ -n "${STANDALONE_OPTIONS_JSON:-}" ] && [ -f "${STANDALONE_OPTIONS_JSON:-}" ] && command -v jq >/dev/null 2>&1; then - t="$(jq -er '.homeassistant.token // empty' "$STANDALONE_OPTIONS_JSON" 2>/dev/null || true)" - fi - printf '%s' "${t:-}" + local t="${HOMEASSISTANT_TOKEN:-${HASS_TOKEN:-}}" + if [ -z "$t" ] && [ -n "${STANDALONE_OPTIONS_JSON:-}" ] && [ -f "${STANDALONE_OPTIONS_JSON:-}" ] && command -v jq > /dev/null 2>&1; then + t="$(jq -er '.homeassistant.token // empty' "$STANDALONE_OPTIONS_JSON" 2> /dev/null || true)" + fi + printf '%s' "${t:-}" } # ----------------------------------------------------------------------------- # Exit helpers # ----------------------------------------------------------------------------- -bashio::exit.ok() { exit 0; } -bashio::exit.nok() { local m="${1:-}"; [ -n "$m" ] && bashio::log.red "$m"; exit 1; } +bashio::exit.ok() { exit 0; } +bashio::exit.nok() { + local m="${1:-}" + [ -n "$m" ] && bashio::log.red "$m" + exit 1 +} # ----------------------------------------------------------------------------- # Core config check shim # ----------------------------------------------------------------------------- # Set STANDALONE_CORE_CHECK_CMD="hass --script check_config -c /config" to enable bashio::core.check() { - if [ -n "${STANDALONE_CORE_CHECK_CMD:-}" ]; then - eval "$STANDALONE_CORE_CHECK_CMD" - else - return 0 - fi + if [ -n "${STANDALONE_CORE_CHECK_CMD:-}" ]; then + eval "$STANDALONE_CORE_CHECK_CMD" + else + return 0 + fi } diff --git a/.templates/ha_autoapps.sh b/.templates/ha_autoapps.sh index 33080a310f..aa2cc772ef 100755 --- a/.templates/ha_autoapps.sh +++ b/.templates/ha_autoapps.sh @@ -41,14 +41,14 @@ restore_apt_sources_if_missing() { mirror="http://ports.ubuntu.com/ubuntu-ports" security_mirror="$mirror" fi - cat > /etc/apt/sources.list < /etc/apt/sources.list << EOF2 deb ${mirror} ${codename} main restricted universe multiverse deb ${mirror} ${codename}-updates main restricted universe multiverse deb ${security_mirror} ${codename}-security main restricted universe multiverse EOF2 ;; debian) - cat > /etc/apt/sources.list < /etc/apt/sources.list << EOF2 deb http://deb.debian.org/debian ${codename} main contrib non-free non-free-firmware deb http://deb.debian.org/debian ${codename}-updates main contrib non-free non-free-firmware deb http://deb.debian.org/debian-security ${codename}-security main contrib non-free non-free-firmware diff --git a/.templates/ha_automatic_packages.sh b/.templates/ha_automatic_packages.sh index 66d11ba73e..5fedbefe72 100755 --- a/.templates/ha_automatic_packages.sh +++ b/.templates/ha_automatic_packages.sh @@ -184,7 +184,7 @@ done if [ "$PACKMANAGER" = "apt" ]; then apt-get update > /dev/null; fi if [ "$PACKMANAGER" = "pacman" ]; then pacman -Sy > /dev/null; fi if [ "$PACKMANAGER" = "apk" ] && [ -f /etc/apk/repositories ] && ! grep -q "community" /etc/apk/repositories; then - ALPINE_VER=$(cat /etc/alpine-release 2>/dev/null | cut -d. -f1,2) + ALPINE_VER=$(cat /etc/alpine-release 2> /dev/null | cut -d. -f1,2) if [ -n "$ALPINE_VER" ]; then echo "https://dl-cdn.alpinelinux.org/alpine/v${ALPINE_VER}/community" >> /etc/apk/repositories apk update > /dev/null @@ -228,7 +228,7 @@ for files in "/etc/services.d" "/etc/cont-init.d"; do if ! ls $files 1> /dev/null 2>&1; then continue; fi # Bashio - if grep -q -rnw "${files}" -e 'bashio' 2>/dev/null && [ ! -f "/usr/bin/bashio" ]; then + if grep -q -rnw "${files}" -e 'bashio' 2> /dev/null && [ ! -f "/usr/bin/bashio" ]; then [ "$VERBOSE" = true ] && echo "install bashio" BASHIO_VERSION="v0.17.5" mkdir -p /tmp/bashio diff --git a/.templates/ha_entrypoint.sh b/.templates/ha_entrypoint.sh index b8e1fd34e5..d35b7c9cb6 100755 --- a/.templates/ha_entrypoint.sh +++ b/.templates/ha_entrypoint.sh @@ -7,13 +7,13 @@ PID1=false if [ "$$" -eq 1 ]; then - PID1=true - echo "Starting as entrypoint" - if [ -d /command ]; then - ln -sf /command/* /usr/bin/ 2>/dev/null || true - fi + PID1=true + echo "Starting as entrypoint" + if [ -d /command ]; then + ln -sf /command/* /usr/bin/ 2> /dev/null || true + fi else - echo "Starting custom scripts" + echo "Starting custom scripts" fi ########################################## @@ -21,31 +21,37 @@ fi ########################################## pick_exec_dir() { - # Prefer locations that are commonly exec-capable in containers - # and writable. Avoid /tmp because it may be mounted noexec. - local d - for d in /dev/shm /run /var/run /mnt /root /; do - if [ -d "$d" ] && [ -w "$d" ]; then - # Create a tiny test executable to confirm "exec" works - local t="${d%/}/.exec_test_$$" - printf '#!/bin/sh\necho ok\n' >"$t" 2>/dev/null || { rm -f "$t" 2>/dev/null || true; continue; } - chmod 700 "$t" 2>/dev/null || { rm -f "$t" 2>/dev/null || true; continue; } - if "$t" >/dev/null 2>&1; then - rm -f "$t" 2>/dev/null || true - echo "$d" - return 0 - fi - rm -f "$t" 2>/dev/null || true - fi - done - return 1 + # Prefer locations that are commonly exec-capable in containers + # and writable. Avoid /tmp because it may be mounted noexec. + local d + for d in /dev/shm /run /var/run /mnt /root /; do + if [ -d "$d" ] && [ -w "$d" ]; then + # Create a tiny test executable to confirm "exec" works + local t="${d%/}/.exec_test_$$" + printf '#!/bin/sh\necho ok\n' > "$t" 2> /dev/null || { + rm -f "$t" 2> /dev/null || true + continue + } + chmod 700 "$t" 2> /dev/null || { + rm -f "$t" 2> /dev/null || true + continue + } + if "$t" > /dev/null 2>&1; then + rm -f "$t" 2> /dev/null || true + echo "$d" + return 0 + fi + rm -f "$t" 2> /dev/null || true + fi + done + return 1 } EXEC_DIR="$(pick_exec_dir || true)" if [ -z "${EXEC_DIR:-}" ]; then - echo "ERROR: Could not find an exec-capable writable directory (e.g., /dev/shm,/run)." - echo "Your environment likely mounts all writable dirs as noexec; shebang validation cannot run safely." - exit 1 + echo "ERROR: Could not find an exec-capable writable directory (e.g., /dev/shm,/run)." + echo "Your environment likely mounts all writable dirs as noexec; shebang validation cannot run safely." + exit 1 fi ###################### @@ -53,14 +59,14 @@ fi ###################### candidate_shebangs=( - "/command/with-contenv bashio" - "/usr/bin/with-contenv bashio" - "/usr/bin/env bashio" - "/usr/bin/bashio" - "/usr/bin/bash" - "/bin/bash" - "/usr/bin/sh" - "/bin/sh" + "/command/with-contenv bashio" + "/usr/bin/with-contenv bashio" + "/usr/bin/env bashio" + "/usr/bin/bashio" + "/usr/bin/bash" + "/bin/bash" + "/usr/bin/sh" + "/bin/sh" ) SHEBANG_ERRORS=() @@ -104,68 +110,68 @@ echo "${_bv:-PROBE_OK}" ' validate_shebang() { - local candidate="$1" - local tmp out rc - local errfile msg + local candidate="$1" + local tmp out rc + local errfile msg - # shellcheck disable=SC2206 - local cmd=( $candidate ) - local exe="${cmd[0]}" + # shellcheck disable=SC2206 + local cmd=($candidate) + local exe="${cmd[0]}" - if [ ! -x "$exe" ]; then - SHEBANG_ERRORS+=(" - FAIL (not executable): #!$candidate") + if [ ! -x "$exe" ]; then + SHEBANG_ERRORS+=(" - FAIL (not executable): #!$candidate") + return 1 + fi + + tmp="${EXEC_DIR%/}/shebang_test.$$.$RANDOM" + errfile="${EXEC_DIR%/}/shebang_probe_err.$$" + { + printf '#!%s\n' "$candidate" + printf '%s\n' "$probe_script_content" + } > "$tmp" + chmod 700 "$tmp" 2> /dev/null || true + + set +e + out="$("$tmp" 2> "$errfile")" + rc=$? + set -e + + rm -f "$tmp" 2> /dev/null || true + + if [ "$rc" -eq 0 ] && [ -n "${out:-}" ] && [ "$out" != "null" ]; then + rm -f "$errfile" 2> /dev/null || true + return 0 + fi + + msg=$' - FAIL: #!'"$candidate"$'\n'" rc=$rc, stdout='${out:-}'"$'\n' + if [ -s "$errfile" ]; then + msg+=$' stderr:\n' + msg+="$(sed -n '1,8p' "$errfile")"$'\n' + else + msg+=$' stderr: \n' + fi + SHEBANG_ERRORS+=("$msg") + rm -f "$errfile" 2> /dev/null || true return 1 - fi - - tmp="${EXEC_DIR%/}/shebang_test.$$.$RANDOM" - errfile="${EXEC_DIR%/}/shebang_probe_err.$$" - { - printf '#!%s\n' "$candidate" - printf '%s\n' "$probe_script_content" - } >"$tmp" - chmod 700 "$tmp" 2>/dev/null || true - - set +e - out="$("$tmp" 2>"$errfile")" - rc=$? - set -e - - rm -f "$tmp" 2>/dev/null || true - - if [ "$rc" -eq 0 ] && [ -n "${out:-}" ] && [ "$out" != "null" ]; then - rm -f "$errfile" 2>/dev/null || true - return 0 - fi - - msg=$' - FAIL: #!'"$candidate"$'\n'" rc=$rc, stdout='${out:-}'"$'\n' - if [ -s "$errfile" ]; then - msg+=$' stderr:\n' - msg+="$(sed -n '1,8p' "$errfile")"$'\n' - else - msg+=$' stderr: \n' - fi - SHEBANG_ERRORS+=("$msg") - rm -f "$errfile" 2>/dev/null || true - return 1 } shebang="" for candidate in "${candidate_shebangs[@]}"; do - if validate_shebang "$candidate"; then - shebang="$candidate" - break - fi + if validate_shebang "$candidate"; then + shebang="$candidate" + break + fi done if [ -z "$shebang" ]; then - echo "ERROR: No valid shebang found (unable to execute bashio::addon.version via candidates)." >&2 - echo "Tried:" >&2 - printf ' - %s\n' "${candidate_shebangs[@]}" >&2 - if [ "${#SHEBANG_ERRORS[@]}" -gt 0 ]; then - echo "Probe failures:" >&2 - printf '%s\n' "${SHEBANG_ERRORS[@]}" >&2 - fi - exit 1 + echo "ERROR: No valid shebang found (unable to execute bashio::addon.version via candidates)." >&2 + echo "Tried:" >&2 + printf ' - %s\n' "${candidate_shebangs[@]}" >&2 + if [ "${#SHEBANG_ERRORS[@]}" -gt 0 ]; then + echo "Probe failures:" >&2 + printf '%s\n' "${SHEBANG_ERRORS[@]}" >&2 + fi + exit 1 fi ##################################### @@ -197,28 +203,28 @@ S6_CONTAINER_ENV="/run/s6/container_environment" # Only when this script is PID 1 -- under /init it is the stage-2 hook and stage 1 has already # written the directory -- and only where with-contenv exists to care. if $PID1 && { [ -x /command/with-contenv ] || [ -x /usr/bin/with-contenv ]; }; then - # Filled in a sibling and renamed into place, never written to live. A half-populated envdir is - # worse than an absent one: s6-envdir accepts it, so a with-contenv script starts and runs - # against an environment quietly missing SUPERVISOR_TOKEN, where an absent one stops it at its - # shebang. rename(2) means a concurrent reader -- a HEALTHCHECK can run alongside PID 1 -- sees - # the directory either absent or complete, never mid-dump. - # - # Cleared rather than written over: /run is not a tmpfs here, so an image layer can persist - # entries, and writing name by name would merge into them and leave variables PID 1 does not - # have, a stale SUPERVISOR_TOKEN among them. A failed rm has to abort the chain, because mkdir -p - # accepts a surviving symlink-to-directory and would let the dump follow it. rm does not traverse - # a symlink, but it would empty anything bind-mounted at this exact path -- not a configuration - # any add-on uses, and not one s6 would tolerate either. - if rm -rf "$S6_CONTAINER_ENV" "$S6_CONTAINER_ENV.tmp" && mkdir -p "$S6_CONTAINER_ENV.tmp" && - s6-dumpenv -- "$S6_CONTAINER_ENV.tmp" && mv "$S6_CONTAINER_ENV.tmp" "$S6_CONTAINER_ENV"; then - echo "Populated $S6_CONTAINER_ENV for with-contenv" - else - # Leaves the directory absent, which is exactly how this fails today -- so the failure mode is - # unchanged, not newly degraded. Never fatal, a read-only /run must still let the add-on boot, - # but never silent either, since the shebang failure it leaves behind says nothing on its own. - rm -rf "$S6_CONTAINER_ENV" "$S6_CONTAINER_ENV.tmp" 2>/dev/null || true - echo -e "\e[38;5;214m$(date) WARNING: could not populate $S6_CONTAINER_ENV; scripts with a with-contenv shebang will fail at their shebang, as they did before this was attempted\e[0m" - fi + # Filled in a sibling and renamed into place, never written to live. A half-populated envdir is + # worse than an absent one: s6-envdir accepts it, so a with-contenv script starts and runs + # against an environment quietly missing SUPERVISOR_TOKEN, where an absent one stops it at its + # shebang. rename(2) means a concurrent reader -- a HEALTHCHECK can run alongside PID 1 -- sees + # the directory either absent or complete, never mid-dump. + # + # Cleared rather than written over: /run is not a tmpfs here, so an image layer can persist + # entries, and writing name by name would merge into them and leave variables PID 1 does not + # have, a stale SUPERVISOR_TOKEN among them. A failed rm has to abort the chain, because mkdir -p + # accepts a surviving symlink-to-directory and would let the dump follow it. rm does not traverse + # a symlink, but it would empty anything bind-mounted at this exact path -- not a configuration + # any add-on uses, and not one s6 would tolerate either. + if rm -rf "$S6_CONTAINER_ENV" "$S6_CONTAINER_ENV.tmp" && mkdir -p "$S6_CONTAINER_ENV.tmp" \ + && s6-dumpenv -- "$S6_CONTAINER_ENV.tmp" && mv "$S6_CONTAINER_ENV.tmp" "$S6_CONTAINER_ENV"; then + echo "Populated $S6_CONTAINER_ENV for with-contenv" + else + # Leaves the directory absent, which is exactly how this fails today -- so the failure mode is + # unchanged, not newly degraded. Never fatal, a read-only /run must still let the add-on boot, + # but never silent either, since the shebang failure it leaves behind says nothing on its own. + rm -rf "$S6_CONTAINER_ENV" "$S6_CONTAINER_ENV.tmp" 2> /dev/null || true + echo -e "\e[38;5;214m$(date) WARNING: could not populate $S6_CONTAINER_ENV; scripts with a with-contenv shebang will fail at their shebang, as they did before this was attempted\e[0m" + fi fi #################################### @@ -228,21 +234,21 @@ fi BASHIO_LIB="" BASHIO_LIB_FULL=false for f in /usr/lib/bashio/bashio.sh /usr/lib/bashio/lib.sh /usr/src/bashio/bashio.sh /usr/local/lib/bashio/bashio.sh; do - if [ -f "$f" ]; then - BASHIO_LIB="$f" - # The real library, which talks to the Supervisor. The standalone shim below only reads - # environment variables, which matters to wait_for_supervisor(). - BASHIO_LIB_FULL=true - break - fi + if [ -f "$f" ]; then + BASHIO_LIB="$f" + # The real library, which talks to the Supervisor. The standalone shim below only reads + # environment variables, which matters to wait_for_supervisor(). + BASHIO_LIB_FULL=true + break + fi done if [ -z "$BASHIO_LIB" ]; then - for f in /usr/local/lib/bashio-standalone.sh /.bashio-standalone.sh; do - if [ -f "$f" ]; then - BASHIO_LIB="$f" - break - fi - done + for f in /usr/local/lib/bashio-standalone.sh /.bashio-standalone.sh; do + if [ -f "$f" ]; then + BASHIO_LIB="$f" + break + fi + done fi ############################## @@ -268,56 +274,56 @@ fi # skips the wait. When the Supervisor is already up -- the normal case -- this costs one request. wait_for_supervisor() { - local max="${HA_SUPERVISOR_WAIT:-30}" - local started deadline remaining attempt announced=0 + local max="${HA_SUPERVISOR_WAIT:-30}" + local started deadline remaining attempt announced=0 - # Nothing to wait for without a token. The standalone shim is excluded too: it answers these - # calls from environment variables and never contacts the Supervisor, so it can never satisfy - # the probe and would burn the whole ceiling on every boot. - [ -n "${SUPERVISOR_TOKEN:-}" ] || return 0 - [ "${BASHIO_LIB_FULL:-false}" = "true" ] || return 0 - # bashio's own curl carries no --max-time, so each attempt is bounded from the outside. - command -v timeout >/dev/null 2>&1 || return 0 - # Digits only, then forced to base 10: `test -gt` accepts a zero-padded override like 08, but - # arithmetic expansion reads it as octal and fails, which would leave the deadline empty and - # spin the loop below forever. - case "$max" in '' | *[!0-9]*) return 0 ;; esac - max=$((10#$max)) - [ "$max" -gt 0 ] || return 0 + # Nothing to wait for without a token. The standalone shim is excluded too: it answers these + # calls from environment variables and never contacts the Supervisor, so it can never satisfy + # the probe and would burn the whole ceiling on every boot. + [ -n "${SUPERVISOR_TOKEN:-}" ] || return 0 + [ "${BASHIO_LIB_FULL:-false}" = "true" ] || return 0 + # bashio's own curl carries no --max-time, so each attempt is bounded from the outside. + command -v timeout > /dev/null 2>&1 || return 0 + # Digits only, then forced to base 10: `test -gt` accepts a zero-padded override like 08, but + # arithmetic expansion reads it as octal and fails, which would leave the deadline empty and + # spin the loop below forever. + case "$max" in '' | *[!0-9]*) return 0 ;; esac + max=$((10#$max)) + [ "$max" -gt 0 ] || return 0 - started=$SECONDS - deadline=$((started + max)) + started=$SECONDS + deadline=$((started + max)) - while :; do - remaining=$((deadline - SECONDS)) - if [ "$remaining" -le 0 ]; then - echo -e "\e[38;5;214m$(date) WARNING: Supervisor API did not report this add-on's network details within ${max}s, continuing anyway\e[0m" - return 0 - fi + while :; do + remaining=$((deadline - SECONDS)) + if [ "$remaining" -le 0 ]; then + echo -e "\e[38;5;214m$(date) WARNING: Supervisor API did not report this add-on's network details within ${max}s, continuing anyway\e[0m" + return 0 + fi - # No single attempt may outlive the ceiling it is bounded by. - attempt=5 - [ "$remaining" -lt "$attempt" ] && attempt="$remaining" + # No single attempt may outlive the ceiling it is bounded by. + attempt=5 + [ "$remaining" -lt "$attempt" ] && attempt="$remaining" - # One call is enough to settle all of them: bashio fetches the whole /addons/self/info object - # and caches it, so a populated ip_address means ingress_port and the rest are cached too. - # Run in a child shell so bashio's globals and traps stay out of the entrypoint; its own error - # logging is dropped because a failed attempt here is expected, not news. - # shellcheck disable=SC2016 - if timeout "$attempt" bash -c '. "$1" && [ -n "$(bashio::addon.ip_address)" ]' \ - _ "$BASHIO_LIB" >/dev/null 2>&1; then - [ "$announced" -eq 0 ] || echo "Supervisor API ready after $((SECONDS - started))s" - return 0 - fi + # One call is enough to settle all of them: bashio fetches the whole /addons/self/info object + # and caches it, so a populated ip_address means ingress_port and the rest are cached too. + # Run in a child shell so bashio's globals and traps stay out of the entrypoint; its own error + # logging is dropped because a failed attempt here is expected, not news. + # shellcheck disable=SC2016 + if timeout "$attempt" bash -c '. "$1" && [ -n "$(bashio::addon.ip_address)" ]' \ + _ "$BASHIO_LIB" > /dev/null 2>&1; then + [ "$announced" -eq 0 ] || echo "Supervisor API ready after $((SECONDS - started))s" + return 0 + fi - if [ "$announced" -eq 0 ]; then - echo "Waiting for the Supervisor API to report this add-on's network details..." - announced=1 - fi + if [ "$announced" -eq 0 ]; then + echo "Waiting for the Supervisor API to report this add-on's network details..." + announced=1 + fi - # Skipped when the attempt already consumed what was left, so the sleep cannot overshoot. - [ "$((deadline - SECONDS))" -gt 0 ] && sleep 1 - done + # Skipped when the attempt already consumed what was left, so the sleep cannot overshoot. + [ "$((deadline - SECONDS))" -gt 0 ] && sleep 1 + done } wait_for_supervisor @@ -327,97 +333,97 @@ wait_for_supervisor #################### run_one_script() { - local script="$1" + local script="$1" - echo "$script: executing" + echo "$script: executing" - if [ "$(id -u)" -eq 0 ]; then - chown "$(id -u)":"$(id -g)" "$script" || true - chmod a+x "$script" || true - else - echo -e "\e[38;5;214m$(date) WARNING: Script executed with user $(id -u):$(id -g), things can break and chown won't work\e[0m" - sed -i "s/^[[:space:]]*chown /true # chown /g" "$script" - sed -i "s/^[[:space:]]*chmod /true # chmod /g" "$script" - fi - - sed -i "1s|^.*|#!$shebang|" "$script" - chmod +x "$script" - - if [ "${ha_entry_source:-null}" = "true" ]; then - sed -i -E 's/^[[:space:]]*exit ([0-9]+)/return \1 \|\| exit \1/g' "$script" - sed -i 's/bashio::exit\.nok/return 1/g' "$script" - sed -i 's/bashio::exit\.ok/return 0/g' "$script" - # shellcheck disable=SC1090 - source "$script" || echo -e "\033[0;31mError\033[0m : $script exiting $?" - else - _run_rc=0 - "$script" || _run_rc=$? - if [ "$_run_rc" -eq 126 ] && [ -n "${BASHIO_LIB:-}" ]; then - echo "Direct exec failed (rc=126, likely E2BIG), retrying via source in subshell..." - _run_rc=0 - ( - # shellcheck disable=SC1090 - . "$BASHIO_LIB" 2>/dev/null || true - # shellcheck disable=SC1090 - . "$script" - ) || _run_rc=$? - if [ "$_run_rc" -ne 0 ]; then - echo -e "\033[0;31mError\033[0m : $script exiting $_run_rc" - fi - elif [ "$_run_rc" -ne 0 ]; then - echo -e "\033[0;31mError\033[0m : $script exiting $_run_rc" + if [ "$(id -u)" -eq 0 ]; then + chown "$(id -u)":"$(id -g)" "$script" || true + chmod a+x "$script" || true + else + echo -e "\e[38;5;214m$(date) WARNING: Script executed with user $(id -u):$(id -g), things can break and chown won't work\e[0m" + sed -i "s/^[[:space:]]*chown /true # chown /g" "$script" + sed -i "s/^[[:space:]]*chmod /true # chmod /g" "$script" fi - fi - sed -i '1a exit 0' "$script" + sed -i "1s|^.*|#!$shebang|" "$script" + chmod +x "$script" + + if [ "${ha_entry_source:-null}" = "true" ]; then + sed -i -E 's/^[[:space:]]*exit ([0-9]+)/return \1 \|\| exit \1/g' "$script" + sed -i 's/bashio::exit\.nok/return 1/g' "$script" + sed -i 's/bashio::exit\.ok/return 0/g' "$script" + # shellcheck disable=SC1090 + source "$script" || echo -e "\033[0;31mError\033[0m : $script exiting $?" + else + _run_rc=0 + "$script" || _run_rc=$? + if [ "$_run_rc" -eq 126 ] && [ -n "${BASHIO_LIB:-}" ]; then + echo "Direct exec failed (rc=126, likely E2BIG), retrying via source in subshell..." + _run_rc=0 + ( + # shellcheck disable=SC1090 + . "$BASHIO_LIB" 2> /dev/null || true + # shellcheck disable=SC1090 + . "$script" + ) || _run_rc=$? + if [ "$_run_rc" -ne 0 ]; then + echo -e "\033[0;31mError\033[0m : $script exiting $_run_rc" + fi + elif [ "$_run_rc" -ne 0 ]; then + echo -e "\033[0;31mError\033[0m : $script exiting $_run_rc" + fi + fi + + sed -i '1a exit 0' "$script" } if [ -d /etc/cont-init.d ]; then - for SCRIPTS in /etc/cont-init.d/*; do - [ -e "$SCRIPTS" ] || continue - run_one_script "$SCRIPTS" - done + for SCRIPTS in /etc/cont-init.d/*; do + [ -e "$SCRIPTS" ] || continue + run_one_script "$SCRIPTS" + done fi if $PID1; then - shopt -s nullglob - for runfile in /etc/services.d/*/run /etc/s6-overlay/s6-rc.d/*/run; do - [ -f "$runfile" ] || continue - echo "Starting: $runfile" - sed -i "1s|^.*|#!$shebang|" "$runfile" - chmod +x "$runfile" - ( - restart_count=0 - max_restarts=5 - while true; do - _svc_rc=0 - "$runfile" || _svc_rc=$? - if [ "$_svc_rc" -eq 126 ] && [ -n "${BASHIO_LIB:-}" ]; then - echo "Direct exec of $runfile failed (rc=126, likely E2BIG), retrying via source..." - _svc_rc=0 - ( - # shellcheck disable=SC1090 - . "$BASHIO_LIB" 2>/dev/null || true - # shellcheck disable=SC1090 - . "$runfile" - ) || _svc_rc=$? - fi - rc=$_svc_rc - if [ "$rc" -eq 0 ]; then - echo "$runfile exited cleanly (exit 0), not restarting." - break - fi - restart_count=$((restart_count + 1)) - if [ "$restart_count" -ge "$max_restarts" ]; then - echo -e "\033[0;31mERROR: $runfile has crashed $restart_count times (last exit code: $rc), giving up.\033[0m" - break - fi - echo -e "\e[38;5;214m$(date) WARNING: $runfile exited (code $rc), restarting (#${restart_count}/${max_restarts}) in 5s...\e[0m" - sleep 5 - done - ) & - done - shopt -u nullglob + shopt -s nullglob + for runfile in /etc/services.d/*/run /etc/s6-overlay/s6-rc.d/*/run; do + [ -f "$runfile" ] || continue + echo "Starting: $runfile" + sed -i "1s|^.*|#!$shebang|" "$runfile" + chmod +x "$runfile" + ( + restart_count=0 + max_restarts=5 + while true; do + _svc_rc=0 + "$runfile" || _svc_rc=$? + if [ "$_svc_rc" -eq 126 ] && [ -n "${BASHIO_LIB:-}" ]; then + echo "Direct exec of $runfile failed (rc=126, likely E2BIG), retrying via source..." + _svc_rc=0 + ( + # shellcheck disable=SC1090 + . "$BASHIO_LIB" 2> /dev/null || true + # shellcheck disable=SC1090 + . "$runfile" + ) || _svc_rc=$? + fi + rc=$_svc_rc + if [ "$rc" -eq 0 ]; then + echo "$runfile exited cleanly (exit 0), not restarting." + break + fi + restart_count=$((restart_count + 1)) + if [ "$restart_count" -ge "$max_restarts" ]; then + echo -e "\033[0;31mERROR: $runfile has crashed $restart_count times (last exit code: $rc), giving up.\033[0m" + break + fi + echo -e "\e[38;5;214m$(date) WARNING: $runfile exited (code $rc), restarting (#${restart_count}/${max_restarts}) in 5s...\e[0m" + sleep 5 + done + ) & + done + shopt -u nullglob fi ###################### @@ -425,43 +431,43 @@ fi ###################### if $PID1; then - echo " " - echo -e "\033[0;32mEverything started!\033[0m" + echo " " + echo -e "\033[0;32mEverything started!\033[0m" - terminate() { - local local_pid - echo "Termination signal received, forwarding to subprocesses..." - if command -v pgrep >/dev/null 2>&1; then - while read -r pid; do - [ -n "$pid" ] || continue - echo "Terminating child PID $pid" - kill -TERM "$pid" 2>/dev/null || echo "Failed to terminate PID $pid" - done < <(pgrep -P "$$" || true) - else - for p in /proc/[0-9]*/; do - local_pid="${p#/proc/}" - local_pid="${local_pid%/}" - if [ "$local_pid" -ne 1 ] && grep -q "^PPid:[[:space:]]*$$" "/proc/$local_pid/status" 2>/dev/null; then - echo "Terminating child PID $local_pid" - kill -TERM "$local_pid" 2>/dev/null || echo "Failed to terminate PID $local_pid" + terminate() { + local local_pid + echo "Termination signal received, forwarding to subprocesses..." + if command -v pgrep > /dev/null 2>&1; then + while read -r pid; do + [ -n "$pid" ] || continue + echo "Terminating child PID $pid" + kill -TERM "$pid" 2> /dev/null || echo "Failed to terminate PID $pid" + done < <(pgrep -P "$$" || true) + else + for p in /proc/[0-9]*/; do + local_pid="${p#/proc/}" + local_pid="${local_pid%/}" + if [ "$local_pid" -ne 1 ] && grep -q "^PPid:[[:space:]]*$$" "/proc/$local_pid/status" 2> /dev/null; then + echo "Terminating child PID $local_pid" + kill -TERM "$local_pid" 2> /dev/null || echo "Failed to terminate PID $local_pid" + fi + done fi - done - fi - wait || true - echo "All subprocesses terminated. Exiting." - exit 0 - } + wait || true + echo "All subprocesses terminated. Exiting." + exit 0 + } - trap terminate SIGTERM SIGINT - while :; do - sleep infinity & - wait $! - done + trap terminate SIGTERM SIGINT + while :; do + sleep infinity & + wait $! + done else - echo " " - echo -e "\033[0;32mStarting the upstream container\033[0m" - echo " " - if [ -f /docker-mods ]; then - exec /docker-mods - fi + echo " " + echo -e "\033[0;32mStarting the upstream container\033[0m" + echo " " + if [ -f /docker-mods ]; then + exec /docker-mods + fi fi diff --git a/CLAUDE.md b/CLAUDE.md index c3ad3e7700..16121a5a31 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -147,7 +147,7 @@ manual actions with precedence. Prompts live in `.github/prompts/`, shared shell in `.github/scripts/`. | Workflow | Model | Trigger | Role | -|---|---|---|---| +| --- | --- | --- | --- | | `on_issues_ai_triage.yaml` | Sonnet-low | issue opened (+ author reply, daily catch-up) | Tier 1: classify, dedupe, answer, ask for info; label `ai-triage` for real add-on bugs | | `daily_ai_fix.yaml` | Opus 5-xhigh | daily 03:00 | Tier 2: diagnose the `ai-triage` batch; small+confident → ready PR (`ai:fixed`); else write a plan (`ai:plan-pending`) | | `on_issue_approved.yaml` | Opus 5-high | maintainer adds `ai:approved` | Tier 3: execute the approved plan → ready PR | @@ -176,7 +176,7 @@ prompt-only, not machine-enforced. ## Linting Rules | Tool | Config | Key ignores | -|------|--------|------------| +| ------ | -------- | ------------ | | Hadolint | `.hadolint.yaml` | DL3002, DL3006-9, DL3018 (no pinning required) | | ShellCheck | `.shellcheckrc` | SC2002 | | Markdownlint | `.markdownlint.yaml` | MD013 (line length), MD025, MD033, MD041 | diff --git a/addons_updater/README.md b/addons_updater/README.md index 33c004b330..803f432535 100644 --- a/addons_updater/README.md +++ b/addons_updater/README.md @@ -75,7 +75,7 @@ You can add the following tags in the file : ### Addon version numbering -The `version` written in the addon `config.yaml` is the one Home Assistant compares to decide whether an update is available. Home Assistant hides the update when it can order both versions and the new one is not strictly newer (`1.2.3` -> `1.2.3-2` is a semver pre-release, so it is *older*), and it cannot order tags such as `version-bf9e0b4f` or `ubuntu-2026-06-01` at all. +The `version` written in the addon `config.yaml` is the one Home Assistant compares to decide whether an update is available. Home Assistant hides the update when it can order both versions and the new one is not strictly newer (`1.2.3` -> `1.2.3-2` is a semver pre-release, so it is _older_), and it cannot order tags such as `version-bf9e0b4f` or `ubuntu-2026-06-01` at all. The addon version is therefore derived from the upstream tag: diff --git a/aurral/CHANGELOG.md b/aurral/CHANGELOG.md index 4f06681eb3..744406997a 100644 --- a/aurral/CHANGELOG.md +++ b/aurral/CHANGELOG.md @@ -1,31 +1,31 @@ - + ## 2.8.0 (2026-09-05) - Update to latest version from lklynet/aurral (changelog : https://github.com/lklynet/aurral/releases) - + ## 2.7.0 (2026-08-29) - Update to latest version from lklynet/aurral (changelog : https://github.com/lklynet/aurral/releases) - + ## 2.5.1 (2026-08-22) - Update to latest version from lklynet/aurral (changelog : https://github.com/lklynet/aurral/releases) - + ## 2.4.0 (2026-08-13) - Update to latest version from lklynet/aurral (changelog : https://github.com/lklynet/aurral/releases) - + ## 2.1.0 (2026-08-08) - Update to latest version from lklynet/aurral (changelog : https://github.com/lklynet/aurral/releases) - + ## 2.0.3 (2026-08-01) - Update to latest version from lklynet/aurral (changelog : https://github.com/lklynet/aurral/releases) - + ## 2.0.2 (2026-08-01) - Update to latest version from lklynet/aurral (changelog : https://github.com/lklynet/aurral/releases) - + ## 2.0.0 (2026-07-22) - Update to latest version from lklynet/aurral (changelog : https://github.com/lklynet/aurral/releases) - + ## 1.76.52 (2026-07-11) - Update to latest version from lklynet/aurral (changelog : https://github.com/lklynet/aurral/releases) - + ## 1.76.51 (2026-06-17) - Update to latest version from lklynet/aurral (changelog : https://github.com/lklynet/aurral/releases) ## 1.76.49 (2026-06-05) diff --git a/aurral/README.md b/aurral/README.md index db6a9464a8..30a5936ce7 100644 --- a/aurral/README.md +++ b/aurral/README.md @@ -6,7 +6,7 @@ This addon is based on the docker image ## Configuration | Option | Default | Description | -|---|---|---| +| --- | --- | --- | | `download_folder` | `/share/aurral/downloads` | Path where Aurral writes flow downloads. Must be under `/share`. | | `weekly_flow_folder` | `weekly-flow` | Subfolder name appended to `download_folder` for weekly flow files. The full path will be `download_folder/weekly_flow_folder`. | diff --git a/autobrr/CHANGELOG.md b/autobrr/CHANGELOG.md index d3a4c36948..a5309d7fff 100644 --- a/autobrr/CHANGELOG.md +++ b/autobrr/CHANGELOG.md @@ -1,16 +1,16 @@ - + ## 1.85.0 (2026-08-29) - Update to latest version from autobrr/autobrr (changelog : https://github.com/autobrr/autobrr/releases) - + ## 1.84.0 (2026-08-15) - Update to latest version from autobrr/autobrr (changelog : https://github.com/autobrr/autobrr/releases) - + ## 1.83.0 (2026-08-01) - Update to latest version from autobrr/autobrr (changelog : https://github.com/autobrr/autobrr/releases) - + ## 1.82.1 (2026-07-16) - Update to latest version from autobrr/autobrr (changelog : https://github.com/autobrr/autobrr/releases) - + ## 1.81.0 (2026-07-04) - Update to latest version from autobrr/autobrr (changelog : https://github.com/autobrr/autobrr/releases) ## 1.80.0 (2026-06-05) diff --git a/autobrr/README.md b/autobrr/README.md index a486ba8e0b..379c66a449 100644 --- a/autobrr/README.md +++ b/autobrr/README.md @@ -67,7 +67,7 @@ Default credentials: `admin` / `password` (change after first login). ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/bazarr/README.md b/bazarr/README.md index c7b2a4df35..849411c337 100644 --- a/bazarr/README.md +++ b/bazarr/README.md @@ -44,7 +44,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/bazarr/rootfs/etc/services.d/nginx/run b/bazarr/rootfs/etc/services.d/nginx/run old mode 100644 new mode 100755 diff --git a/bentopdf/README.md b/bentopdf/README.md index 614080cac0..37ac6d47d1 100644 --- a/bentopdf/README.md +++ b/bentopdf/README.md @@ -17,7 +17,7 @@ A privacy-first PDF toolkit running entirely in your browser — no uploads, no ### Organize & Edit | Tool | Tool | Tool | -|------|------|------| +| ------ | ------ | ------ | | Merge PDF | Split PDF | Organize PDF | | Delete Pages | Extract Pages | Reverse Pages | | Rotate PDF | Rotate Custom | Crop PDF | @@ -28,7 +28,7 @@ A privacy-first PDF toolkit running entirely in your browser — no uploads, no ### Convert TO PDF | Tool | Tool | Tool | -|------|------|------| +| ------ | ------ | ------ | | Word to PDF | Excel to PDF | PowerPoint to PDF | | Image to PDF | JPG to PDF | PNG to PDF | | BMP to PDF | TIFF to PDF | WEBP to PDF | @@ -44,7 +44,7 @@ A privacy-first PDF toolkit running entirely in your browser — no uploads, no ### Convert FROM PDF | Tool | Tool | Tool | -|------|------|------| +| ------ | ------ | ------ | | PDF to DOCX | PDF to Excel | PDF to JPG | | PDF to PNG | PDF to BMP | PDF to TIFF | | PDF to WEBP | PDF to SVG | PDF to Text | @@ -54,7 +54,7 @@ A privacy-first PDF toolkit running entirely in your browser — no uploads, no ### Security & Metadata | Tool | Tool | Tool | -|------|------|------| +| ------ | ------ | ------ | | Encrypt PDF | Decrypt PDF | Change Permissions | | Remove Restrictions | Sign PDF | Digital Sign PDF | | Validate Signature | Edit Metadata | View Metadata | @@ -64,7 +64,7 @@ A privacy-first PDF toolkit running entirely in your browser — no uploads, no ### Enhance & Process | Tool | Tool | Tool | -|------|------|------| +| ------ | ------ | ------ | | Compress PDF | OCR PDF | Deskew PDF | | Rasterize PDF | Linearize PDF | PDF to PDF/A | | Adjust Colors | Invert Colors | Text Color | @@ -76,7 +76,7 @@ A privacy-first PDF toolkit running entirely in your browser — no uploads, no ### Forms & More | Tool | Tool | Tool | -|------|------|------| +| ------ | ------ | ------ | | Form Creator | Form Filler | Table of Contents | | Bookmark | PDF Editor | Extract Images | | Extract Tables | Extract Attachments | Edit Attachments | diff --git a/bentopdf/rootfs/etc/s6-overlay/s6-rc.d/bentopdf/run b/bentopdf/rootfs/etc/s6-overlay/s6-rc.d/bentopdf/run old mode 100644 new mode 100755 diff --git a/birdnet-go-dev/rootfs/etc/cont-init.d/01-structure.sh b/birdnet-go-dev/rootfs/etc/cont-init.d/01-structure.sh index 4c11de5822..86c0432be2 100755 --- a/birdnet-go-dev/rootfs/etc/cont-init.d/01-structure.sh +++ b/birdnet-go-dev/rootfs/etc/cont-init.d/01-structure.sh @@ -43,8 +43,8 @@ if [ ! -f "$CONFIG_LOCATION" ]; then # config. (We can't remove the file and continue — subsequent yq calls # under set -e would abort the init script.) if ! curl -fL -s -S \ - https://raw.githubusercontent.com/tphakala/birdnet-go/refs/heads/main/internal/conf/config.yaml \ - -o "$CONFIG_LOCATION"; then + https://raw.githubusercontent.com/tphakala/birdnet-go/refs/heads/main/internal/conf/config.yaml \ + -o "$CONFIG_LOCATION"; then bashio::log.warning "Could not download default config.yaml; seeding an empty document so addon defaults can populate it" echo '{}' > "$CONFIG_LOCATION" fi @@ -190,5 +190,5 @@ LOG_DIR="/config/logs" if [ -d "$LOG_DIR" ]; then bashio::log.info "Trimming log files older than ${LOG_MAX_AGE_DAYS} days in ${LOG_DIR}" ln -sf "$LOG_DIR" /logs - find "$LOG_DIR" -type f -name "*.log*" -mtime +"$LOG_MAX_AGE_DAYS" -delete 2>/dev/null || true + find "$LOG_DIR" -type f -name "*.log*" -mtime +"$LOG_MAX_AGE_DAYS" -delete 2> /dev/null || true fi diff --git a/birdnet-go-dev/rootfs/etc/cont-init.d/33-mariadb.sh b/birdnet-go-dev/rootfs/etc/cont-init.d/33-mariadb.sh index 29d1e30772..6d953ae289 100755 --- a/birdnet-go-dev/rootfs/etc/cont-init.d/33-mariadb.sh +++ b/birdnet-go-dev/rootfs/etc/cont-init.d/33-mariadb.sh @@ -44,8 +44,8 @@ if ! bashio::config.true 'mariadb_auto_config'; then # Only revert if config.yaml points at the HA MariaDB host we would have # written — a mysql block pointing at a different host was set manually. # shellcheck disable=SC2016 - CURRENT_MYSQL_HOST="$(yq -r '.output.mysql.host // empty' "$CONFIG_LOCATION" 2>/dev/null || true)" - if yq -e '.output.mysql.enabled == true' "$CONFIG_LOCATION" >/dev/null 2>&1 \ + CURRENT_MYSQL_HOST="$(yq -r '.output.mysql.host // empty' "$CONFIG_LOCATION" 2> /dev/null || true)" + if yq -e '.output.mysql.enabled == true' "$CONFIG_LOCATION" > /dev/null 2>&1 \ && [ "${CURRENT_MYSQL_HOST}" = "${MYSQL_HOST}" ]; then yq -i -y \ '.output.mysql.enabled = false @@ -71,7 +71,7 @@ bashio::log.green "---" # Resolve MariaDB hostname to IPv4: on HAOS >=17.3 the Supervisor network # gained IPv6, but the MariaDB addon only grants its user from the IPv4 # subnet. Fall back to the raw hostname if resolution fails. -MYSQL_HOST_RESOLVED="$(getent ahostsv4 "${MYSQL_HOST}" 2>/dev/null | awk '{print $1; exit}')" +MYSQL_HOST_RESOLVED="$(getent ahostsv4 "${MYSQL_HOST}" 2> /dev/null | awk '{print $1; exit}')" MYSQL_HOST_RESOLVED="${MYSQL_HOST_RESOLVED:-${MYSQL_HOST}}" if [ "${MYSQL_HOST_RESOLVED}" != "${MYSQL_HOST}" ]; then bashio::log.blue "Resolved ${MYSQL_HOST} -> ${MYSQL_HOST_RESOLVED} (forcing IPv4)" diff --git a/birdnet-go/CHANGELOG.md b/birdnet-go/CHANGELOG.md index be6c242640..801daead61 100644 --- a/birdnet-go/CHANGELOG.md +++ b/birdnet-go/CHANGELOG.md @@ -1,4 +1,4 @@ - + ## 20260827 (2026-08-29) - Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases) - Upstream tag : 20260823 @@ -6,13 +6,13 @@ - Minor bugs fixed ## 20260716.1 (26-08-2026) - Minor bugs fixed - + ## 20260716.1 (2026-08-26) - Rebuild after syncing the alexbelgium/birdnet-go fork with upstream tphakala/birdnet-go and resolving conflicts on all open pull requests ## 20260716 (2026-07-16) - Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases) - + ## 20260712 (2026-07-13) - Update to latest version from tphakala/birdnet-go (changelog : https://github.com/tphakala/birdnet-go/releases) ## nightly-20260615-4 (09-07-2026) @@ -22,8 +22,8 @@ ## nightly-20260615-2 (05-07-2026) - Minor bugs fixed - - Fix detections/database not persisting across restarts on a fresh install: upstream's default `config.yaml` ships `output.sqlite.path: birdnet.db` (relative) explicitly, so the missing-only (`//=`) seeding introduced previously never rewrote it to an absolute path. A relative path resolves against the app's ephemeral working directory, so the database was silently recreated empty on every restart. Any relative `output.sqlite.path` is now rewritten to live under the persistent `/config` on startup; values already set to an absolute path are left untouched. (https://github.com/tphakala/birdnet-go/discussions/3774) - - MQTT auto-config now also enables BirdNET-Go's native Home Assistant MQTT auto-discovery: detection sensors appear in Home Assistant automatically with no manual YAML (existing UI/config.yaml edits are preserved) +- Fix detections/database not persisting across restarts on a fresh install: upstream's default `config.yaml` ships `output.sqlite.path: birdnet.db` (relative) explicitly, so the missing-only (`//=`) seeding introduced previously never rewrote it to an absolute path. A relative path resolves against the app's ephemeral working directory, so the database was silently recreated empty on every restart. Any relative `output.sqlite.path` is now rewritten to live under the persistent `/config` on startup; values already set to an absolute path are left untouched. (https://github.com/tphakala/birdnet-go/discussions/3774) +- MQTT auto-config now also enables BirdNET-Go's native Home Assistant MQTT auto-discovery: detection sensors appear in Home Assistant automatically with no manual YAML (existing UI/config.yaml edits are preserved) - MQTT auto-config seeds `realtime.mqtt.retain: true` (only when unset) so sensor states survive Home Assistant restarts - Added supervisor watchdog (tcp://[HOST]:[PORT:8080]) so the add-on is automatically restarted if BirdNET-Go stops responding - Added backup_exclude for rotated logs, making Home Assistant backups smaller (SQLite journals are kept so hot backups stay consistent) diff --git a/birdnet-go/rootfs/etc/cont-init.d/01-structure.sh b/birdnet-go/rootfs/etc/cont-init.d/01-structure.sh index c0e3493064..4c374b230e 100755 --- a/birdnet-go/rootfs/etc/cont-init.d/01-structure.sh +++ b/birdnet-go/rootfs/etc/cont-init.d/01-structure.sh @@ -43,8 +43,8 @@ if [ ! -f "$CONFIG_LOCATION" ]; then # config. (We can't remove the file and continue — subsequent yq calls # under set -e would abort the init script.) if ! curl -fL -s -S \ - https://raw.githubusercontent.com/tphakala/birdnet-go/refs/heads/main/internal/conf/config.yaml \ - -o "$CONFIG_LOCATION"; then + https://raw.githubusercontent.com/tphakala/birdnet-go/refs/heads/main/internal/conf/config.yaml \ + -o "$CONFIG_LOCATION"; then bashio::log.warning "Could not download default config.yaml; seeding an empty document so addon defaults can populate it" echo '{}' > "$CONFIG_LOCATION" fi @@ -186,5 +186,5 @@ LOG_DIR="/config/logs" if [ -d "$LOG_DIR" ]; then bashio::log.info "Trimming log files older than ${LOG_MAX_AGE_DAYS} days in ${LOG_DIR}" ln -sf "$LOG_DIR" /logs - find "$LOG_DIR" -type f -name "*.log*" -mtime +"$LOG_MAX_AGE_DAYS" -delete 2>/dev/null || true + find "$LOG_DIR" -type f -name "*.log*" -mtime +"$LOG_MAX_AGE_DAYS" -delete 2> /dev/null || true fi diff --git a/birdnet-pi-zach/DOCS.md b/birdnet-pi-zach/DOCS.md index 5d4b7aa2bb..bd4e98efee 100644 --- a/birdnet-pi-zach/DOCS.md +++ b/birdnet-pi-zach/DOCS.md @@ -9,9 +9,9 @@ Here are some example tests I did (the whole threads are really interesting also **My recommendation:** -- **Best entry system (< 50 €):** Boya By-lm40 (30 €) + deadcat (10 €) -- **Best middle end system (< 150 €):** Clippy EM272 TRS/TRRS (55 €) + Rode AI micro trs/trrs to usb (70 €) + Rycote deadcat (27 €) -- **Best high end system (<400 €):** Clippy EM272 XLR (85 €) or LOM Ucho Pro (75 €) + Focusrite Scarlet 2i2 4th Gen (200 €) + Bubblebee Pro Extreme deadcat (45 €) +- **Best entry system (< 50 €):** Boya By-lm40 (30 €) + deadcat (10 €) +- **Best middle end system (< 150 €):** Clippy EM272 TRS/TRRS (55 €) + Rode AI micro trs/trrs to usb (70 €) + Rycote deadcat (27 €) +- **Best high end system (<400 €):** Clippy EM272 XLR (85 €) or LOM Ucho Pro (75 €) + Focusrite Scarlet 2i2 4th Gen (200 €) + Bubblebee Pro Extreme deadcat (45 €) **Sources for high end microphones in Europe:** diff --git a/birdnet-pi-zach/rootfs/helpers/birdnet_to_mqtt.py b/birdnet-pi-zach/rootfs/helpers/birdnet_to_mqtt.py index b075e0e231..2e5beaeec0 100644 --- a/birdnet-pi-zach/rootfs/helpers/birdnet_to_mqtt.py +++ b/birdnet-pi-zach/rootfs/helpers/birdnet_to_mqtt.py @@ -112,6 +112,7 @@ def automatic_mqtt_publish(file, detection, path): mqttc.publish(mqtt_topic, json_bird, 1) log.info("Posted to MQTT: ok") + # Create MQTT client using legacy callback API when available for # compatibility with paho-mqtt >= 2.0 callback_api = getattr(mqtt, "CallbackAPIVersion", None) diff --git a/birdnet-pi/DOCS.md b/birdnet-pi/DOCS.md index 5d4b7aa2bb..bd4e98efee 100644 --- a/birdnet-pi/DOCS.md +++ b/birdnet-pi/DOCS.md @@ -9,9 +9,9 @@ Here are some example tests I did (the whole threads are really interesting also **My recommendation:** -- **Best entry system (< 50 €):** Boya By-lm40 (30 €) + deadcat (10 €) -- **Best middle end system (< 150 €):** Clippy EM272 TRS/TRRS (55 €) + Rode AI micro trs/trrs to usb (70 €) + Rycote deadcat (27 €) -- **Best high end system (<400 €):** Clippy EM272 XLR (85 €) or LOM Ucho Pro (75 €) + Focusrite Scarlet 2i2 4th Gen (200 €) + Bubblebee Pro Extreme deadcat (45 €) +- **Best entry system (< 50 €):** Boya By-lm40 (30 €) + deadcat (10 €) +- **Best middle end system (< 150 €):** Clippy EM272 TRS/TRRS (55 €) + Rode AI micro trs/trrs to usb (70 €) + Rycote deadcat (27 €) +- **Best high end system (<400 €):** Clippy EM272 XLR (85 €) or LOM Ucho Pro (75 €) + Focusrite Scarlet 2i2 4th Gen (200 €) + Bubblebee Pro Extreme deadcat (45 €) **Sources for high end microphones in Europe:** diff --git a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py index b075e0e231..2e5beaeec0 100644 --- a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py +++ b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py @@ -112,6 +112,7 @@ def automatic_mqtt_publish(file, detection, path): mqttc.publish(mqtt_topic, json_bird, 1) log.info("Posted to MQTT: ok") + # Create MQTT client using legacy callback API when available for # compatibility with paho-mqtt >= 2.0 callback_api = getattr(mqtt, "CallbackAPIVersion", None) diff --git a/birdnet-pipy/CHANGELOG.md b/birdnet-pipy/CHANGELOG.md index 035b00a447..b2a1a2d9e0 100644 --- a/birdnet-pipy/CHANGELOG.md +++ b/birdnet-pipy/CHANGELOG.md @@ -1,19 +1,19 @@ - + ## 0.8.8 (2026-08-22) - Update to latest version from Suncuss/BirdNET-PiPy (changelog : https://github.com/Suncuss/BirdNET-PiPy/releases) - + ## 0.8.6 (2026-08-13) - Update to latest version from Suncuss/BirdNET-PiPy (changelog : https://github.com/Suncuss/BirdNET-PiPy/releases) - + ## 0.8.5 (2026-08-01) - Update to latest version from Suncuss/BirdNET-PiPy (changelog : https://github.com/Suncuss/BirdNET-PiPy/releases) - + ## 0.8.4 (2026-07-13) - Update to latest version from Suncuss/BirdNET-PiPy (changelog : https://github.com/Suncuss/BirdNET-PiPy/releases) - + ## 0.8.3 (2026-07-11) - Update to latest version from Suncuss/BirdNET-PiPy (changelog : https://github.com/Suncuss/BirdNET-PiPy/releases) - + ## 0.8.2.1 (2026-07-05) - Re-tag of 0.8.2-1 with no content change. Home Assistant compares add-on versions with semver semantics, where a `-N` suffix counts as a *pre-release* and sorts **below** the base version — so users already on 0.8.2 saw the 0.8.2-1 nginx fix as "Up-to-date" with the Update button disabled. Four-segment `0.8.2.1` sorts above both `0.8.2` and `0.8.2-1` (and below the next upstream `0.8.3`), so the update becomes installable everywhere. @@ -23,7 +23,7 @@ ## 0.8.2 (2026-07-04) - Update to latest version from Suncuss/BirdNET-PiPy (changelog : https://github.com/Suncuss/BirdNET-PiPy/releases) - + ## 0.7.5 (2026-06-23) - Update to latest version from Suncuss/BirdNET-PiPy (changelog : https://github.com/Suncuss/BirdNET-PiPy/releases) ## 0.7.4 (2026-06-01) diff --git a/birdnet-pipy/config.yaml b/birdnet-pipy/config.yaml index c6a56df26c..1321879266 100644 --- a/birdnet-pipy/config.yaml +++ b/birdnet-pipy/config.yaml @@ -73,7 +73,7 @@ map: name: BirdNET-PiPy options: env_vars: [] - ICECAST_PASSWORD: '' + ICECAST_PASSWORD: "" data_location: /config/data panel_icon: mdi:bird ports: diff --git a/birdnet-pipy/rootfs/etc/cont-init.d/01-structure.sh b/birdnet-pipy/rootfs/etc/cont-init.d/01-structure.sh index 6c102d6485..9372045d99 100755 --- a/birdnet-pipy/rootfs/etc/cont-init.d/01-structure.sh +++ b/birdnet-pipy/rootfs/etc/cont-init.d/01-structure.sh @@ -7,11 +7,11 @@ DATA_LOCATION="$(bashio::config 'data_location' || true)" DATA_LOCATION="${DATA_LOCATION:-$DEFAULT_LOCATION}" case "${DATA_LOCATION}" in - /config/*|/share/*|/data/*) ;; - *) - bashio::log.warning "Invalid data_location '${DATA_LOCATION}', falling back to ${DEFAULT_LOCATION}" - DATA_LOCATION="${DEFAULT_LOCATION}" - ;; + /config/* | /share/* | /data/*) ;; + *) + bashio::log.warning "Invalid data_location '${DATA_LOCATION}', falling back to ${DEFAULT_LOCATION}" + DATA_LOCATION="${DEFAULT_LOCATION}" + ;; esac LEGACY1="/config/birdnet-pipy/data" @@ -19,14 +19,14 @@ LEGACY2="/data" mkdir -p "${DATA_LOCATION}" -if [ -z "$(ls -A "${DATA_LOCATION}" 2>/dev/null || true)" ]; then - if [ -d "${LEGACY1}" ] && [ -n "$(ls -A "${LEGACY1}" 2>/dev/null || true)" ]; then - bashio::log.notice "Migrating legacy data from ${LEGACY1} to ${DATA_LOCATION}" - cp -a "${LEGACY1}/." "${DATA_LOCATION}/" || true - elif [ -d "${LEGACY2}" ] && [ "${LEGACY2}" != "${DATA_LOCATION}" ] && [ -n "$(ls -A "${LEGACY2}" 2>/dev/null || true)" ]; then - bashio::log.notice "Migrating legacy data from ${LEGACY2} to ${DATA_LOCATION}" - cp -a "${LEGACY2}/." "${DATA_LOCATION}/" || true - fi +if [ -z "$(ls -A "${DATA_LOCATION}" 2> /dev/null || true)" ]; then + if [ -d "${LEGACY1}" ] && [ -n "$(ls -A "${LEGACY1}" 2> /dev/null || true)" ]; then + bashio::log.notice "Migrating legacy data from ${LEGACY1} to ${DATA_LOCATION}" + cp -a "${LEGACY1}/." "${DATA_LOCATION}/" || true + elif [ -d "${LEGACY2}" ] && [ "${LEGACY2}" != "${DATA_LOCATION}" ] && [ -n "$(ls -A "${LEGACY2}" 2> /dev/null || true)" ]; then + bashio::log.notice "Migrating legacy data from ${LEGACY2} to ${DATA_LOCATION}" + cp -a "${LEGACY2}/." "${DATA_LOCATION}/" || true + fi fi mkdir -p "${DATA_LOCATION}/config" "${DATA_LOCATION}/clips" "${DATA_LOCATION}/logs" "${DATA_LOCATION}/cache" || true diff --git a/birdnet-pipy/rootfs/etc/cont-init.d/10-config.sh b/birdnet-pipy/rootfs/etc/cont-init.d/10-config.sh index 3c5a51dc58..499e322790 100755 --- a/birdnet-pipy/rootfs/etc/cont-init.d/10-config.sh +++ b/birdnet-pipy/rootfs/etc/cont-init.d/10-config.sh @@ -7,10 +7,10 @@ CFG_DIR="${DATA_DIR}/config" SETTINGS="${CFG_DIR}/user_settings.json" if [ -f "$SETTINGS" ]; then - if ! grep -q 'detection' "$SETTINGS"; then - bak="${SETTINGS}.bak" - [ -e "$bak" ] && bak="${SETTINGS}.bak.$(date -u +%Y%m%dT%H%M%SZ)" - mv -f -- "$SETTINGS" "$bak" - echo "WARNING: Erroneous file detected: '$SETTINGS' did not contain 'detection' and was renamed to '$bak'." >&2 - fi + if ! grep -q 'detection' "$SETTINGS"; then + bak="${SETTINGS}.bak" + [ -e "$bak" ] && bak="${SETTINGS}.bak.$(date -u +%Y%m%dT%H%M%SZ)" + mv -f -- "$SETTINGS" "$bak" + echo "WARNING: Erroneous file detected: '$SETTINGS' did not contain 'detection' and was renamed to '$bak'." >&2 + fi fi diff --git a/birdnet-pipy/rootfs/etc/cont-init.d/15-audio_perms.sh b/birdnet-pipy/rootfs/etc/cont-init.d/15-audio_perms.sh index 3752d6d86d..723001cc7c 100755 --- a/birdnet-pipy/rootfs/etc/cont-init.d/15-audio_perms.sh +++ b/birdnet-pipy/rootfs/etc/cont-init.d/15-audio_perms.sh @@ -3,21 +3,21 @@ set -euo pipefail SND_GID="" -if [ -e /dev/snd ] && command -v stat >/dev/null 2>&1; then - SND_GID="$(stat -c '%g' /dev/snd 2>/dev/null || true)" +if [ -e /dev/snd ] && command -v stat > /dev/null 2>&1; then + SND_GID="$(stat -c '%g' /dev/snd 2> /dev/null || true)" fi -if [ -n "${SND_GID}" ] && getent group audio >/dev/null 2>&1; then - current_gid="$(getent group audio | cut -d: -f3 || true)" - if [ -n "${current_gid}" ] && [ "${current_gid}" != "${SND_GID}" ]; then - groupmod -g "${SND_GID}" audio 2>/dev/null || true - fi +if [ -n "${SND_GID}" ] && getent group audio > /dev/null 2>&1; then + current_gid="$(getent group audio | cut -d: -f3 || true)" + if [ -n "${current_gid}" ] && [ "${current_gid}" != "${SND_GID}" ]; then + groupmod -g "${SND_GID}" audio 2> /dev/null || true + fi fi for u in root nginx www-data icecast2; do - if id "${u}" >/dev/null 2>&1; then - usermod -aG audio "${u}" 2>/dev/null || true - fi + if id "${u}" > /dev/null 2>&1; then + usermod -aG audio "${u}" 2> /dev/null || true + fi done # Create /run/pulse/native symlink if the PulseAudio socket is elsewhere @@ -25,21 +25,21 @@ done PULSE_SOCK="${PULSE_SERVER:-}" PULSE_SOCK="${PULSE_SOCK#unix:}" if [ -n "${PULSE_SOCK}" ] && [ -S "${PULSE_SOCK}" ] && [ ! -S /run/pulse/native ]; then - mkdir -p /run/pulse - ln -sf "${PULSE_SOCK}" /run/pulse/native + mkdir -p /run/pulse + ln -sf "${PULSE_SOCK}" /run/pulse/native fi # Copy PulseAudio cookie for the icecast2 user so it can authenticate -if id icecast2 >/dev/null 2>&1; then - ICECAST_HOME="$(getent passwd icecast2 | cut -d: -f6)" - if [ -n "${ICECAST_HOME}" ]; then - for cookie in /config/.config/pulse/cookie /root/.config/pulse/cookie; do - if [ -f "${cookie}" ]; then - mkdir -p "${ICECAST_HOME}/.config/pulse" - cp "${cookie}" "${ICECAST_HOME}/.config/pulse/cookie" - chown icecast2 "${ICECAST_HOME}/.config/pulse" "${ICECAST_HOME}/.config/pulse/cookie" - break - fi - done - fi +if id icecast2 > /dev/null 2>&1; then + ICECAST_HOME="$(getent passwd icecast2 | cut -d: -f6)" + if [ -n "${ICECAST_HOME}" ]; then + for cookie in /config/.config/pulse/cookie /root/.config/pulse/cookie; do + if [ -f "${cookie}" ]; then + mkdir -p "${ICECAST_HOME}/.config/pulse" + cp "${cookie}" "${ICECAST_HOME}/.config/pulse/cookie" + chown icecast2 "${ICECAST_HOME}/.config/pulse" "${ICECAST_HOME}/.config/pulse/cookie" + break + fi + done + fi fi diff --git a/birdnet-pipy/rootfs/etc/services.d/api/run b/birdnet-pipy/rootfs/etc/services.d/api/run old mode 100644 new mode 100755 index 27ac1b2eaf..05291fde8a --- a/birdnet-pipy/rootfs/etc/services.d/api/run +++ b/birdnet-pipy/rootfs/etc/services.d/api/run @@ -10,10 +10,10 @@ cd /app # and core.main reach the API locally, satisfying the wait_for in nginx/run + # main/run). Heavy admin jobs cooperatively yield to keep this worker live. exec gunicorn wsgi:application \ - --worker-class geventwebsocket.gunicorn.workers.GeventWebSocketWorker \ - --workers 1 \ - --bind 127.0.0.1:5002 \ - --timeout 120 \ - --graceful-timeout 30 \ - --keep-alive 65 \ - --error-logfile - + --worker-class geventwebsocket.gunicorn.workers.GeventWebSocketWorker \ + --workers 1 \ + --bind 127.0.0.1:5002 \ + --timeout 120 \ + --graceful-timeout 30 \ + --keep-alive 65 \ + --error-logfile - diff --git a/birdnet-pipy/rootfs/etc/services.d/icecast/run b/birdnet-pipy/rootfs/etc/services.d/icecast/run old mode 100644 new mode 100755 diff --git a/birdnet-pipy/rootfs/etc/services.d/main/run b/birdnet-pipy/rootfs/etc/services.d/main/run old mode 100644 new mode 100755 diff --git a/birdnet-pipy/rootfs/etc/services.d/model/run b/birdnet-pipy/rootfs/etc/services.d/model/run old mode 100644 new mode 100755 diff --git a/birdnet-pipy/rootfs/etc/services.d/nginx/run b/birdnet-pipy/rootfs/etc/services.d/nginx/run old mode 100644 new mode 100755 diff --git a/bitwarden/CHANGELOG.md b/bitwarden/CHANGELOG.md index 39e5e1da0d..d02caa9fa7 100644 --- a/bitwarden/CHANGELOG.md +++ b/bitwarden/CHANGELOG.md @@ -1,10 +1,10 @@ - + ## 1.37.2 (2026-08-29) - Update to latest version from dani-garcia/bitwarden_rs (changelog : https://github.com/dani-garcia/bitwarden_rs/releases) - + ## 1.37.1 (2026-08-01) - Update to latest version from dani-garcia/bitwarden_rs (changelog : https://github.com/dani-garcia/bitwarden_rs/releases) - + ## 1.37.0 (2026-07-25) - Update to latest version from dani-garcia/bitwarden_rs (changelog : https://github.com/dani-garcia/bitwarden_rs/releases) diff --git a/bitwarden/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/run b/bitwarden/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/run old mode 100644 new mode 100755 diff --git a/bitwarden/rootfs/etc/s6-overlay/s6-rc.d/nginx/run b/bitwarden/rootfs/etc/s6-overlay/s6-rc.d/nginx/run old mode 100644 new mode 100755 diff --git a/bitwarden/rootfs/etc/s6-overlay/s6-rc.d/vaultwarden/run b/bitwarden/rootfs/etc/s6-overlay/s6-rc.d/vaultwarden/run old mode 100644 new mode 100755 index 45cf56410e..28f2283883 --- a/bitwarden/rootfs/etc/s6-overlay/s6-rc.d/vaultwarden/run +++ b/bitwarden/rootfs/etc/s6-overlay/s6-rc.d/vaultwarden/run @@ -21,19 +21,19 @@ export ROCKET_SECRET_KEY="${secret_key}" # Find the matching log level if bashio::config.has_value 'log_level'; then case "$(bashio::string.lower "$(bashio::config 'log_level')")" in - all|trace) + all | trace) log_level="trace" ;; debug) log_level="debug" ;; - info|notice) + info | notice) log_level="info" ;; warning) log_level="warn" ;; - error|fatal) + error | fatal) log_level="error" ;; off) diff --git a/booksonic_air/README.md b/booksonic_air/README.md index 03138da482..5665fc1fa5 100644 --- a/booksonic_air/README.md +++ b/booksonic_air/README.md @@ -64,7 +64,7 @@ Default credentials are shown in the startup logs. ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/browser_brave/CHANGELOG.md b/browser_brave/CHANGELOG.md index 7d878e7189..03a7b5d8bd 100644 --- a/browser_brave/CHANGELOG.md +++ b/browser_brave/CHANGELOG.md @@ -1,46 +1,46 @@ - + ## 1.94.121-ls127 (2026-09-05) - Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases) - + ## 1.94.117-ls125 (2026-08-29) - Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases) - + ## 1.93.138-ls124 (2026-08-22) - Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases) - + ## 1.93.136-ls122 (2026-08-13) - Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases) - + ## 1.93.134-ls121 (2026-08-08) - Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases) - + ## 1.93.129-ls119 (2026-08-01) - Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases) - + ## 1.92.144-ls117 (2026-07-25) - Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases) - + ## 1.92.141-ls115 (2026-07-18) - Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases) - + ## 1.92.140-ls113 (2026-07-16) - Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases) - + ## 1.92.139-ls112 (2026-07-11) - Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases) - + ## 1.92.134-ls109 (2026-07-04) - Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases) - + ## 1.91.180-ls108 (2026-06-27) - Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases) - + ## 1.91.175-ls106 (2026-06-20) - Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases) - + ## 1.91.172-ls105 (2026-06-13) - Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases) - + ## 1.91.171-ls104 (2026-06-11) - Update to latest version from linuxserver/docker-brave (changelog : https://github.com/linuxserver/docker-brave/releases) ## 1.91.168-ls103 (2026-06-05) diff --git a/browser_chromium/CHANGELOG.md b/browser_chromium/CHANGELOG.md index 88ca5d4b11..8b91b92133 100644 --- a/browser_chromium/CHANGELOG.md +++ b/browser_chromium/CHANGELOG.md @@ -1,12 +1,12 @@ - + ## 2026.09.05 (2026-09-05) - Update to latest version from linuxserver/docker-chromium (changelog : https://github.com/linuxserver/docker-chromium/releases) - Upstream tag : version-d39975b5 - + ## 2026.08.13 (2026-08-13) - Update to latest version from linuxserver/docker-chromium (changelog : https://github.com/linuxserver/docker-chromium/releases) - Upstream tag : version-e8713bf7 - + ## 2026.08.01.1 (2026-08-01) - Update to latest version from linuxserver/docker-chromium (changelog : https://github.com/linuxserver/docker-chromium/releases) - Upstream tag : version-e2e1ec9c @@ -14,25 +14,25 @@ - Version renamed from `version-bf9e0b4f`, which Home Assistant could not order and therefore could not reliably offer as an update: the previous version held no number that could order it, so the date of this change is used. The addon itself and the upstream version it tracks are unchanged - + ## version-bf9e0b4f (2026-07-25) - Update to latest version from linuxserver/docker-chromium (changelog : https://github.com/linuxserver/docker-chromium/releases) - + ## version-ae9a7fca (2026-07-16) - Update to latest version from linuxserver/docker-chromium (changelog : https://github.com/linuxserver/docker-chromium/releases) - + ## version-30a7c401 (2026-07-11) - Update to latest version from linuxserver/docker-chromium (changelog : https://github.com/linuxserver/docker-chromium/releases) - + ## version-7148c2a3 (2026-07-04) - Update to latest version from linuxserver/docker-chromium (changelog : https://github.com/linuxserver/docker-chromium/releases) - + ## version-ec868334 (2026-06-27) - Update to latest version from linuxserver/docker-chromium (changelog : https://github.com/linuxserver/docker-chromium/releases) - + ## version-b9b82d3e (2026-06-20) - Update to latest version from linuxserver/docker-chromium (changelog : https://github.com/linuxserver/docker-chromium/releases) - + ## version-cca5154d (2026-06-11) - Update to latest version from linuxserver/docker-chromium (changelog : https://github.com/linuxserver/docker-chromium/releases) ## version-89f88890 (2026-06-05) diff --git a/browser_chromium/rootfs/etc/cont-init.d/20-folders.sh b/browser_chromium/rootfs/etc/cont-init.d/20-folders.sh old mode 100755 new mode 100644 index 242d8446dd..f95c497f33 --- a/browser_chromium/rootfs/etc/cont-init.d/20-folders.sh +++ b/browser_chromium/rootfs/etc/cont-init.d/20-folders.sh @@ -7,7 +7,6 @@ set -e PUID=$(bashio::config "PUID") PGID=$(bashio::config "PGID") - # Create cache #mkdir -p /.cache #chmod 755 /.cache diff --git a/browser_chromium/rootfs/etc/usr/bin/wrapped-chromium b/browser_chromium/rootfs/etc/usr/bin/wrapped-chromium index 467bea4e74..f26f396210 100644 --- a/browser_chromium/rootfs/etc/usr/bin/wrapped-chromium +++ b/browser_chromium/rootfs/etc/usr/bin/wrapped-chromium @@ -5,12 +5,12 @@ set -Eeuo pipefail # Resolve chromium binary (LSIO uses this path) if [[ -x /usr/lib/chromium/chromium ]]; then - BIN=/usr/lib/chromium/chromium + BIN=/usr/lib/chromium/chromium elif command -v chromium >/dev/null 2>&1; then - BIN="$(command -v chromium)" + BIN="$(command -v chromium)" else - echo "ERROR: chromium binary not found" >&2 - exit 127 + echo "ERROR: chromium binary not found" >&2 + exit 127 fi # Fixed profile dir as requested @@ -19,7 +19,7 @@ mkdir -p "${USER_DATA_DIR}" # Cleanup stale locks if chromium is not already running if ! pgrep -f 'chromium' >/dev/null 2>&1; then - rm -f "${USER_DATA_DIR}/Singleton"* || true + rm -f "${USER_DATA_DIR}/Singleton"* || true fi # Detect seccomp mode (0 = disabled) @@ -27,22 +27,22 @@ seccomp_mode="$(awk -F':' '/^Seccomp:/{gsub(/[[:space:]]/,"",$2); print $2}' /pr # Base arguments (exactly what you requested + required safety flags) args=( - --remote-debugging-address=0.0.0.0 - --remote-debugging-port=9221 - --user-data-dir="${USER_DATA_DIR}" - --disable-dev-shm-usage - --no-first-run - --no-default-browser-check - --disable-background-networking - --disable-sync - --password-store=basic - "--simulate-outdated-no-au=Tue, 31 Dec 2099 23:59:59 GMT" - --start-maximized + --remote-debugging-address=0.0.0.0 + --remote-debugging-port=9221 + --user-data-dir="${USER_DATA_DIR}" + --disable-dev-shm-usage + --no-first-run + --no-default-browser-check + --disable-background-networking + --disable-sync + --password-store=basic + "--simulate-outdated-no-au=Tue, 31 Dec 2099 23:59:59 GMT" + --start-maximized ) # Container reality: sandbox usually breaks unless seccomp is fully disabled if [[ "${seccomp_mode}" != "0" ]]; then - args+=( --no-sandbox --test-type ) + args+=(--no-sandbox --test-type) fi # IMPORTANT: diff --git a/browserless_chrome/CHANGELOG.md b/browserless_chrome/CHANGELOG.md index 09d818d650..4ebe1e607e 100644 --- a/browserless_chrome/CHANGELOG.md +++ b/browserless_chrome/CHANGELOG.md @@ -1,37 +1,37 @@ - + ## 2.56.3 (2026-09-05) - Update to latest version from browserless/chrome (changelog : https://github.com/browserless/chrome/releases) - + ## 2.56.0 (2026-08-22) - Update to latest version from browserless/chrome (changelog : https://github.com/browserless/chrome/releases) - + ## 2.55.4 (2026-08-13) - Update to latest version from browserless/chrome (changelog : https://github.com/browserless/chrome/releases) - + ## 2.55.3 (2026-08-08) - Update to latest version from browserless/chrome (changelog : https://github.com/browserless/chrome/releases) - + ## 2.55.2 (2026-08-01) - Update to latest version from browserless/chrome (changelog : https://github.com/browserless/chrome/releases) - + ## 2.55.0 (2026-07-16) - Update to latest version from browserless/chrome (changelog : https://github.com/browserless/chrome/releases) - + ## 2.54.2 (2026-07-04) - Update to latest version from browserless/chrome (changelog : https://github.com/browserless/chrome/releases) - + ## 2.54.1 (2026-06-23) - Update to latest version from browserless/chrome (changelog : https://github.com/browserless/chrome/releases) - + ## 2.54.0 (2026-06-20) - Update to latest version from browserless/chrome (changelog : https://github.com/browserless/chrome/releases) - + ## 2.52.2 (2026-06-17) - Update to latest version from browserless/chrome (changelog : https://github.com/browserless/chrome/releases) - + ## 2.52.1 (2026-06-13) - Update to latest version from browserless/chrome (changelog : https://github.com/browserless/chrome/releases) - + ## 2.52.0 (2026-06-11) - Update to latest version from browserless/chrome (changelog : https://github.com/browserless/chrome/releases) ## 2.51.0 (2026-06-05) diff --git a/calibre/CHANGELOG.md b/calibre/CHANGELOG.md index e5e55a0e07..aefdfcd98e 100644 --- a/calibre/CHANGELOG.md +++ b/calibre/CHANGELOG.md @@ -1,16 +1,16 @@ - + ## 9.14.0 (2026-08-29) - Update to latest version from linuxserver/docker-calibre (changelog : https://github.com/linuxserver/docker-calibre/releases) - + ## 9.13.0 (2026-08-08) - Update to latest version from linuxserver/docker-calibre (changelog : https://github.com/linuxserver/docker-calibre/releases) - + ## 9.12.0 (2026-08-01) - Update to latest version from linuxserver/docker-calibre (changelog : https://github.com/linuxserver/docker-calibre/releases) - + ## 9.11.0 (2026-07-04) - Update to latest version from linuxserver/docker-calibre (changelog : https://github.com/linuxserver/docker-calibre/releases) - + ## 9.10.0 (2026-06-27) - Update to latest version from linuxserver/docker-calibre (changelog : https://github.com/linuxserver/docker-calibre/releases) diff --git a/calibre/README.md b/calibre/README.md index d4cb2ca986..d9bf946500 100644 --- a/calibre/README.md +++ b/calibre/README.md @@ -62,7 +62,7 @@ Please read the upstream container documentation for further info: https://githu ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/calibre_web/CHANGELOG.md b/calibre_web/CHANGELOG.md index ad0f1d06b5..4ada82528a 100644 --- a/calibre_web/CHANGELOG.md +++ b/calibre_web/CHANGELOG.md @@ -1,4 +1,4 @@ - + ## 0.6.27.4 (2026-09-04) - Fix: Kobo sync could not be enabled, failing with "Kepubify binary not found" even when the path was set by hand. The LinuxServer base image installs the converter as `/usr/bin/kepubify` with `curl -o`, which leaves it mode 0644 and gives it a name calibre-web does not accept : `binary_helper.py` only takes `kepubify-linux-64bit` or `kepubify-linux-32bit`, and only when `os.access(X_OK)` passes. The addon now makes the binary executable and publishes it as `/opt/kepubify/kepubify-linux-64bit`, the directory calibre-web's own autodetection already probes, so the path is filled in without any manual step (https://github.com/alexbelgium/hassio-addons/issues/3040) - Fix: on installs created before that change, calibre-web had already run its autodetection once, found nothing usable and stored an empty path, and it never retries. An empty path is now reset so calibre-web detects the converter itself at the next start. A path set by hand is left alone diff --git a/calibre_web/README.md b/calibre_web/README.md index 9de33bf06b..089cfb2bf2 100644 --- a/calibre_web/README.md +++ b/calibre_web/README.md @@ -62,7 +62,7 @@ Default password: admin123 ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | @@ -99,7 +99,7 @@ This addon supports mounting both local drives and remote SMB shares: ### Optional Calibre-Web features -Calibre-Web documents optional extras that a manual installation adds with `pip install calibreweb[metadata]` and similar. **You do not need to install anything here**: the LinuxServer base image this add-on builds on installs Calibre-Web's `requirements.txt` *and* its full `optional-requirements.txt` into the application's virtualenv, so the gdrive, gmail, goodreads, ldap, oauth, metadata, comics and kobo dependencies are all present already. Running `pip install calibreweb[...]` inside the container is not a supported way to enable them: it installs the PyPI distribution of Calibre-Web over an installation that already has those dependencies, and it can disturb the versions the base image pinned. It is also thrown away, because the Supervisor recreates the add-on container on restart. +Calibre-Web documents optional extras that a manual installation adds with `pip install calibreweb[metadata]` and similar. **You do not need to install anything here**: the LinuxServer base image this add-on builds on installs Calibre-Web's `requirements.txt` _and_ its full `optional-requirements.txt` into the application's virtualenv, so the gdrive, gmail, goodreads, ldap, oauth, metadata, comics and kobo dependencies are all present already. Running `pip install calibreweb[...]` inside the container is not a supported way to enable them: it installs the PyPI distribution of Calibre-Web over an installation that already has those dependencies, and it can disturb the versions the base image pinned. It is also thrown away, because the Supervisor recreates the add-on container on restart. Optional features are switched on in the Calibre-Web web interface, not in the add-on options, under `Admin` -> `Basic Configuration` -> `Feature Configuration` (for example `Enable Uploads`, `Enable Kobo sync`, `Use Goodreads`). diff --git a/calibre_web/rootfs/etc/cont-init.d/80-configuration.sh b/calibre_web/rootfs/etc/cont-init.d/80-configuration.sh index 1edd958d91..15c5b48acb 100755 --- a/calibre_web/rootfs/etc/cont-init.d/80-configuration.sh +++ b/calibre_web/rootfs/etc/cont-init.d/80-configuration.sh @@ -30,16 +30,16 @@ else # duplicates it can leave behind are entries calibre-web skips or already trusts. # The column only exists once calibre-web 0.6.27+ has migrated app.db and cont-init runs # before calibre-web, so a failure here is not fatal : the next start applies it. - trusted_ips_error=$(sqlite3 /config/app.db "update settings set config_reverse_proxy_trusted_ips='127.0.0.1,::1,::ffff:127.0.0.1,172.30.32.0/23,::ffff:172.30.32.0/119,'||coalesce(config_reverse_proxy_trusted_ips,'') where coalesce(config_reverse_proxy_trusted_ips,'') not like '%::ffff:172.30.32.0/119%'" 2>&1) || - bashio::log.warning "Could not set the ingress trusted ip list, it will be applied at next start (${trusted_ips_error})" + trusted_ips_error=$(sqlite3 /config/app.db "update settings set config_reverse_proxy_trusted_ips='127.0.0.1,::1,::ffff:127.0.0.1,172.30.32.0/23,::ffff:172.30.32.0/119,'||coalesce(config_reverse_proxy_trusted_ips,'') where coalesce(config_reverse_proxy_trusted_ips,'') not like '%::ffff:172.30.32.0/119%'" 2>&1) \ + || bashio::log.warning "Could not set the ingress trusted ip list, it will be applied at next start (${trusted_ips_error})" # Calibre-web autodetects kepubify only while this setting is still NULL. On every install # that predates the Dockerfile fix above, that detection already ran, found nothing usable and # stored an empty string, so it is never retried. Put an empty value back to NULL and # calibre-web detects /opt/kepubify itself when it starts, a few seconds after this runs. # A path the user set by hand is not empty and is left alone. - kepubify_error=$(sqlite3 /config/app.db "update settings set config_kepubifypath = NULL where config_kepubifypath = ''" 2>&1) || - bashio::log.warning "Could not reset the kepubify path, it will be applied at next start (${kepubify_error})" + kepubify_error=$(sqlite3 /config/app.db "update settings set config_kepubifypath = NULL where config_kepubifypath = ''" 2>&1) \ + || bashio::log.warning "Could not reset the kepubify path, it will be applied at next start (${kepubify_error})" fi bashio::log.info "Default username:password is admin:admin123" diff --git a/changedetection.io/CHANGELOG.md b/changedetection.io/CHANGELOG.md index 57be3b2e01..aa222997db 100644 --- a/changedetection.io/CHANGELOG.md +++ b/changedetection.io/CHANGELOG.md @@ -1,7 +1,7 @@ - + ## 0.60.3 (2026-09-05) - Update to latest version from linuxserver/docker-changedetection.io (changelog : https://github.com/linuxserver/docker-changedetection.io/releases) - + ## 0.55.8 (2026-07-16) - Update to latest version from linuxserver/docker-changedetection.io (changelog : https://github.com/linuxserver/docker-changedetection.io/releases) diff --git a/changedetection.io/README.md b/changedetection.io/README.md index d3bcbbdcae..7b99b738d8 100644 --- a/changedetection.io/README.md +++ b/changedetection.io/README.md @@ -52,7 +52,7 @@ You can add a shortcut pointing to your Changedetection.io instance with the fol ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/changedetection.io/rootfs/etc/services.d/nginx/run b/changedetection.io/rootfs/etc/services.d/nginx/run old mode 100644 new mode 100755 diff --git a/claude_desktop/CHANGELOG.md b/claude_desktop/CHANGELOG.md index 4818a55c38..79dd2c0ae0 100644 --- a/claude_desktop/CHANGELOG.md +++ b/claude_desktop/CHANGELOG.md @@ -1,12 +1,12 @@ - + ## 07308545.6 (2026-09-05) - Update to latest version from aaddrick/claude-desktop-debian (changelog : https://github.com/aaddrick/claude-desktop-debian/releases) - Upstream tag : v3.2.3+claude1.40609.1 - + ## 07308545.5 (2026-08-29) - Update to latest version from aaddrick/claude-desktop-debian (changelog : https://github.com/aaddrick/claude-desktop-debian/releases) - Upstream tag : v3.2.2+claude1.37937.3 - + ## 07308545.4 (2026-08-22) - Update to latest version from aaddrick/claude-desktop-debian (changelog : https://github.com/aaddrick/claude-desktop-debian/releases) - Upstream tag : v3.2.2+claude1.32885.1 @@ -71,7 +71,7 @@ ## 07308545.1 (17-08-2026) - Minor bugs fixed - + ## 07308543.1 (17-08-2026) - Fix the "For your security, sign in again" prompt recurring on every restart again. The v1.37 `safeStorage` patch (`86-claude_safestorage.sh` / `claude-safestorage-patch.js`) only knew how @@ -94,11 +94,11 @@ ## 07308545 (2026-08-15) - Update to latest version from aaddrick/claude-desktop-debian (changelog : https://github.com/aaddrick/claude-desktop-debian/releases) - Upstream tag : v3.2.2+claude1.30096.1 - + ## 07308544 (2026-08-13) - Update to latest version from aaddrick/claude-desktop-debian (changelog : https://github.com/aaddrick/claude-desktop-debian/releases) - Upstream tag : v3.2.2+claude1.28929.0 - + ## 07308543 (2026-08-08) - Update to latest version from linuxserver/docker-baseimage-selkies (changelog : https://github.com/linuxserver/docker-baseimage-selkies/releases) - Upstream tag : debiantrixie-version-07308543 @@ -185,10 +185,10 @@ ## 2026.08.02 (02-08-2026) - Minor bugs fixed - + ## ubunturesolute-version-3a10bef7 (2026-08-01) - Update to latest version from linuxserver/docker-baseimage-selkies (changelog : https://github.com/linuxserver/docker-baseimage-selkies/releases) - + ## kali-version-e963b19b (2026-08-01) - Update to latest version from linuxserver/docker-baseimage-selkies (changelog : https://github.com/linuxserver/docker-baseimage-selkies/releases) ## 1.37 (28-07-2026) @@ -199,7 +199,7 @@ - **`gnome-keyring` stays out of the image.** Re-adding it would reintroduce the first-boot keyring password prompt that blocks Claude Desktop from launching at all. This route needs no keyring, no D-Bus Secret Service, no daemon and no password, so no prompt can appear. The trade-off is unchanged from v1.35 and is inherent to the `basic` backend: its key is fixed rather than gated by a keyring, so any process that can read the persistent `$HOME/.config/Claude` profile can recover the stored credentials. - **One-time step after upgrading.** The previously stored session is already stale, so a single sign-in is still needed once after this update; it then persists across restarts. - + ## 1.36.4 (28-07-2026) - Fix Selkies dying with a Rust `RuntimeDirNotSet` unwrap panic just after `Data WebSocket Server listening on port 8081`, and the data websocket then being proxied to the wrong port. Upstream relies on s6-rc ordering: `init-selkies-config` publishes `XDG_RUNTIME_DIR` and `CUSTOM_WS_PORT` into the s6 envdir and `svc-selkies` starts afterwards. The add-on entrypoint replaces s6-overlay and starts every `s6-rc.d` run script in parallel with no dependency graph, so Selkies can snapshot the envdir before that oneshot has written to it -- which is why it bound port 8081 (its own default) instead of the 8082 nginx proxies to, and why its Wayland compositor found no runtime directory to bind a socket in. `20-folders.sh` now exports both variables inside each run script, where no start ordering can lose them, and corrects the base image's `$HOME/.XDG` override where that write happens instead of appending a correction after the `exit 0` that the oneshot-tolerance block adds -- which meant the correction never ran on any boot after the first. @@ -210,7 +210,7 @@ ## 1.36.2 (28-07-2026) - Minor bugs fixed - + ## 1.36.1 (27-07-2026) - Fix the Codex CLI install failing on every boot with `Verified Codex installation failed; Codex is unavailable this boot`, leaving `install_codex_cli` permanently non-functional. The download, its SHA-256 verification, and the extraction all succeeded; the chain broke at the final step, which validates the candidate binary by running `--version` as the `abc` runtime user. `mktemp -d` creates its directory `0700 root:root`, and `abc` cannot traverse a root-only directory, so executing the staged binary failed with `unable to exec: Permission denied` (exit 126) before it could be moved into place. Reproduced and fixed by making the staging directory traversable (`chmod 0755`) immediately after `mktemp`; verified on a live add-on container, where the same probe goes from exit 126 to success once the mode is widened. Nothing secret is staged there — the public release archive and the extracted binary, both world-readable upstream artifacts — and the existing `cleanup()` trap still removes the directory on exit. The validation deliberately keeps running as `abc` rather than root, so the binary is exercised as the identity that will actually run it. @@ -240,10 +240,10 @@ ## 1.33 (22-07-2026) - Add cowork virtualization support: `qemu-system-x86` and `ovmf` (Bookworm main, installed via apt) plus `virtiofsd` for sharing the workspace into the sandbox microVM. `virtiofsd` is only packaged for Debian trixie/sid, not Bookworm or bookworm-backports, and its trixie `.deb` links a newer GLIBC than this add-on's Bookworm runtime — so it now gets built from the pinned crates.io release (`1.14.0`) in a dedicated `virtiofsd-builder` stage, the same GLIBC-safe pattern already used for `rtk` and `tokensave`. Its build deps (`libseccomp-dev`, `libcap-ng-dev`, `pkg-config`, `clang`, `libclang-dev`) live only in that builder stage; only the runtime shared libs (`libseccomp2`, `libcap-ng0`) ship in the final image. The built binary is validated with `--version` at build time alongside `rtk`/`tokensave`, so a GLIBC/ABI mismatch fails the image build instead of surfacing at container start. Docker itself is deliberately not installed: this base image already ships Docker-in-Docker (`docker-ce`/`containerd.io` from Docker's own apt repo, started via the pre-existing `START_DOCKER` env var) — an initial attempt to also `apt-get install docker.io` broke the build, since Debian's package pulls in `containerd`/`runc`, which apt refuses to install alongside the base image's already-installed `containerd.io` (`Conflicts`). - + ## ubunturesolute-version-8208e985 (2026-07-21) - Update to latest version from linuxserver/docker-baseimage-selkies (changelog : https://github.com/linuxserver/docker-baseimage-selkies/releases) - + ## kali-version-9ad48e7a (2026-07-18) - Update to latest version from linuxserver/docker-baseimage-selkies (changelog : https://github.com/linuxserver/docker-baseimage-selkies/releases) ## 1.32 (17-07-2026) diff --git a/claude_desktop/rootfs/defaults/autostart b/claude_desktop/rootfs/defaults/autostart index aa1fab8596..7b337c2134 100644 --- a/claude_desktop/rootfs/defaults/autostart +++ b/claude_desktop/rootfs/defaults/autostart @@ -55,9 +55,9 @@ # shared memory into ordinary files for no benefit. If the size cannot be determined, keep the # flag — the crash it prevents is worse than the overhead it costs. SHM_FLAGS="--disable-dev-shm-usage" -SHM_KB="$(df -k /dev/shm 2> /dev/null | awk 'NR==2 {print $2}')" +SHM_KB="$(df -k /dev/shm 2>/dev/null | awk 'NR==2 {print $2}')" if [ -n "$SHM_KB" ] && [ "$SHM_KB" -ge 262144 ]; then - SHM_FLAGS="" + SHM_FLAGS="" fi # SHM_FLAGS must stay unquoted so it expands to a separate argument, or to nothing at all. diff --git a/claude_desktop/rootfs/etc/cont-init.d/81-codex_cli.sh b/claude_desktop/rootfs/etc/cont-init.d/81-codex_cli.sh index 988483dfd6..dba942085c 100755 --- a/claude_desktop/rootfs/etc/cont-init.d/81-codex_cli.sh +++ b/claude_desktop/rootfs/etc/cont-init.d/81-codex_cli.sh @@ -141,7 +141,7 @@ release_info="" if curl -fsSL --retry 3 --retry-delay 2 --connect-timeout 10 --max-time 30 \ -o "$release_metadata" "$CODEX_RELEASE_API"; then release_info="$( - CODEX_ASSET="$CODEX_ASSET" python3 - "$release_metadata" <<'PY' 2> /dev/null || true + CODEX_ASSET="$CODEX_ASSET" python3 - "$release_metadata" << 'PY' 2> /dev/null || true import json import os import re @@ -249,7 +249,7 @@ fi { printf '#!/usr/bin/env bash\n' printf 'CODEX_REAL=%q\n' "$CODEX_REAL" - cat <<'SH' + cat << 'SH' RUNTIME_HOME="$(getent passwd abc | cut -d: -f6)" if [ -z "$RUNTIME_HOME" ]; then echo "codex: unable to resolve the abc runtime home" >&2 @@ -338,8 +338,7 @@ ln -sfn "$CODEX_BIN" "$CODEX_LINK" CODEX_SANDBOX_MODE="$(bashio::config 'codex_sandbox_mode' 'danger-full-access')" run_as_runtime_user mkdir -p "$RUNTIME_HOME/.codex" CODEX_SANDBOX_MODE="$CODEX_SANDBOX_MODE" RUNTIME_HOME="$RUNTIME_HOME" \ - run_as_runtime_user python3 - <<'PY' \ - || bashio::log.warning "Unable to update the managed Codex configuration block" + run_as_runtime_user python3 - << 'PY' || bashio::log.warning "Unable to update the managed Codex configuration block" import os import re import tomllib diff --git a/claude_desktop/rootfs/etc/cont-init.d/82-claude_tools.sh b/claude_desktop/rootfs/etc/cont-init.d/82-claude_tools.sh index b27aae7efa..3bb664ec36 100755 --- a/claude_desktop/rootfs/etc/cont-init.d/82-claude_tools.sh +++ b/claude_desktop/rootfs/etc/cont-init.d/82-claude_tools.sh @@ -30,7 +30,7 @@ manage_claude_md_block() { fi elif [ -f "$CLAUDE_MD" ] && grep -qF "$begin" "$CLAUDE_MD"; then bashio::log.info "Removing ${name} guidance from CLAUDE.md" - CLAUDE_MD="$CLAUDE_MD" BLOCK_NAME="$name" python3 - <<'PY' || bashio::log.warning "Unable to remove the ${name} guidance automatically" + CLAUDE_MD="$CLAUDE_MD" BLOCK_NAME="$name" python3 - << 'PY' || bashio::log.warning "Unable to remove the ${name} guidance automatically" import os import re from pathlib import Path @@ -58,7 +58,7 @@ PY manage_settings_hook() { # manage_settings_hook HOOK_EVENT="$1" HOOK_MATCHER="$2" HOOK_COMMAND="$3" HOOK_ACTION="$4" \ - python3 - <<'PY' || bashio::log.warning "Unable to update the $1 hook for '$3'" + python3 - << 'PY' || bashio::log.warning "Unable to update the $1 hook for '$3'" import json import os from pathlib import Path @@ -389,14 +389,14 @@ bashio::log.info "MCP servers for Claude Desktop: ${MCP_SERVERS_DESKTOP}" bashio::log.info "MCP servers for Claude Code: ${MCP_SERVERS_CODE}" HEADROOM_ENABLED="$HEADROOM_ENABLED" HEADROOM_BIN="$(command -v headroom || echo headroom)" \ - HEADROOM_HF_HOME="${HOME}/.headroom/hf" \ - TOKENSAVE_ENABLED="$TOKENSAVE_ENABLED" TOKENSAVE_BIN="$(command -v tokensave || echo tokensave)" \ - CODEX_ENABLED="$CODEX_ENABLED" CODEX_BIN="$CODEX_BIN" CODEX_SANDBOX_MODE="$CODEX_SANDBOX_MODE" \ - HA_MCP_ENABLED="$HA_MCP_ENABLED" HA_MCP_URL="$HA_MCP_URL" HA_MCP_TOKEN="$HA_MCP_TOKEN" \ - MCP_PROXY_BIN="$(command -v mcp-proxy || echo mcp-proxy)" \ - MCP_SERVERS_DESKTOP="$MCP_SERVERS_DESKTOP" MCP_SERVERS_CODE="$MCP_SERVERS_CODE" \ - CLAUDE_DESKTOP_CONFIG="$CLAUDE_DESKTOP_CONFIG" CLAUDE_CODE_CONFIG="$CLAUDE_CODE_CONFIG" \ - python3 - <<'PY' || bashio::log.warning "Unable to update the MCP server registrations automatically" +HEADROOM_HF_HOME="${HOME}/.headroom/hf" \ +TOKENSAVE_ENABLED="$TOKENSAVE_ENABLED" TOKENSAVE_BIN="$(command -v tokensave || echo tokensave)" \ +CODEX_ENABLED="$CODEX_ENABLED" CODEX_BIN="$CODEX_BIN" CODEX_SANDBOX_MODE="$CODEX_SANDBOX_MODE" \ +HA_MCP_ENABLED="$HA_MCP_ENABLED" HA_MCP_URL="$HA_MCP_URL" HA_MCP_TOKEN="$HA_MCP_TOKEN" \ +MCP_PROXY_BIN="$(command -v mcp-proxy || echo mcp-proxy)" \ +MCP_SERVERS_DESKTOP="$MCP_SERVERS_DESKTOP" MCP_SERVERS_CODE="$MCP_SERVERS_CODE" \ +CLAUDE_DESKTOP_CONFIG="$CLAUDE_DESKTOP_CONFIG" CLAUDE_CODE_CONFIG="$CLAUDE_CODE_CONFIG" \ + python3 - << 'PY' || bashio::log.warning "Unable to update the MCP server registrations automatically" import json import os from pathlib import Path @@ -607,7 +607,7 @@ PY # Guide Claude to actually use the Headroom compression tools so the MCP integration produces # real savings when transparent proxying is unavailable. if $HEADROOM_ENABLED; then - manage_claude_md_block headroom add <<'MD' + manage_claude_md_block headroom add << 'MD' ## Headroom context compression A local Headroom proxy (127.0.0.1:8787) backs the `headroom` MCP tools. To save context tokens: @@ -636,7 +636,7 @@ if $HEADROOM_ENABLED && bashio::config.true 'headroom_wrap_claude_code'; then else HEADROOM_ROUTE_ACTION="remove" fi -HEADROOM_ROUTE_ACTION="$HEADROOM_ROUTE_ACTION" python3 - <<'PY' || bashio::log.warning "Unable to manage the Claude Code proxy routing env" +HEADROOM_ROUTE_ACTION="$HEADROOM_ROUTE_ACTION" python3 - << 'PY' || bashio::log.warning "Unable to manage the Claude Code proxy routing env" import json import os from pathlib import Path @@ -703,7 +703,7 @@ manage_settings_hook PostToolUse "Bash|Grep|Glob|WebFetch" "$HEADROOM_HOOK_CMD" # Tell Claude Code that it can configure Home Assistant over the Core API via the shipped # `ha-cli` helper (no /config filesystem mount needed). if bashio::config.true 'enable_ha_api_helper'; then - manage_claude_md_block ha-api-helper add <<'MD' + manage_claude_md_block ha-api-helper add << 'MD' ## Configuring Home Assistant You can configure this Home Assistant instance through its Core API using the `ha-cli` @@ -731,7 +731,7 @@ fi # Registering the MCP server is not enough on its own: without guidance the model rarely reaches # for a second agent, the same gap the Headroom block above exists to close. if $CODEX_ENABLED; then - manage_claude_md_block codex add <<'MD' + manage_claude_md_block codex add << 'MD' ## Delegating to ChatGPT Codex The `codex` MCP server runs OpenAI's Codex agent locally, signed in with the user's ChatGPT diff --git a/claude_desktop/rootfs/etc/cont-init.d/83-claude_permissions.sh b/claude_desktop/rootfs/etc/cont-init.d/83-claude_permissions.sh index ecb016a544..2b94e1d5d3 100755 --- a/claude_desktop/rootfs/etc/cont-init.d/83-claude_permissions.sh +++ b/claude_desktop/rootfs/etc/cont-init.d/83-claude_permissions.sh @@ -19,7 +19,7 @@ esac # only while it still holds one of those managed values — a defaultMode the user set by hand # is never deleted. Ownership of the written file is reconciled by 84-claude_runtime_ownership.sh. mkdir -p "$(dirname "$SETTINGS_PATH")" -PERMISSION_MODE="$PERMISSION_MODE" SETTINGS_PATH="$SETTINGS_PATH" python3 - <<'PY' +PERMISSION_MODE="$PERMISSION_MODE" SETTINGS_PATH="$SETTINGS_PATH" python3 - << 'PY' import json import os from pathlib import Path diff --git a/claude_desktop/rootfs/etc/cont-init.d/86-claude_safestorage.sh b/claude_desktop/rootfs/etc/cont-init.d/86-claude_safestorage.sh index 19306a1160..3dfffcb68e 100755 --- a/claude_desktop/rootfs/etc/cont-init.d/86-claude_safestorage.sh +++ b/claude_desktop/rootfs/etc/cont-init.d/86-claude_safestorage.sh @@ -36,7 +36,7 @@ fi # archive stays unpatched, so every later boot would retry under a new pid and strand another # copy until the container runs out of space. cleanup_tmp() { - find "$(dirname "$ASAR")" -maxdepth 1 -name ".$(basename "$ASAR").addon-tmp.*" -delete 2>/dev/null || true + find "$(dirname "$ASAR")" -maxdepth 1 -name ".$(basename "$ASAR").addon-tmp.*" -delete 2> /dev/null || true } if output=$(timeout 120 node "$PATCHER" "$ASAR" 2>&1); then diff --git a/claude_desktop/rootfs/usr/local/bin/claude-tools-doctor.sh b/claude_desktop/rootfs/usr/local/bin/claude-tools-doctor.sh index 93aa5551c2..1d8c66b9ae 100755 --- a/claude_desktop/rootfs/usr/local/bin/claude-tools-doctor.sh +++ b/claude_desktop/rootfs/usr/local/bin/claude-tools-doctor.sh @@ -45,7 +45,7 @@ if [ "$(bashio::config 'permission_mode')" = "bypass" ]; then fi section "Claude Code permission state" -RUNTIME_HOME="$RUNTIME_HOME" python3 - <<'PY' +RUNTIME_HOME="$RUNTIME_HOME" python3 - << 'PY' import json import os from pathlib import Path @@ -66,7 +66,7 @@ else: PY section "MCP registrations (environment values redacted)" -RUNTIME_HOME="$RUNTIME_HOME" python3 - <<'PY' +RUNTIME_HOME="$RUNTIME_HOME" python3 - << 'PY' import json import os from pathlib import Path @@ -104,7 +104,7 @@ for path in paths: PY section "Claude Code hooks" -RUNTIME_HOME="$RUNTIME_HOME" python3 - <<'PY' +RUNTIME_HOME="$RUNTIME_HOME" python3 - << 'PY' import json import os from pathlib import Path diff --git a/claude_desktop/rootfs/usr/local/bin/codex-login b/claude_desktop/rootfs/usr/local/bin/codex-login old mode 100755 new mode 100644 diff --git a/claude_desktop/rootfs/usr/local/bin/ha-cli b/claude_desktop/rootfs/usr/local/bin/ha-cli old mode 100755 new mode 100644 index 6d521ef256..bc2962141d --- a/claude_desktop/rootfs/usr/local/bin/ha-cli +++ b/claude_desktop/rootfs/usr/local/bin/ha-cli @@ -96,7 +96,7 @@ def resolve_endpoint(): def _url(base, path): path = path.lstrip("/") if path.startswith("api/"): - path = path[len("api/"):] + path = path[len("api/") :] return base.rstrip("/") + "/" + path @@ -133,7 +133,9 @@ def rest(method, base, token, path, body=None): if body is not None: data = json.dumps(body).encode("utf-8") headers["Content-Type"] = "application/json" - req = urllib.request.Request(_url(base, path), data=data, method=method, headers=headers) + req = urllib.request.Request( + _url(base, path), data=data, method=method, headers=headers + ) try: with urllib.request.urlopen(req, timeout=30) as resp: text = resp.read().decode("utf-8") @@ -141,7 +143,9 @@ def rest(method, base, token, path, body=None): detail = exc.read().decode("utf-8", "replace").strip() sys.exit(f"ha-cli: HTTP {exc.code} {exc.reason} on {method} {path}\n{detail}") except urllib.error.URLError as exc: - sys.exit(f"ha-cli: cannot reach Home Assistant ({exc.reason}) on {method} {path}") + sys.exit( + f"ha-cli: cannot reach Home Assistant ({exc.reason}) on {method} {path}" + ) try: return json.loads(text) if text.strip() else None except ValueError: @@ -214,7 +218,9 @@ def main(argv): sys.exit("usage: ha-cli call [BODY]") domain, service = args[0].split(".", 1) body = _read_body(args[1]) if len(args) > 1 else None - _print(rest("POST", rest_base, token, f"services/{domain}/{service}", body or {})) + _print( + rest("POST", rest_base, token, f"services/{domain}/{service}", body or {}) + ) elif cmd == "states": path = f"states/{args[0]}" if args else "states" _print(rest("GET", rest_base, token, path)) diff --git a/claude_desktop/rootfs/usr/local/bin/headroom-posttooluse-compress.py b/claude_desktop/rootfs/usr/local/bin/headroom-posttooluse-compress.py old mode 100755 new mode 100644 index 987bef0114..1e84645814 --- a/claude_desktop/rootfs/usr/local/bin/headroom-posttooluse-compress.py +++ b/claude_desktop/rootfs/usr/local/bin/headroom-posttooluse-compress.py @@ -76,7 +76,11 @@ def main() -> int: # Find big string/array fields before paying the headroom import cost. def is_string_array(value): - return isinstance(value, list) and len(value) > ARRAY_KEEP and all(isinstance(v, str) for v in value) + return ( + isinstance(value, list) + and len(value) > ARRAY_KEEP + and all(isinstance(v, str) for v in value) + ) if isinstance(response, str): string_candidates = ["__whole__"] if len(response) >= MIN_CHARS else [] @@ -85,10 +89,14 @@ def main() -> int: string_candidates = [ key for key, value in response.items() - if key not in SKIP_KEYS and isinstance(value, str) and len(value) >= MIN_CHARS + if key not in SKIP_KEYS + and isinstance(value, str) + and len(value) >= MIN_CHARS ] array_candidates = [ - key for key, value in response.items() if key not in SKIP_KEYS and is_string_array(value) + key + for key, value in response.items() + if key not in SKIP_KEYS and is_string_array(value) ] else: string_candidates = [] diff --git a/cleanuparr/CHANGELOG.md b/cleanuparr/CHANGELOG.md index b3d7095134..ee4af799da 100644 --- a/cleanuparr/CHANGELOG.md +++ b/cleanuparr/CHANGELOG.md @@ -1,16 +1,16 @@ - + ## 2.10.5 (2026-08-13) - Update to latest version from Cleanuparr/Cleanuparr (changelog : https://github.com/Cleanuparr/Cleanuparr/releases) - + ## 2.10.3 (2026-08-08) - Update to latest version from Cleanuparr/Cleanuparr (changelog : https://github.com/Cleanuparr/Cleanuparr/releases) - + ## 2.10.2 (2026-08-01) - Update to latest version from Cleanuparr/Cleanuparr (changelog : https://github.com/Cleanuparr/Cleanuparr/releases) - + ## 2.9.16 (2026-07-11) - Update to latest version from Cleanuparr/Cleanuparr (changelog : https://github.com/Cleanuparr/Cleanuparr/releases) - + ## 2.9.14 (2026-06-20) - Update to latest version from Cleanuparr/Cleanuparr (changelog : https://github.com/Cleanuparr/Cleanuparr/releases) diff --git a/cleanuparr/README.md b/cleanuparr/README.md index 9637f0adec..40e11128b5 100644 --- a/cleanuparr/README.md +++ b/cleanuparr/README.md @@ -23,7 +23,7 @@ Integrations supported: ## Configuration | Option | Description | -|--------|-------------| +| -------- | ------------- | | `TZ` | Timezone (e.g. `Europe/Paris`). Defaults to `Europe/London`. | | `PUID` | User ID to run the process as. Defaults to `0` (root). | | `PGID` | Group ID to run the process as. Defaults to `0` (root). | diff --git a/cleanuparr/config.yaml b/cleanuparr/config.yaml index 15aba3305e..7ddaf22b3a 100644 --- a/cleanuparr/config.yaml +++ b/cleanuparr/config.yaml @@ -1,8 +1,7 @@ arch: - aarch64 - amd64 -description: - Automatically removes stuck and unwanted downloads from your *arr and download clients +description: Automatically removes stuck and unwanted downloads from your *arr and download clients devices: - /dev/dri - /dev/dri/card0 diff --git a/cleanuparr/rootfs/ha_entrypoint.sh b/cleanuparr/rootfs/ha_entrypoint.sh index a177b39aac..d44e8eb02c 100755 --- a/cleanuparr/rootfs/ha_entrypoint.sh +++ b/cleanuparr/rootfs/ha_entrypoint.sh @@ -33,7 +33,7 @@ mkdir -p "$HA_DATA_DIR" # Symlink /app/config → HA persistent storage # The .NET app uses /app/config, NOT /config at the filesystem root if [ -d /app/config ] && [ ! -L /app/config ]; then - cp -rn /app/config/. "$HA_DATA_DIR/" 2>/dev/null || true + cp -rn /app/config/. "$HA_DATA_DIR/" 2> /dev/null || true rm -rf /app/config fi ln -sfn "$HA_DATA_DIR" /app/config diff --git a/cloudcommander/CHANGELOG.md b/cloudcommander/CHANGELOG.md index 6ebeee599d..c537f8db69 100644 --- a/cloudcommander/CHANGELOG.md +++ b/cloudcommander/CHANGELOG.md @@ -1,13 +1,13 @@ - + ## 19.20.5 (2026-09-05) - Update to latest version from coderaiser/cloudcmd (changelog : https://github.com/coderaiser/cloudcmd/releases) - + ## 19.20.4 (2026-08-29) - Update to latest version from coderaiser/cloudcmd (changelog : https://github.com/coderaiser/cloudcmd/releases) - + ## 19.20.0 (2026-08-08) - Update to latest version from coderaiser/cloudcmd (changelog : https://github.com/coderaiser/cloudcmd/releases) - + ## 19.19.1 (2026-06-17) - Update to latest version from coderaiser/cloudcmd (changelog : https://github.com/coderaiser/cloudcmd/releases) diff --git a/cloudcommander/README.md b/cloudcommander/README.md index 218bbe19f9..2bc851e07e 100644 --- a/cloudcommander/README.md +++ b/cloudcommander/README.md @@ -40,7 +40,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `CUSTOM_OPTIONS` | str | | Custom CLI options (e.g., `--name Homeassistant`) | | `DROPBOX_TOKEN` | str | | Dropbox integration token (see https://cloudcmd.io/) | | `localdisks` | str | | Local drives to mount (e.g., `sda1,sdb1,MYNAS`) | diff --git a/cloudcommander/rootfs/etc/cont-init.d/99-run.sh b/cloudcommander/rootfs/etc/cont-init.d/99-run.sh index 90cb6a69e2..b19398b54e 100755 --- a/cloudcommander/rootfs/etc/cont-init.d/99-run.sh +++ b/cloudcommander/rootfs/etc/cont-init.d/99-run.sh @@ -103,7 +103,7 @@ for candidate in "${cloudcmd_candidates[@]}"; do fi done -if [ -z "$CLOUDCMD_BIN" ] && command -v cloudcmd >/dev/null 2>&1; then +if [ -z "$CLOUDCMD_BIN" ] && command -v cloudcmd > /dev/null 2>&1; then CLOUDCMD_BIN=$(command -v cloudcmd) fi diff --git a/codex/CHANGELOG.md b/codex/CHANGELOG.md index 3958bee858..30209f565c 100644 --- a/codex/CHANGELOG.md +++ b/codex/CHANGELOG.md @@ -1,37 +1,37 @@ - + ## 2.2.11 (2026-08-29) - Update to latest version from ajslater/codex (changelog : https://github.com/ajslater/codex/releases) - + ## 2.2.8 (2026-08-22) - Update to latest version from ajslater/codex (changelog : https://github.com/ajslater/codex/releases) - + ## 2.2.6 (2026-08-08) - Update to latest version from ajslater/codex (changelog : https://github.com/ajslater/codex/releases) - + ## 2.2.5 (2026-08-02) - Update to latest version from ajslater/codex (changelog : https://github.com/ajslater/codex/releases) - + ## 2.2.4 (2026-08-01) - Update to latest version from ajslater/codex (changelog : https://github.com/ajslater/codex/releases) - + ## 2.2.2 (2026-07-25) - Update to latest version from ajslater/codex (changelog : https://github.com/ajslater/codex/releases) - + ## 2.2.0 (2026-07-16) - Update to latest version from ajslater/codex (changelog : https://github.com/ajslater/codex/releases) - + ## 2.1.2 (2026-07-11) - Update to latest version from ajslater/codex (changelog : https://github.com/ajslater/codex/releases) - + ## 2.1.0 (2026-07-04) - Update to latest version from ajslater/codex (changelog : https://github.com/ajslater/codex/releases) - + ## 2.0.3 (2026-06-23) - Update to latest version from ajslater/codex (changelog : https://github.com/ajslater/codex/releases) - + ## 2.0.0 (2026-06-20) - Update to latest version from ajslater/codex (changelog : https://github.com/ajslater/codex/releases) - + ## 1.12.8 (2026-06-17) - Update to latest version from ajslater/codex (changelog : https://github.com/ajslater/codex/releases) diff --git a/codex/README.md b/codex/README.md index d43a253fb3..4ea823a97a 100644 --- a/codex/README.md +++ b/codex/README.md @@ -62,7 +62,7 @@ You can place the user folder from the theme/skeleton in /share/codex/www/user, ## Options | Option | Description | Default | Example | -|--------|-------------|---------|---------| +| -------- | ------------- | --------- | --------- | | `PGID` | Group ID for file permissions | `0` | `1000` | | `PUID` | User ID for file permissions | `0` | `1000` | | `TZ` | Timezone in long format | - | `America/Los_Angeles` | diff --git a/collabora/CHANGELOG.md b/collabora/CHANGELOG.md index 9d4afa8e35..5d97b86790 100644 --- a/collabora/CHANGELOG.md +++ b/collabora/CHANGELOG.md @@ -1,10 +1,10 @@ - + ## 26.04.3.2.1 (2026-09-05) - Update to latest version from collabora/code - + ## 26.04.3.1.1 (2026-08-13) - Update to latest version from collabora/code - + ## 26.04.2.4.1 (2026-07-26) - Rebuild on a Debian base: upstream turned collabora/code into a distroless image with no shell, which broke the addon build entirely. collabora/code stays the tracked upstream image in build.json, but is now a build stage whose payload is copied onto ghcr.io/hassio-addons/debian-base, and the addon ships its own launcher in place of the removed /start-collabora-online.sh - build.json names the architecture explicitly again (`collabora/code:latest-amd64` and `collabora/code:latest-arm64`). The builder never passes `--platform`, so the tag is the only thing that decides which binaries land in the addon @@ -19,16 +19,16 @@ - Added `aliasgroup2` and `aliasgroup3` for additional Nextcloud servers - `cert_domain` is now a string (it is a certificate common name) and is passed to Collabora - Documented the above, and corrected the README which asked for two backslashes where Collabora expects one - + ## 1.3.0 (2026-07-16) - Update to latest version from CollaboraOnline/online (changelog : https://github.com/CollaboraOnline/online/releases) - + ## 1.2.2 (2026-07-04) - Update to latest version from CollaboraOnline/online (changelog : https://github.com/CollaboraOnline/online/releases) - + ## 1.2.1 (2026-06-27) - Update to latest version from CollaboraOnline/online (changelog : https://github.com/CollaboraOnline/online/releases) - + ## 1.2.0 (2026-06-23) - Update to latest version from CollaboraOnline/online (changelog : https://github.com/CollaboraOnline/online/releases) diff --git a/collabora/README.md b/collabora/README.md index c6f04f87eb..9489d6e92b 100644 --- a/collabora/README.md +++ b/collabora/README.md @@ -51,7 +51,7 @@ Webui can be found at `https://homeassistant:9980/browser/dist/admin/admin.html` ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `aliasgroup1` | str | | External address of the **Nextcloud** server allowed to use this Collabora (e.g. `https://nextcloud_domain\.com:443`) | | `aliasgroup2` | str | | A second Nextcloud server, same format as `aliasgroup1` | | `aliasgroup3` | str | | A third Nextcloud server, same format as `aliasgroup1` | diff --git a/collabora/rootfs/etc/cont-init.d/99-run.sh b/collabora/rootfs/etc/cont-init.d/99-run.sh index 95b0d33240..35abfcd2c9 100755 --- a/collabora/rootfs/etc/cont-init.d/99-run.sh +++ b/collabora/rootfs/etc/cont-init.d/99-run.sh @@ -27,9 +27,9 @@ normalise_wopi_host() { # server_name is a literal "hostname[:port]", not a regex and not a URL normalise_server_name() { local value="$1" - value="${value//\\/}" # never escaped, drop backslashes if any were copied over - value="${value#*://}" # strip the scheme - value="${value%%/*}" # strip any path + value="${value//\\/}" # never escaped, drop backslashes if any were copied over + value="${value#*://}" # strip the scheme + value="${value%%/*}" # strip any path printf '%s' "$value" } diff --git a/comicarr/CHANGELOG.md b/comicarr/CHANGELOG.md index 5e0764b73f..943b8dd76d 100644 --- a/comicarr/CHANGELOG.md +++ b/comicarr/CHANGELOG.md @@ -1,7 +1,7 @@ - + ## 0.38.7 (2026-09-05) - Update to latest version from frankieramirez/comicarr (changelog : https://github.com/frankieramirez/comicarr/releases) - + ## 0.38.2 (2026-08-29) - Update to latest version from frankieramirez/comicarr (changelog : https://github.com/frankieramirez/comicarr/releases) ## 0.34.0 (20-08-2026) diff --git a/comicarr/README.md b/comicarr/README.md index 554004500c..ea6dcadd15 100644 --- a/comicarr/README.md +++ b/comicarr/README.md @@ -30,7 +30,7 @@ database. ## Configuration | Option | Description | -|--------|-------------| +| -------- | ------------- | | `PUID` / `PGID` | Ownership applied to the add-on configuration directory. Defaults to `0` (root). See the note below before changing it. | | `TZ` | Timezone, e.g. `Europe/Paris`. | | `localdisks` | Local disks to mount, e.g. `sda1` or a disk label. | diff --git a/comicarr/rootfs/etc/services.d/comicarr/run b/comicarr/rootfs/etc/services.d/comicarr/run old mode 100644 new mode 100755 diff --git a/comicarr/rootfs/etc/services.d/nginx/run b/comicarr/rootfs/etc/services.d/nginx/run old mode 100644 new mode 100755 diff --git a/comixed/README.md b/comixed/README.md index b6b16725c2..826a45a43b 100644 --- a/comixed/README.md +++ b/comixed/README.md @@ -60,7 +60,7 @@ Initial setup requires creating an admin account through the web interface. ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `TZ` | str | | Timezone (e.g., `Europe/London`) | | `localdisks` | str | | Local drives to mount (e.g., `sda1,sdb1,MYNAS`) | | `networkdisks` | str | | SMB shares to mount (e.g., `//SERVER/SHARE`) | diff --git a/elasticsearch/CHANGELOG.md b/elasticsearch/CHANGELOG.md index ffda699463..a706bd5a68 100644 --- a/elasticsearch/CHANGELOG.md +++ b/elasticsearch/CHANGELOG.md @@ -1,12 +1,12 @@ - + ## 8.19.21 (2026-09-05) - Update to latest version from elastic/elasticsearch (changelog : https://github.com/elastic/elasticsearch/releases) - + ## 8.19.20 (2026-08-13) - Update to latest version from elastic/elasticsearch (changelog : https://github.com/elastic/elasticsearch/releases) ## 8.19.19.2 (21-07-2026) - Minor bugs fixed - + ## 8.19.19 (2026-07-21) - Update to latest version from elastic/elasticsearch (changelog : https://github.com/elastic/elasticsearch/releases) ## 8.19.18-3 (14-07-2026) diff --git a/elasticsearch/rootfs/usr/local/bin/addon-init.sh b/elasticsearch/rootfs/usr/local/bin/addon-init.sh index eae765ed58..4e6e324de2 100755 --- a/elasticsearch/rootfs/usr/local/bin/addon-init.sh +++ b/elasticsearch/rootfs/usr/local/bin/addon-init.sh @@ -46,17 +46,17 @@ fi # 1 Export user env_vars # ############################ -if [ -f "$OPTIONS_JSON" ] && command -v jq >/dev/null 2>&1; then +if [ -f "$OPTIONS_JSON" ] && command -v jq > /dev/null 2>&1; then while IFS= read -r pair; do - name=$(jq -r '.name // empty' <<<"$pair") - value=$(jq -r '.value // empty' <<<"$pair") + name=$(jq -r '.name // empty' <<< "$pair") + value=$(jq -r '.value // empty' <<< "$pair") if [[ $name =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]; then echo "Setting env variable from options: $name" export "$name"="$value" elif [ -n "$name" ]; then echo "WARNING: ignoring invalid env_vars name: $name" fi - done < <(jq -c '.env_vars[]?' "$OPTIONS_JSON" 2>/dev/null || true) + done < <(jq -c '.env_vars[]?' "$OPTIONS_JSON" 2> /dev/null || true) fi ################################## @@ -82,7 +82,7 @@ data_version="" if [ -f "$VERSION_MARKER" ]; then data_version="$(head -n 1 "$VERSION_MARKER" | tr -cd '0-9.')" -elif [ -d "$PERSISTENT_HOME/data" ] && [ -n "$(ls -A "$PERSISTENT_HOME/data" 2>/dev/null)" ]; then +elif [ -d "$PERSISTENT_HOME/data" ] && [ -n "$(ls -A "$PERSISTENT_HOME/data" 2> /dev/null)" ]; then # Existing data without a marker: only 7.17.9 was ever shipped before markers data_version="7.17.9" fi @@ -128,7 +128,7 @@ mkdir -p "$PERSISTENT_HOME" for dir in "data" "config"; do if [ ! -L "$ES_HOME/$dir" ]; then if [ -d "$ES_HOME/$dir" ]; then - cp -rn "$ES_HOME/$dir" "$PERSISTENT_HOME" 2>/dev/null || true + cp -rn "$ES_HOME/$dir" "$PERSISTENT_HOME" 2> /dev/null || true rm -rf "${ES_HOME:?}/$dir" fi mkdir -p "$PERSISTENT_HOME/$dir" @@ -139,7 +139,7 @@ done # Make the persisted files usable by the elasticsearch user (uid 1000), # which the official entrypoint drops to when started as root if [ "$(id -u)" -eq 0 ]; then - chown -R 1000:0 "$PERSISTENT_HOME/data" "$PERSISTENT_HOME/config" 2>/dev/null || true + chown -R 1000:0 "$PERSISTENT_HOME/data" "$PERSISTENT_HOME/config" 2> /dev/null || true fi echo "Data location: $PERSISTENT_HOME (persistent). Please wait while elasticsearch starts..." @@ -156,9 +156,9 @@ if [ "$data_version" != "$current_version" ]; then # Check the HTTP status directly instead of curl -f: a 401 means # Elasticsearch is up and answering (security just requires # auth), so it must count as healthy too, not as a failure. - status=$(curl -A "HealthCheck: Docker/1.0" -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:9200" 2>/dev/null || true) + status=$(curl -A "HealthCheck: Docker/1.0" -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:9200" 2> /dev/null || true) if [ "$status" = "200" ] || [ "$status" = "401" ]; then - echo "$current_version" >"$VERSION_MARKER" + echo "$current_version" > "$VERSION_MARKER" echo "Elasticsearch $current_version started successfully; data version recorded." exit 0 fi diff --git a/emby/README.md b/emby/README.md index 69f6461031..1f569f0126 100644 --- a/emby/README.md +++ b/emby/README.md @@ -43,7 +43,7 @@ Webui can be found at `:8096`, or within Home Assistant through Ingress ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/emby/rootfs/etc/services.d/nginx/run b/emby/rootfs/etc/services.d/nginx/run old mode 100644 new mode 100755 diff --git a/emby_beta/CHANGELOG.md b/emby_beta/CHANGELOG.md index 83b6684815..ee7ca22166 100644 --- a/emby_beta/CHANGELOG.md +++ b/emby_beta/CHANGELOG.md @@ -1,43 +1,43 @@ - + ## 4.10.0.30 (2026-09-05) - Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases) - + ## 4.10.0.29 (2026-08-29) - Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases) - + ## 4.10.0.28 (2026-08-29) - Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases) - + ## 4.10.0.26 (2026-08-22) - Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases) - + ## 4.10.0.25 (2026-08-15) - Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases) - + ## 4.10.0.24 (2026-08-13) - Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases) - + ## 4.10.0.22 (2026-08-01) - Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases) - + ## 4.10.0.21 (2026-08-01) - Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases) - + ## 4.10.0.20 (2026-07-18) - Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases) - + ## 4.10.0.19 (2026-07-13) - Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases) - + ## 4.10.0.18 (2026-07-11) - Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases) - + ## 4.10.0.17 (2026-07-04) - Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases) - + ## 4.10.0.16 (2026-06-27) - Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases) - + ## 4.10.0.15 (2026-06-20) - Update to latest version from linuxserver/docker-emby (changelog : https://github.com/linuxserver/docker-emby/releases) ## 4.10.0.14 (2026-06-05) diff --git a/enedisgateway2mqtt/README.md b/enedisgateway2mqtt/README.md index 00c408d63e..a674127a88 100644 --- a/enedisgateway2mqtt/README.md +++ b/enedisgateway2mqtt/README.md @@ -48,7 +48,7 @@ Initial setup requires starting the addon once to initialize configuration templ ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `CONFIG_LOCATION` | str | `/config/myelectricaldata/config.yaml` | Path to configuration file | | `TZ` | str | `Europe/Paris` | Timezone (e.g., `Europe/London`) | | `mqtt_autodiscover` | bool | `true` | Enable MQTT autodiscovery | diff --git a/enedisgateway2mqtt_dev/README.md b/enedisgateway2mqtt_dev/README.md index 6169e58538..b0897a9415 100644 --- a/enedisgateway2mqtt_dev/README.md +++ b/enedisgateway2mqtt_dev/README.md @@ -48,7 +48,7 @@ Initial setup requires starting the addon once to initialize configuration templ ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `CONFIG_LOCATION` | str | `/config/myelectricaldata/config.yaml` | Path to configuration file | | `TZ` | str | `Europe/Paris` | Timezone (e.g., `Europe/London`) | | `mqtt_autodiscover` | bool | `true` | Enable MQTT autodiscovery | diff --git a/ente/CHANGELOG.md b/ente/CHANGELOG.md index f99dec2ccd..fe24effcc6 100644 --- a/ente/CHANGELOG.md +++ b/ente/CHANGELOG.md @@ -1,8 +1,8 @@ - + ## 4.4.27 (2026-09-05) - Update to latest version from ente/ente (changelog : https://github.com/ente/ente/releases) - Upstream tag : 1.7.28 - + ## 4.4.26 (2026-08-13) - Update to latest version from ente/ente (changelog : https://github.com/ente/ente/releases) - Upstream tag : 1.3.61 diff --git a/ente/README.md b/ente/README.md index 8039ecb9e0..a75be71cf8 100644 --- a/ente/README.md +++ b/ente/README.md @@ -52,7 +52,7 @@ Webui can be found at . ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `ENTE_ENDPOINT_URL` | str | `http://homeassistant.local:8280` | The URL where Ente API will be accessible (used by web UI) | | `DB_PASSWORD` | str | `ente` | Database password for internal PostgreSQL | | `USE_EXTERNAL_DB` | bool | `false` | Use external PostgreSQL database | @@ -63,7 +63,7 @@ Webui can be found at . If you want to use an external PostgreSQL database, set `USE_EXTERNAL_DB: true` and configure: | Option | Type | Description | -|--------|------|-------------| +| -------- | ------ | ------------- | | `DB_HOSTNAME` | str | PostgreSQL server hostname | | `DB_PORT` | int | PostgreSQL server port (default: 5432) | | `DB_USERNAME` | str | PostgreSQL username | diff --git a/epicgamesfree/CHANGELOG.md b/epicgamesfree/CHANGELOG.md index 2a4aee6321..9df71d88c1 100644 --- a/epicgamesfree/CHANGELOG.md +++ b/epicgamesfree/CHANGELOG.md @@ -1,16 +1,16 @@ - + ## 2026.08.29 (2026-08-29) - Update to latest version from charlocharlie/epicgames-freegames - Upstream tag : debian-2026-08-29 - + ## 2026.08.13 (2026-08-13) - Update to latest version from charlocharlie/epicgames-freegames - Upstream tag : debian-2026-08-13 - + ## 2026.08.04 (2026-08-04) - Update to latest version from charlocharlie/epicgames-freegames - Upstream tag : debian-2026-08-04 - + ## 2026.08.01 (2026-08-01) - Update to latest version from charlocharlie/epicgames-freegames - Upstream tag : debian-2026-08-01 @@ -18,16 +18,16 @@ - Version renamed from `debian-2026-07-27`, which Home Assistant could not order and therefore could not reliably offer as an update: every number of the previous version is kept, as a section of its own. The addon itself and the upstream version it tracks are unchanged - + ## debian-2026-07-27 (2026-07-27) - Update to latest version from charlocharlie/epicgames-freegames - + ## debian-2026-07-24 (2026-07-24) - Update to latest version from charlocharlie/epicgames-freegames - + ## debian-2026-07-20 (2026-07-20) - Update to latest version from charlocharlie/epicgames-freegames - + ## debian-2026-06-21 (2026-06-21) - Update to latest version from charlocharlie/epicgames-freegames ## debian-2026-06-05 (2026-06-05) diff --git a/epicgamesfree/README.md b/epicgamesfree/README.md index 213cf5029c..d4f7adde67 100644 --- a/epicgamesfree/README.md +++ b/epicgamesfree/README.md @@ -88,7 +88,7 @@ Create `/config/addons_config/epicgamesfree/config.json`: ### Configuration Options | Option | Type | Description | -|--------|------|-------------| +| -------- | ------ | ------------- | | `accounts` | array | List of Epic Games accounts | | `cronSchedule` | string | Cron schedule to claim games (default: `0 */6 * * *`) | | `runOnStartup` | boolean | Run a claim cycle when the add-on starts | diff --git a/epicgamesfree/rootfs/etc/cont-init.d/99-run.sh b/epicgamesfree/rootfs/etc/cont-init.d/99-run.sh index ad08ca1c9f..ed694a74c0 100755 --- a/epicgamesfree/rootfs/etc/cont-init.d/99-run.sh +++ b/epicgamesfree/rootfs/etc/cont-init.d/99-run.sh @@ -22,7 +22,7 @@ if bashio::config.true 'disable_cron'; then fi if bashio::command.exists service; then - service cron stop >/dev/null 2>&1 || true + service cron stop > /dev/null 2>&1 || true fi fi diff --git a/filebrowser/CHANGELOG.md b/filebrowser/CHANGELOG.md index accddc1b4e..e4c81de77e 100644 --- a/filebrowser/CHANGELOG.md +++ b/filebrowser/CHANGELOG.md @@ -1,4 +1,4 @@ - + ## 2.63.23 (2026-08-01) - Update to latest version from filebrowser/filebrowser (changelog : https://github.com/filebrowser/filebrowser/releases) ## 2.63.18.5 (26-07-2026) @@ -7,7 +7,7 @@ - Minor bugs fixed ## 2.63.18.3 (22-07-2026) - New flag added : follow_external_symlinks - + ## 2.63.18 (2026-07-04) - Update to latest version from filebrowser/filebrowser (changelog : https://github.com/filebrowser/filebrowser/releases) @@ -16,10 +16,10 @@ ## 2.63.16 (2026-06-23) - Update to latest version from filebrowser/filebrowser (changelog : https://github.com/filebrowser/filebrowser/releases) - + ## 2.63.15 (2026-06-17) - Update to latest version from filebrowser/filebrowser (changelog : https://github.com/filebrowser/filebrowser/releases) - + ## 2.63.14 (2026-06-11) - Update to latest version from filebrowser/filebrowser (changelog : https://github.com/filebrowser/filebrowser/releases) ## 2.63.12 (2026-06-05) diff --git a/filebrowser/README.md b/filebrowser/README.md index 8d6df6ae02..35445e0297 100644 --- a/filebrowser/README.md +++ b/filebrowser/README.md @@ -59,7 +59,7 @@ The web UI can be found at `:8071` or through the Home Assistant sideba ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `ssl` | bool | `false` | Enable HTTPS for web interface | | `certfile` | str | `fullchain.pem` | SSL certificate file (in `/ssl/`) | | `keyfile` | str | `privkey.pem` | SSL private key file (in `/ssl/`) | diff --git a/filebrowser_quantum/CHANGELOG.md b/filebrowser_quantum/CHANGELOG.md index f42a20da88..ad1e7b1240 100644 --- a/filebrowser_quantum/CHANGELOG.md +++ b/filebrowser_quantum/CHANGELOG.md @@ -1,7 +1,7 @@ - + ## 1.5.6 (2026-09-05) - Update to latest version from gtsteffaniak/filebrowser (changelog : https://github.com/gtsteffaniak/filebrowser/releases) - + ## 1.5.3.3 (2026-08-31) - Complete the iOS companion app fix from 1.5.3.2. The "no preview available" screen -- what you get for a `.zip`, `.bin` or anything else FileBrowser @@ -15,7 +15,7 @@ fixed for the download button in the file list. Links the app opens without a link element, such as the public-share sidebar download, are still affected. - + ## 1.5.3.2 (2026-08-30) - Fix Download in the Home Assistant iOS companion app (iOS 17 and later), where a file opened and showed its content with no way to save it. @@ -26,7 +26,7 @@ own download link. "Open file" still opens, and the public-share sidebar's own download button is not covered. Desktop browsers already downloaded these and are unchanged, as is direct access on port 8071. - + ## 1.5.3.1 (2026-08-29) - Fix "open parent directory" in Tools -> File Size Analyzer under Home Assistant ingress. FileBrowser opened the parent folder in a new tab, which @@ -37,13 +37,13 @@ item" action on search results, which open a new tab the same way. Download and preview popups, links pointing out of the add-on, and direct access on port 8071 are unchanged. - + ## 1.5.3 (2026-08-29) - Update to latest version from gtsteffaniak/filebrowser (changelog : https://github.com/gtsteffaniak/filebrowser/releases) - + ## 1.5.2 (2026-08-22) - Update to latest version from gtsteffaniak/filebrowser (changelog : https://github.com/gtsteffaniak/filebrowser/releases) - + ## 1.5.1.2 (2026-08-19) - Fix direct access on port 8071, which was broken in 1.5.1.1: the root redirect pointed at the container-internal port 8072 instead of the @@ -60,12 +60,12 @@ ## 1.5.1 (2026-08-08) - Update to latest version from gtsteffaniak/filebrowser (changelog : https://github.com/gtsteffaniak/filebrowser/releases) - + ## 1.5.0 (2026-07-22) - Update to latest version from gtsteffaniak/filebrowser (changelog : https://github.com/gtsteffaniak/filebrowser/releases) ## 1.4.0-2 (16-07-2026) - Minor bugs fixed - + ## 1.4.0 (2026-06-20) - Update to latest version from gtsteffaniak/filebrowser (changelog : https://github.com/gtsteffaniak/filebrowser/releases) ## 1.3.3-8 (2026-06-03) diff --git a/filebrowser_quantum/README.md b/filebrowser_quantum/README.md index 7477f0523a..add7169465 100644 --- a/filebrowser_quantum/README.md +++ b/filebrowser_quantum/README.md @@ -57,7 +57,7 @@ The web UI can be found at `:8071` or through the Home Assistant sideba ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `auth_method` | list | `password` | Authentication method (`password`, `noauth`, `proxy`, `oidc`) | | `default_user_scope` | str | `/` | The root filesystem path used as the FileBrowser source and as the default scope for all users. Must be an existing absolute directory path (e.g. `/share`, `/media`). | | `localdisks` | str | _(optional)_ | Local drives to mount (e.g., `sda1,sdb1,MYNAS`) | diff --git a/filebrowser_quantum/rootfs/etc/cont-init.d/99-run.sh b/filebrowser_quantum/rootfs/etc/cont-init.d/99-run.sh index 8e6f1de671..753e1cec2b 100755 --- a/filebrowser_quantum/rootfs/etc/cont-init.d/99-run.sh +++ b/filebrowser_quantum/rootfs/etc/cont-init.d/99-run.sh @@ -88,10 +88,10 @@ bashio::log.info "Updating FileBrowser config..." # --- Server (hardcoded values) --- bashio::log.info "... set server" -yq e -i ".server.port = 8080" "$FILEBROWSER_CONFIG" -yq e -i ".server.listen = \"0.0.0.0\"" "$FILEBROWSER_CONFIG" +yq e -i ".server.port = 8080" "$FILEBROWSER_CONFIG" +yq e -i ".server.listen = \"0.0.0.0\"" "$FILEBROWSER_CONFIG" yq e -i ".server.database = \"/config/database.db\"" "$FILEBROWSER_CONFIG" -yq e -i ".server.cacheDir = \"/cache\"" "$FILEBROWSER_CONFIG" +yq e -i ".server.cacheDir = \"/cache\"" "$FILEBROWSER_CONFIG" # --- Default user scope / source path --- bashio::log.info "... set default user scope" @@ -110,8 +110,8 @@ if [ ! -d "$DEFAULT_USER_SCOPE" ]; then fi bashio::log.info "... set source path and defaultUserScope to ${DEFAULT_USER_SCOPE}" -yq e -i ".server.sources[0].path = \"${DEFAULT_USER_SCOPE}\"" "$FILEBROWSER_CONFIG" -yq e -i ".server.sources[0].name = \"Default\"" "$FILEBROWSER_CONFIG" +yq e -i ".server.sources[0].path = \"${DEFAULT_USER_SCOPE}\"" "$FILEBROWSER_CONFIG" +yq e -i ".server.sources[0].name = \"Default\"" "$FILEBROWSER_CONFIG" yq e -i ".server.sources[0].config.defaultUserScope = \"${DEFAULT_USER_SCOPE}\"" "$FILEBROWSER_CONFIG" # --- Base URL (from env or config) --- @@ -124,28 +124,28 @@ AUTH_METHOD=$(bashio::config 'auth_method' 'password') bashio::log.info "... authentication method set to $AUTH_METHOD" case "$AUTH_METHOD" in noauth) - yq e -i ".auth.methods.noauth = true" "$FILEBROWSER_CONFIG" + yq e -i ".auth.methods.noauth = true" "$FILEBROWSER_CONFIG" yq e -i ".auth.methods.password.enabled = false" "$FILEBROWSER_CONFIG" - yq e -i ".auth.methods.proxy.enabled = false" "$FILEBROWSER_CONFIG" - yq e -i ".auth.methods.oidc.enabled = false" "$FILEBROWSER_CONFIG" + yq e -i ".auth.methods.proxy.enabled = false" "$FILEBROWSER_CONFIG" + yq e -i ".auth.methods.oidc.enabled = false" "$FILEBROWSER_CONFIG" ;; password) - yq e -i ".auth.methods.noauth = false" "$FILEBROWSER_CONFIG" - yq e -i ".auth.methods.password.enabled = true" "$FILEBROWSER_CONFIG" - yq e -i ".auth.methods.proxy.enabled = false" "$FILEBROWSER_CONFIG" - yq e -i ".auth.methods.oidc.enabled = false" "$FILEBROWSER_CONFIG" + yq e -i ".auth.methods.noauth = false" "$FILEBROWSER_CONFIG" + yq e -i ".auth.methods.password.enabled = true" "$FILEBROWSER_CONFIG" + yq e -i ".auth.methods.proxy.enabled = false" "$FILEBROWSER_CONFIG" + yq e -i ".auth.methods.oidc.enabled = false" "$FILEBROWSER_CONFIG" ;; proxy) - yq e -i ".auth.methods.noauth = false" "$FILEBROWSER_CONFIG" + yq e -i ".auth.methods.noauth = false" "$FILEBROWSER_CONFIG" yq e -i ".auth.methods.password.enabled = false" "$FILEBROWSER_CONFIG" - yq e -i ".auth.methods.proxy.enabled = true" "$FILEBROWSER_CONFIG" - yq e -i ".auth.methods.oidc.enabled = false" "$FILEBROWSER_CONFIG" + yq e -i ".auth.methods.proxy.enabled = true" "$FILEBROWSER_CONFIG" + yq e -i ".auth.methods.oidc.enabled = false" "$FILEBROWSER_CONFIG" ;; oidc) - yq e -i ".auth.methods.noauth = false" "$FILEBROWSER_CONFIG" + yq e -i ".auth.methods.noauth = false" "$FILEBROWSER_CONFIG" yq e -i ".auth.methods.password.enabled = false" "$FILEBROWSER_CONFIG" - yq e -i ".auth.methods.proxy.enabled = false" "$FILEBROWSER_CONFIG" - yq e -i ".auth.methods.oidc.enabled = true" "$FILEBROWSER_CONFIG" + yq e -i ".auth.methods.proxy.enabled = false" "$FILEBROWSER_CONFIG" + yq e -i ".auth.methods.oidc.enabled = true" "$FILEBROWSER_CONFIG" ;; *) bashio::log.fatal "Unknown auth_method: $AUTH_METHOD" diff --git a/fireflyiii/CHANGELOG.md b/fireflyiii/CHANGELOG.md index dac872bcb6..eda280d598 100644 --- a/fireflyiii/CHANGELOG.md +++ b/fireflyiii/CHANGELOG.md @@ -1,4 +1,4 @@ - + ## 6.6.6 (2026-07-04) - Update to latest version from firefly-iii/firefly-iii (changelog : https://github.com/firefly-iii/firefly-iii/releases) diff --git a/fireflyiii/README.md b/fireflyiii/README.md index d467f97967..fbe9228f1c 100644 --- a/fireflyiii/README.md +++ b/fireflyiii/README.md @@ -45,7 +45,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `APP_KEY` | str | `CHANGEME_32_CHARS_EuC5dfn3LAPzeO` | **CRITICAL**: 32-character encryption key - change before first run! | | `CONFIG_LOCATION` | str | `/config/addons_config/fireflyiii/config.yaml` | Location of additional config file | | `DB_CONNECTION` | list | `sqlite_internal` | Database type (sqlite_internal/mariadb_addon/mysql/pgsql) | diff --git a/fireflyiii/rootfs/etc/cont-init.d/99-run.sh b/fireflyiii/rootfs/etc/cont-init.d/99-run.sh index bb4757f4fa..e2ef45bbe7 100755 --- a/fireflyiii/rootfs/etc/cont-init.d/99-run.sh +++ b/fireflyiii/rootfs/etc/cont-init.d/99-run.sh @@ -132,7 +132,7 @@ case $(bashio::config 'DB_CONNECTION') in export DB_PORT && bashio::log.blue "DB_PORT=$DB_PORT" export DB_DATABASE && bashio::log.blue "DB_DATABASE=$DB_DATABASE" export DB_USERNAME && bashio::log.blue "DB_USERNAME=$DB_USERNAME" - export DB_PASSWORD # do not log password + export DB_PASSWORD # do not log password bashio::log.warning "Firefly-iii is using the Maria DB addon" bashio::log.warning "Please ensure this is included in your backups" diff --git a/fireflyiii_data_importer/CHANGELOG.md b/fireflyiii_data_importer/CHANGELOG.md index cbe61fb999..65ac4dddcf 100644 --- a/fireflyiii_data_importer/CHANGELOG.md +++ b/fireflyiii_data_importer/CHANGELOG.md @@ -1,4 +1,4 @@ - + ## 2.3.4 (2026-07-04) - Update to latest version from firefly-iii/data-importer (changelog : https://github.com/firefly-iii/data-importer/releases) ## 2.3.2-5 (28-05-2026) diff --git a/fireflyiii_data_importer/README.md b/fireflyiii_data_importer/README.md index e86dcd9ded..cb8f4006a8 100644 --- a/fireflyiii_data_importer/README.md +++ b/fireflyiii_data_importer/README.md @@ -49,7 +49,7 @@ For complete setup documentation, see: https://docs.firefly-iii.org/data-importe ### Options | Option | Type | Required | Description | -|--------|------|----------|-------------| +| -------- | ------ | ---------- | ------------- | | `FIREFLY_III_URL` | str | Yes | URL to your Firefly III instance | | `FIREFLY_III_ACCESS_TOKEN` | str | Yes | Personal Access Token from Firefly III | | `CONFIG_LOCATION` | str | Yes | Location for configuration files | diff --git a/fireflyiii_data_importer/rootfs/templates/cronupdate b/fireflyiii_data_importer/rootfs/templates/cronupdate index eff247b11b..5794b32de9 100644 --- a/fireflyiii_data_importer/rootfs/templates/cronupdate +++ b/fireflyiii_data_importer/rootfs/templates/cronupdate @@ -4,19 +4,27 @@ set -e # Source environment variables for cron context # shellcheck disable=SC1091 -if [ -f /etc/environment ]; then set -a; . /etc/environment; set +a; fi +if [ -f /etc/environment ]; then + set -a + . /etc/environment + set +a +fi # shellcheck disable=SC1091 -if [ -f /.env ]; then set -a; . /.env; set +a; fi +if [ -f /.env ]; then + set -a + . /.env + set +a +fi # Use persisted value instead of calling bashio::config (www-data may lack API access) CONFIGSOURCE="${CONFIG_LOCATION}" ( -echo "[INFO] Running update according to defined schedule. Files located in $CONFIGSOURCE/import_files will be imported." -if [ "${SILENT_MODE}" = "true" ]; then - echo "[WARNING] Silent mode activated. Only errors will be shown. Please disable in addon options if you need to debug" - sudo -Eu www-data /usr/local/bin/php /var/www/html/artisan importer:auto-import "$CONFIGSOURCE/import_files" >/dev/null -else - sudo -Eu www-data /usr/local/bin/php /var/www/html/artisan importer:auto-import "$CONFIGSOURCE/import_files" -fi + echo "[INFO] Running update according to defined schedule. Files located in $CONFIGSOURCE/import_files will be imported." + if [ "${SILENT_MODE}" = "true" ]; then + echo "[WARNING] Silent mode activated. Only errors will be shown. Please disable in addon options if you need to debug" + sudo -Eu www-data /usr/local/bin/php /var/www/html/artisan importer:auto-import "$CONFIGSOURCE/import_files" >/dev/null + else + sudo -Eu www-data /usr/local/bin/php /var/www/html/artisan importer:auto-import "$CONFIGSOURCE/import_files" + fi ) &>/proc/1/fd/1 diff --git a/flexget/CHANGELOG.md b/flexget/CHANGELOG.md index 8f32d3e88a..ab8c9a29e7 100644 --- a/flexget/CHANGELOG.md +++ b/flexget/CHANGELOG.md @@ -1,38 +1,38 @@ - + ## 3.20.9 (2026-09-05) - Update to latest version from wiserain/flexget - Upstream tag : ci - + ## 3.20.8 (2026-08-29) - Update to latest version from wiserain/flexget - + ## 3.20.6 (2026-08-22) - Update to latest version from wiserain/flexget - + ## 3.20.5 (2026-08-15) - Update to latest version from wiserain/flexget - + ## 3.20.2 (2026-08-08) - Update to latest version from wiserain/flexget - + ## 3.19.31 (2026-08-01) - Update to latest version from wiserain/flexget - + ## 3.19.30 (2026-07-25) - Update to latest version from wiserain/flexget - + ## 3.19.28 (2026-07-22) - Update to latest version from wiserain/flexget - + ## 3.19.26 (2026-07-04) - Update to latest version from wiserain/flexget - + ## 3.19.25 (2026-06-23) - Update to latest version from wiserain/flexget - + ## 3.19.24 (2026-06-20) - Update to latest version from wiserain/flexget - + ## 3.19.23 (2026-06-06) - Update to latest version from wiserain/flexget diff --git a/flexget/README.md b/flexget/README.md index 52b0099bdb..8feac217ed 100644 --- a/flexget/README.md +++ b/flexget/README.md @@ -69,7 +69,7 @@ Default password: `homeassistant123` (change via addon options). ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `WebuiPass` | str | `homeassistant123` | Web interface password | diff --git a/free_games_claimer/README.md b/free_games_claimer/README.md index a26163e5d2..9b3064d3f2 100644 --- a/free_games_claimer/README.md +++ b/free_games_claimer/README.md @@ -52,7 +52,7 @@ interaction. Set `VNC_PASSWORD` in `config.env` to protect the VNC session. ## Add-on options | Option | Default | Description | -|--------|---------|-------------| +| -------- | --------- | ------------- | | `CONFIG_LOCATION` | `/config/config.env` | Persistent environment configuration file | | `RUN_ONCE` | `true` | Run all selected claimers once, then stop the add-on as previous releases did | | `STORES` | empty | Optional comma-separated override, such as `epic,prime,gog,steam` | diff --git a/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh b/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh index 7dac64162d..11589c9a50 100755 --- a/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh +++ b/free_games_claimer/rootfs/etc/cont-init.d/99-run.sh @@ -84,19 +84,19 @@ legacy_commands_to_stores() { for command in "${command_list[@]}"; do normalized="${command,,}" case "${normalized}" in - *epic-games*|*epicgames*|*" epic"*|epic*) + *epic-games* | *epicgames* | *" epic"* | epic*) selected="$(append_store "epic" "${selected}")" ;; - *prime-gaming*|*primegaming*|*" prime"*|prime*|*" amazon"*|amazon*) + *prime-gaming* | *primegaming* | *" prime"* | prime* | *" amazon"* | amazon*) selected="$(append_store "prime" "${selected}")" ;; - *steam-games*|*" steam"*|steam*) + *steam-games* | *" steam"* | steam*) selected="$(append_store "steam" "${selected}")" ;; *gamerpower*) selected="$(append_store "gamerpower" "${selected}")" ;; - *" gog"*|gog*) + *" gog"* | gog*) selected="$(append_store "gog" "${selected}")" ;; esac diff --git a/free_games_claimer/rootfs/templates/config.env b/free_games_claimer/rootfs/templates/config.env index 39a538959b..7b306017a6 100644 --- a/free_games_claimer/rootfs/templates/config.env +++ b/free_games_claimer/rootfs/templates/config.env @@ -2,14 +2,14 @@ # Complete option reference: # https://github.com/P-Adamiec/Free-Games-Claimer-Remaster#configuration +HEIGHT=720 +LOGIN_TIMEOUT=180 +NOVNC_PORT=6080 # Browser and noVNC SHOW=1 -WIDTH=1280 -HEIGHT=720 TIMEOUT=60 -LOGIN_TIMEOUT=180 VNC_LOGIN_TIMEOUT=180 -NOVNC_PORT=6080 +WIDTH=1280 # Public address used in notification links when behind a reverse proxy. # VNC_URL=https://fgc.example.tld diff --git a/free_games_claimer/rootfs/usr/local/bin/migrate_vogler_data.py b/free_games_claimer/rootfs/usr/local/bin/migrate_vogler_data.py index 1c11bf6e3b..c259fae314 100644 --- a/free_games_claimer/rootfs/usr/local/bin/migrate_vogler_data.py +++ b/free_games_claimer/rootfs/usr/local/bin/migrate_vogler_data.py @@ -47,8 +47,10 @@ def normalize_timestamp(value: Any) -> str: return parsed.isoformat(sep=" ", timespec="seconds") except ValueError: pass - return datetime.now(timezone.utc).replace(tzinfo=None).isoformat( - sep=" ", timespec="seconds" + return ( + datetime.now(timezone.utc) + .replace(tzinfo=None) + .isoformat(sep=" ", timespec="seconds") ) @@ -99,8 +101,7 @@ def iter_records(store: str, payload: Any, source: Path) -> Iterator[dict[str, A def ensure_schema(connection: sqlite3.Connection) -> None: - connection.executescript( - """ + connection.executescript(""" CREATE TABLE IF NOT EXISTS claimed_games ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, store VARCHAR(32) NOT NULL, @@ -117,8 +118,7 @@ def ensure_schema(connection: sqlite3.Connection) -> None: CREATE INDEX IF NOT EXISTS ix_claimed_games_store ON claimed_games (store); CREATE INDEX IF NOT EXISTS ix_claimed_games_user ON claimed_games (user); CREATE INDEX IF NOT EXISTS ix_claimed_games_game_id ON claimed_games (game_id); - """ - ) + """) def migrate() -> int: @@ -209,7 +209,12 @@ def migrate() -> int: connection.commit() log(f"Imported {source_imported} record(s) from {source}") - except (OSError, ValueError, json.JSONDecodeError, sqlite3.Error) as err: + except ( + OSError, + ValueError, + json.JSONDecodeError, + sqlite3.Error, + ) as err: connection.rollback() message = f"Failed to import {source}: {err}" errors.append(message) diff --git a/gazpar2mqtt/CHANGELOG.md b/gazpar2mqtt/CHANGELOG.md index a8ccdaa1eb..c23818568e 100644 --- a/gazpar2mqtt/CHANGELOG.md +++ b/gazpar2mqtt/CHANGELOG.md @@ -7,7 +7,7 @@ ## 0.8.2 (2025-12-24) - Update to latest version from yukulehe/gazpar2mqtt -## (2025-12-23) +## (2025-12-23) - Update to latest version from yukulehe/gazpar2mqtt - The Home Assistant project has deprecated support for the armv7, armhf and i386 architectures. Support wil be fully dropped in the upcoming Home Assistant 2025.12 release diff --git a/gazpar2mqtt/README.md b/gazpar2mqtt/README.md index 5501537b5c..ff55bc7d78 100644 --- a/gazpar2mqtt/README.md +++ b/gazpar2mqtt/README.md @@ -48,7 +48,7 @@ This addon fetches gas consumption data from GRDF (French gas utility) and publi ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `CONFIG_LOCATION` | str | `/config/gazpar2mqtt/config.yaml` | Path to configuration file | | `TZ` | str | `Europe/Paris` | Timezone (e.g., `Europe/London`) | | `mqtt_autodiscover` | bool | `true` | Enable MQTT autodiscovery | diff --git a/gitea/CHANGELOG.md b/gitea/CHANGELOG.md index 8a8974b6e9..553889ec18 100644 --- a/gitea/CHANGELOG.md +++ b/gitea/CHANGELOG.md @@ -1,18 +1,18 @@ - + ## 1.27.3 (2026-09-05) - Update to latest version from go-gitea/gitea (changelog : https://github.com/go-gitea/gitea/releases) - + ## 1.27.2 (2026-08-15) - Update to latest version from go-gitea/gitea (changelog : https://github.com/go-gitea/gitea/releases) - + ## 1.27.1 (2026-08-01) - Update to latest version from go-gitea/gitea (changelog : https://github.com/go-gitea/gitea/releases) - + ## 1.27.0 (2026-07-22) - Update to latest version from go-gitea/gitea (changelog : https://github.com/go-gitea/gitea/releases) ## 1.27 (15-07-2026) - Fix the Gitea add-on HEALTHCHECK to work correctly when SSL is enabled, so Home Assistant can accurately report the add-on's health status regardless of whether the instance uses HTTP or HTTPS. - + ## 1.26.4 (2026-06-23) - Update to latest version from go-gitea/gitea (changelog : https://github.com/go-gitea/gitea/releases) ## 1.26.2-3 (19-06-2026) diff --git a/gitea/README.md b/gitea/README.md index 1bee233677..4968eaaf47 100644 --- a/gitea/README.md +++ b/gitea/README.md @@ -42,7 +42,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `ssl` | bool | `false` | Enable HTTPS for the web interface | | `certfile` | str | `fullchain.pem` | SSL certificate file (must be located in /ssl) | | `keyfile` | str | `privkey.pem` | SSL key file (must be located in /ssl) | diff --git a/grampsweb/CHANGELOG.md b/grampsweb/CHANGELOG.md index e716d4f53b..8b530f137a 100644 --- a/grampsweb/CHANGELOG.md +++ b/grampsweb/CHANGELOG.md @@ -1,19 +1,19 @@ - + ## 26.8.1 (2026-08-29) - Update to latest version from gramps-project/gramps-web (changelog : https://github.com/gramps-project/gramps-web/releases) - + ## 26.8.0 (2026-08-15) - Update to latest version from gramps-project/gramps-web (changelog : https://github.com/gramps-project/gramps-web/releases) - + ## 26.7.1 (2026-08-01) - Update to latest version from gramps-project/gramps-web (changelog : https://github.com/gramps-project/gramps-web/releases) - + ## 26.7.0 (2026-07-22) - Update to latest version from gramps-project/gramps-web (changelog : https://github.com/gramps-project/gramps-web/releases) - + ## 26.6.2 (2026-06-23) - Update to latest version from gramps-project/gramps-web (changelog : https://github.com/gramps-project/gramps-web/releases) - + ## 26.6.1 (2026-06-11) - Update to latest version from gramps-project/gramps-web (changelog : https://github.com/gramps-project/gramps-web/releases) ## 26.6.0 (2026-06-05) diff --git a/grampsweb/README.md b/grampsweb/README.md index 2e7ebf8448..a9a32759cb 100644 --- a/grampsweb/README.md +++ b/grampsweb/README.md @@ -53,7 +53,7 @@ Webui can be found at . ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `CELERY_NUM_WORKERS` | int | `2` | Number of Celery workers for background tasks | | `GUNICORN_NUM_WORKERS` | int | `8` | Number of Gunicorn workers for web requests | | `GRAMPSWEB_SECRET_KEY` | str | - | Secret key for session security (auto-generated if not set) | @@ -65,7 +65,7 @@ Webui can be found at . ### Email Configuration (Optional) | Option | Type | Description | -|--------|------|-------------| +| -------- | ------ | ------------- | | `GRAMPSWEB_EMAIL_HOST` | str | SMTP server hostname | | `GRAMPSWEB_EMAIL_PORT` | int | SMTP server port | | `GRAMPSWEB_EMAIL_USE_SSL` | bool | Use SSL encryption (for port 465) | diff --git a/grav/CHANGELOG.md b/grav/CHANGELOG.md index f76dd58495..a14d42c1b7 100644 --- a/grav/CHANGELOG.md +++ b/grav/CHANGELOG.md @@ -1,37 +1,37 @@ - + ## 2.0.24 (2026-09-05) - Update to latest version from linuxserver/docker-grav (changelog : https://github.com/linuxserver/docker-grav/releases) - + ## 2.0.21 (2026-08-29) - Update to latest version from linuxserver/docker-grav (changelog : https://github.com/linuxserver/docker-grav/releases) - + ## 2.0.20 (2026-08-22) - Update to latest version from linuxserver/docker-grav (changelog : https://github.com/linuxserver/docker-grav/releases) - + ## 2.0.19 (2026-08-15) - Update to latest version from linuxserver/docker-grav (changelog : https://github.com/linuxserver/docker-grav/releases) - + ## 2.0.18 (2026-08-13) - Update to latest version from linuxserver/docker-grav (changelog : https://github.com/linuxserver/docker-grav/releases) - + ## 2.0.17 (2026-08-08) - Update to latest version from linuxserver/docker-grav (changelog : https://github.com/linuxserver/docker-grav/releases) - + ## 2.0.14 (2026-08-01) - Update to latest version from linuxserver/docker-grav (changelog : https://github.com/linuxserver/docker-grav/releases) - + ## 2.0.12 (2026-07-22) - Update to latest version from linuxserver/docker-grav (changelog : https://github.com/linuxserver/docker-grav/releases) - + ## 2.0.6 (2026-07-04) - Update to latest version from linuxserver/docker-grav (changelog : https://github.com/linuxserver/docker-grav/releases) - + ## 2.0.3 (2026-06-27) - Update to latest version from linuxserver/docker-grav (changelog : https://github.com/linuxserver/docker-grav/releases) - + ## 2.0.0 (2026-06-23) - Update to latest version from linuxserver/docker-grav (changelog : https://github.com/linuxserver/docker-grav/releases) - + ## 1.7.53 (2026-06-17) - Update to latest version from linuxserver/docker-grav (changelog : https://github.com/linuxserver/docker-grav/releases) diff --git a/grav/README.md b/grav/README.md index d835e4153a..aad75bd6a8 100644 --- a/grav/README.md +++ b/grav/README.md @@ -66,7 +66,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `1000` | Group ID for file permissions | | `PUID` | int | `1000` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/guacamole/CHANGELOG.md b/guacamole/CHANGELOG.md index 2a76bf19db..b05a1b901c 100644 --- a/guacamole/CHANGELOG.md +++ b/guacamole/CHANGELOG.md @@ -7,7 +7,7 @@ ## 1.6.0-bullseye (2025-12-24) - Update to latest version from abesnier/guacamole -## (2025-12-23) +## (2025-12-23) - Update to latest version from abesnier/guacamole - Added support for configuring extra environment variables via the `env_vars` add-on option alongside config.yaml. See https://github.com/alexbelgium/hassio-addons/wiki/Add-Environment-variables-to-your-Addon-2 for details. diff --git a/guacamole/README.md b/guacamole/README.md index c9ffddedf7..90dd2c5e82 100644 --- a/guacamole/README.md +++ b/guacamole/README.md @@ -44,7 +44,7 @@ The default username is `guacadmin` with password `guacadmin`. It is strongly re ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `EXTENSIONS` | str | `auth-totp` | Guacamole extensions to enable (e.g., `auth-totp`, `history-recording-storage`) | | `recording_search_path` | str | `/config/recordings` | Directory added to `guacamole.properties` as the `recording-search-path` used by the history recording storage extension | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/immich/CHANGELOG.md b/immich/CHANGELOG.md index 88a987a0b4..e406821f1c 100644 --- a/immich/CHANGELOG.md +++ b/immich/CHANGELOG.md @@ -1,10 +1,10 @@ - + ## 3.1.0.1 (2026-08-17) - Fix `password authentication failed for user` when `DB_PASSWORD` contains special characters. Passwords are now URI-encoded before being used in the psql connection string, and SQL-escaped before being used in `CREATE`/`ALTER USER` statements - + ## 3.1.0 (2026-08-01) - Update to latest version from immich-app/immich (changelog : https://github.com/immich-app/immich/releases) - + ## 3.0.3 (2026-07-22) - Update to latest version from immich-app/immich (changelog : https://github.com/immich-app/immich/releases) ## 3.0.1-2 (04-07-2026) diff --git a/immich/README.md b/immich/README.md index 77a5ea6e9e..28cee1476a 100644 --- a/immich/README.md +++ b/immich/README.md @@ -51,7 +51,7 @@ Webui can be found at `:8080`. PostgreSQL can be either internal or ext ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `data_location` | str | `/share/immich` | Path where Immich data is stored | | `library_location` | str | | Path to photo/video library | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/immich_cuda/CHANGELOG.md b/immich_cuda/CHANGELOG.md index 4a7d0b73e7..8fbb0a12a7 100644 --- a/immich_cuda/CHANGELOG.md +++ b/immich_cuda/CHANGELOG.md @@ -1,7 +1,7 @@ - + ## 3.1.0 (2026-08-01) - Update to latest version from immich-app/immich (changelog : https://github.com/immich-app/immich/releases) - + ## 3.0.3 (2026-07-22) - Update to latest version from immich-app/immich (changelog : https://github.com/immich-app/immich/releases) ## 3.0.1-2 (04-07-2026) diff --git a/immich_cuda/README.md b/immich_cuda/README.md index a7ef3f05e3..e5bff280cb 100644 --- a/immich_cuda/README.md +++ b/immich_cuda/README.md @@ -58,7 +58,7 @@ Webui can be found at `:8080`. PostgreSQL can be either internal or ext ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `data_location` | str | `/share/immich` | Path where Immich data is stored | | `library_location` | str | | Path to photo/video library | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/immich_cuda/config.yaml b/immich_cuda/config.yaml index 97f1ae1efd..d379636485 100644 --- a/immich_cuda/config.yaml +++ b/immich_cuda/config.yaml @@ -2,8 +2,7 @@ arch: - amd64 backup_exclude: - "**/machine-learning/*" -description: - Self-hosted photo and video backup solution directly from your mobile phone +description: Self-hosted photo and video backup solution directly from your mobile phone devices: - /dev/dri - /dev/dxg diff --git a/immich_frame/CHANGELOG.md b/immich_frame/CHANGELOG.md index fc75acc943..5c8a9fcc4c 100644 --- a/immich_frame/CHANGELOG.md +++ b/immich_frame/CHANGELOG.md @@ -1,7 +1,7 @@ - + ## 1.0.37.0 (2026-07-22) - Update to latest version from immichFrame/ImmichFrame (changelog : https://github.com/immichFrame/ImmichFrame/releases) - + ## 1.0.34.0 (2026-07-04) - Update to latest version from immichFrame/ImmichFrame (changelog : https://github.com/immichFrame/ImmichFrame/releases) diff --git a/immich_frame/README.md b/immich_frame/README.md index 184c49dcee..9a3d25dce1 100644 --- a/immich_frame/README.md +++ b/immich_frame/README.md @@ -42,7 +42,7 @@ Webui can be found at `:8171`. #### Connection | Option | Type | Description | -|--------|------|-------------| +| -------- | ------ | ------------- | | `ImmichServerUrl` | str | URL of your Immich server (e.g., `http://homeassistant:3001`). Used for single-account setup. | | `ApiKey` | str | Immich API key for authentication. Used for single-account setup. | | `Accounts` | list | List of Immich accounts for multi-account support. Each entry requires `ImmichServerUrl` and `ApiKey`, plus optional per-account filters (see below). | @@ -53,7 +53,7 @@ Webui can be found at `:8171`. These top-level options map to ImmichFrame's `General` settings and control the display behavior: | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `Interval` | int | 45 | Image display interval in seconds | | `TransitionDuration` | float | 2 | Transition duration in seconds | | `ShowClock` | bool | true | Display the current time | @@ -91,7 +91,7 @@ These top-level options map to ImmichFrame's `General` settings and control the These options can be set within each `Accounts` entry to control which images are shown: | Option | Type | Description | -|--------|------|-------------| +| -------- | ------ | ------------- | | `Albums` | str | Comma-separated album UUIDs | | `ExcludedAlbums` | str | Comma-separated excluded album UUIDs | | `People` | str | Comma-separated people UUIDs | diff --git a/immich_frame/rootfs/etc/cont-init.d/99-run.sh b/immich_frame/rootfs/etc/cont-init.d/99-run.sh index f1583ef9e5..4bbd7bac21 100755 --- a/immich_frame/rootfs/etc/cont-init.d/99-run.sh +++ b/immich_frame/rootfs/etc/cont-init.d/99-run.sh @@ -9,13 +9,13 @@ if [ -L /config/Config ]; then bashio::log.info "Migrating legacy /config/Config symlink to real directory" mkdir -p /config/Config.migrate # Copy contents from the symlink target into the new real directory - cp -a /config/Config/. /config/Config.migrate/ 2>/dev/null || true + cp -a /config/Config/. /config/Config.migrate/ 2> /dev/null || true rm -f /config/Config mv /config/Config.migrate /config/Config fi if [ -d /app/Config ] && [ ! -L /app/Config ]; then - cp -n /app/Config/* /config/Config/ 2>/dev/null || true + cp -n /app/Config/* /config/Config/ 2> /dev/null || true rm -rf /app/Config fi if [ ! -e /app/Config ]; then @@ -35,10 +35,10 @@ in_list() { [[ "$2" == *" $1 "* ]]; } # Helper: read a value from options.json handling booleans and nulls correctly config_val() { - jq -r "($1) as \$v | if \$v == null then \"\" else (\$v | tostring) end" /data/options.json 2>/dev/null + jq -r "($1) as \$v | if \$v == null then \"\" else (\$v | tostring) end" /data/options.json 2> /dev/null } config_has() { - jq -e "($1) != null" /data/options.json >/dev/null 2>&1 + jq -e "($1) != null" /data/options.json > /dev/null 2>&1 } # Helper: write a YAML key-value pair with proper formatting @@ -82,7 +82,7 @@ yaml_kv() { declare -A GENERAL_ENVS declare -A ACCOUNT_ENVS -ENV_COUNT=$(jq '.env_vars // [] | length' /data/options.json 2>/dev/null || echo 0) +ENV_COUNT=$(jq '.env_vars // [] | length' /data/options.json 2> /dev/null || echo 0) if [ "$ENV_COUNT" -gt 0 ]; then bashio::log.info "Processing ${ENV_COUNT} env_var(s) for Settings.yaml" fi @@ -91,7 +91,7 @@ for idx in $(seq 0 $((ENV_COUNT - 1))); do EVALUE=$(jq -r ".env_vars[${idx}].value // \"\"" /data/options.json) [ -z "$ENAME" ] && continue [ -z "$EVALUE" ] && continue - [ "$ENAME" = "TZ" ] && continue # TZ is a system env var, not an ImmichFrame setting + [ "$ENAME" = "TZ" ] && continue # TZ is a system env var, not an ImmichFrame setting if in_list "$ENAME" "$ACCOUNT_KEYS"; then ACCOUNT_ENVS["$ENAME"]="$EVALUE" @@ -121,7 +121,10 @@ ACCOUNT_SCHEMA_OPTS="Albums ExcludedAlbums People Tags ShowFavorites ShowMemorie for opt in $GENERAL_SCHEMA_OPTS; do if config_has ".$opt"; then - $GENERAL_STARTED || { echo "General:"; GENERAL_STARTED=true; } + $GENERAL_STARTED || { + echo "General:" + GENERAL_STARTED=true + } yaml_kv " " "$opt" "$(config_val ".$opt")" fi done @@ -129,13 +132,16 @@ ACCOUNT_SCHEMA_OPTS="Albums ExcludedAlbums People Tags ShowFavorites ShowMemorie # Add general env_vars (skip if already set via schema option) for key in "${!GENERAL_ENVS[@]}"; do if ! config_has ".$key"; then - $GENERAL_STARTED || { echo "General:"; GENERAL_STARTED=true; } + $GENERAL_STARTED || { + echo "General:" + GENERAL_STARTED=true + } yaml_kv " " "$key" "${GENERAL_ENVS[$key]}" fi done # -- Accounts section -- - ACCOUNT_COUNT=$(jq '.Accounts // [] | length' /data/options.json 2>/dev/null || echo 0) + ACCOUNT_COUNT=$(jq '.Accounts // [] | length' /data/options.json 2> /dev/null || echo 0) if [ "$ACCOUNT_COUNT" -gt 0 ]; then bashio::log.info "Configuring ${ACCOUNT_COUNT} account(s) from Accounts list" diff --git a/immich_noml/CHANGELOG.md b/immich_noml/CHANGELOG.md index 0ebe6ae855..dbc79ee0d9 100644 --- a/immich_noml/CHANGELOG.md +++ b/immich_noml/CHANGELOG.md @@ -1,7 +1,7 @@ - + ## 3.1.0 (2026-08-01) - Update to latest version from immich-app/immich (changelog : https://github.com/immich-app/immich/releases) - + ## 3.0.3 (2026-07-22) - Update to latest version from immich-app/immich (changelog : https://github.com/immich-app/immich/releases) ## 3.0.1-2 (04-07-2026) diff --git a/immich_noml/README.md b/immich_noml/README.md index b1220ca7bf..d514977af3 100644 --- a/immich_noml/README.md +++ b/immich_noml/README.md @@ -62,7 +62,7 @@ Webui can be found at `:8080`. PostgreSQL can be either internal or ext ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `data_location` | str | `/share/immich` | Path where Immich data is stored | | `library_location` | str | | Path to photo/video library | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/immich_noml/config.yaml b/immich_noml/config.yaml index fb29e4f287..5f86b1391e 100644 --- a/immich_noml/config.yaml +++ b/immich_noml/config.yaml @@ -3,8 +3,7 @@ arch: - amd64 backup_exclude: - "**/machine-learning/*" -description: - Self-hosted photo and video backup solution directly from your mobile phone +description: Self-hosted photo and video backup solution directly from your mobile phone devices: - /dev/dri - /dev/dxg diff --git a/immich_openvino/CHANGELOG.md b/immich_openvino/CHANGELOG.md index bff8ac552f..d8e6f536d3 100644 --- a/immich_openvino/CHANGELOG.md +++ b/immich_openvino/CHANGELOG.md @@ -1,7 +1,7 @@ - + ## 3.1.0 (2026-08-01) - Update to latest version from immich-app/immich (changelog : https://github.com/immich-app/immich/releases) - + ## 3.0.3 (2026-07-22) - Update to latest version from immich-app/immich (changelog : https://github.com/immich-app/immich/releases) ## 3.0.1-2 (04-07-2026) diff --git a/immich_openvino/README.md b/immich_openvino/README.md index c1960c5b08..5b84422ef1 100644 --- a/immich_openvino/README.md +++ b/immich_openvino/README.md @@ -59,7 +59,7 @@ Webui can be found at `:8080`. PostgreSQL can be either internal or ext ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `data_location` | str | `/share/immich` | Path where Immich data is stored | | `library_location` | str | | Path to photo/video library | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/immich_power_tools/CHANGELOG.md b/immich_power_tools/CHANGELOG.md index a07a6e0c03..0035874de0 100644 --- a/immich_power_tools/CHANGELOG.md +++ b/immich_power_tools/CHANGELOG.md @@ -1,7 +1,7 @@ - + ## 0.23.0 (2026-09-05) - Update to latest version from varun-raj/immich-power-tools (changelog : https://github.com/varun-raj/immich-power-tools/releases) - + ## 0.22.0 (2026-07-04) - Update to latest version from varun-raj/immich-power-tools (changelog : https://github.com/varun-raj/immich-power-tools/releases) diff --git a/immich_power_tools/README.md b/immich_power_tools/README.md index ab68edec56..a4ed282e65 100644 --- a/immich_power_tools/README.md +++ b/immich_power_tools/README.md @@ -48,7 +48,7 @@ Webui can be found at `:8001`. ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `IMMICH_URL` | str | **Required** | Internal Immich server URL (e.g., `http://homeassistant:3001`) | | `EXTERNAL_IMMICH_URL` | str | **Required** | External Immich server URL for browser access | | `IMMICH_API_KEY` | str | **Required** | Immich API key for authentication | diff --git a/inadyn/README.md b/inadyn/README.md index 4da00962fc..080208871b 100644 --- a/inadyn/README.md +++ b/inadyn/README.md @@ -57,7 +57,7 @@ For detailed configuration information, see the [official documentation](https:/ ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `verify_address` | bool | | Verify the IP address with check IP service | | `fake_address` | bool | | Use fake address for testing | | `allow_ipv6` | bool | | Enable IPv6 support | @@ -73,7 +73,7 @@ For detailed configuration information, see the [official documentation](https:/ Each provider in the `providers` list supports these options: | Option | Type | Description | -|--------|------|-------------| +| -------- | ------ | ------------- | | `provider` | str | Provider name or custom identifier | | `custom_provider` | bool | Whether this is a custom provider | | `username` | str | Username or token for authentication | diff --git a/jackett/CHANGELOG.md b/jackett/CHANGELOG.md index 0f4ba3812a..fc90685f0e 100644 --- a/jackett/CHANGELOG.md +++ b/jackett/CHANGELOG.md @@ -1,55 +1,55 @@ - + ## 0.24.2531 (2026-09-05) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2486 (2026-08-29) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2434 (2026-08-22) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2406 (2026-08-15) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2404 (2026-08-13) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2342 (2026-08-08) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2315 (2026-08-02) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2307 (2026-08-01) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2304 (2026-08-01) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2265 (2026-07-25) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2251 (2026-07-22) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2166 (2026-07-04) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2125 (2026-06-27) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2110 (2026-06-23) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2080 (2026-06-20) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2075 (2026-06-17) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2051 (2026-06-13) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) - + ## 0.24.2045 (2026-06-11) - Update to latest version from linuxserver/docker-jackett (changelog : https://github.com/linuxserver/docker-jackett/releases) ## 0.24.2021 (2026-06-05) diff --git a/jackett/README.md b/jackett/README.md index 645890b5c7..abab13493e 100644 --- a/jackett/README.md +++ b/jackett/README.md @@ -43,7 +43,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/jellyfin/CHANGELOG.md b/jellyfin/CHANGELOG.md index 2db25a2b2f..3f71d9ad37 100644 --- a/jellyfin/CHANGELOG.md +++ b/jellyfin/CHANGELOG.md @@ -1,4 +1,4 @@ - + ## 10.11.11 (2026-06-11) - Update to latest version from linuxserver/docker-jellyfin (changelog : https://github.com/linuxserver/docker-jellyfin/releases) diff --git a/jellyfin/README.md b/jellyfin/README.md index 938685af7f..ea0d64dc41 100644 --- a/jellyfin/README.md +++ b/jellyfin/README.md @@ -40,7 +40,7 @@ Webui can be found at `:8096` or through the sidebar using Ingress. ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/jellyfin/config.yaml b/jellyfin/config.yaml index 332ea6b0bd..a33595f97c 100644 --- a/jellyfin/config.yaml +++ b/jellyfin/config.yaml @@ -71,7 +71,7 @@ devices: - /dev/nvme1 - /dev/nvme2 environment: - ATTACHED_DEVICES_PERMS: '/dev/dri /dev/dvb /dev/vchiq /dev/vc-mem /dev/video1? -type c -o -type f' + ATTACHED_DEVICES_PERMS: "/dev/dri /dev/dvb /dev/vchiq /dev/vc-mem /dev/video1? -type c -o -type f" host_dbus: true host_network: true image: ghcr.io/alexbelgium/jellyfin-{arch} diff --git a/jellyfin/rootfs/etc/cont-init.d/25-video_fix.sh b/jellyfin/rootfs/etc/cont-init.d/25-video_fix.sh index 68e981ac48..3a4021a0e1 100755 --- a/jellyfin/rootfs/etc/cont-init.d/25-video_fix.sh +++ b/jellyfin/rootfs/etc/cont-init.d/25-video_fix.sh @@ -10,7 +10,7 @@ log() { } # Ensure user exists -if ! id "$JELLYFIN_USER" >/dev/null 2>&1; then +if ! id "$JELLYFIN_USER" > /dev/null 2>&1; then log "User $JELLYFIN_USER not found — skipping" exit 0 fi @@ -21,17 +21,17 @@ if [ -d /dev/dri ]; then for dev in /dev/dri/renderD*; do if [ -e "$dev" ]; then log "Setting permissions on $dev" - chmod 666 "$dev" 2>/dev/null || log "chmod failed on $dev" + chmod 666 "$dev" 2> /dev/null || log "chmod failed on $dev" fi done # Detect the actual GID of the render device - RENDER_GID="$(stat -c '%g' /dev/dri/renderD128 2>/dev/null || true)" + RENDER_GID="$(stat -c '%g' /dev/dri/renderD128 2> /dev/null || true)" if [ -z "$RENDER_GID" ]; then # Fallback: try any render device for dev in /dev/dri/renderD*; do if [ -e "$dev" ]; then - RENDER_GID="$(stat -c '%g' "$dev" 2>/dev/null || true)" + RENDER_GID="$(stat -c '%g' "$dev" 2> /dev/null || true)" break fi done @@ -46,7 +46,7 @@ if [ -d /dev/dri ]; then if [ -z "$GROUP_NAME" ]; then GROUP_NAME="render${RENDER_GID}" log "Creating group $GROUP_NAME with GID $RENDER_GID" - if ! groupadd -g "$RENDER_GID" "$GROUP_NAME" 2>/dev/null; then + if ! groupadd -g "$RENDER_GID" "$GROUP_NAME" 2> /dev/null; then log "Group creation failed (probably already exists). Continuing." fi else @@ -58,7 +58,7 @@ if [ -d /dev/dri ]; then log "User $JELLYFIN_USER already in group $GROUP_NAME" else log "Adding user $JELLYFIN_USER to group $GROUP_NAME" - if ! usermod -aG "$GROUP_NAME" "$JELLYFIN_USER" 2>/dev/null; then + if ! usermod -aG "$GROUP_NAME" "$JELLYFIN_USER" 2> /dev/null; then log "usermod failed — probably read-only user or already applied" fi fi diff --git a/jellyfin/rootfs/etc/services.d/nginx/run b/jellyfin/rootfs/etc/services.d/nginx/run old mode 100644 new mode 100755 diff --git a/joal/README.md b/joal/README.md index b70d8c0ade..bbaa9509da 100644 --- a/joal/README.md +++ b/joal/README.md @@ -43,7 +43,7 @@ Configuration details are available in the addon logs. ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `secret_token` | str | `lrMY24Byhx` | Authentication token for the web interface | | `ui_path` | str | `joal` | Web UI path | | `run_duration` | str | `12h` | Runtime duration (e.g., 5s, 2m, 12h, 5d) | diff --git a/joplin/README.md b/joplin/README.md index a4b5bc99e1..3daa6b6ead 100644 --- a/joplin/README.md +++ b/joplin/README.md @@ -43,7 +43,7 @@ Webui can be found at `:22300`. ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `APP_BASE_URL` | str | `http://your_domain:port` | Base public URL where the service will be running | | `data_location` | str | `/config/addons_config/joplin` | Path where Joplin data is stored | | `DB_CLIENT` | str | | Database client type. Only `pg` (PostgreSQL) is supported. MariaDB/MySQL is NOT supported. | diff --git a/joplin/rootfs/etc/cont-init.d/99-run.sh b/joplin/rootfs/etc/cont-init.d/99-run.sh index b59858b917..3cd1d7f0c9 100755 --- a/joplin/rootfs/etc/cont-init.d/99-run.sh +++ b/joplin/rootfs/etc/cont-init.d/99-run.sh @@ -7,7 +7,7 @@ bashio::log.warning "Warning - minimum configuration recommended : 2 cpu cores a unlock_sqlite_migrations() { local db_path="$1" - if ! command -v sqlite3 >/dev/null 2>&1; then + if ! command -v sqlite3 > /dev/null 2>&1; then bashio::log.warning "sqlite3 not available; skipping SQLite migration lock check." return 0 fi @@ -20,7 +20,7 @@ unlock_sqlite_migrations() { # If the lock table doesn't exist yet, nothing to unlock local has_table - has_table="$(sqlite3 "$db_path" "SELECT 1 FROM sqlite_master WHERE type='table' AND name='knex_migrations_lock' LIMIT 1;" 2>/dev/null || true)" + has_table="$(sqlite3 "$db_path" "SELECT 1 FROM sqlite_master WHERE type='table' AND name='knex_migrations_lock' LIMIT 1;" 2> /dev/null || true)" [[ "$has_table" == "1" ]] || return 0 # Ensure the lock row exists (Knex expects one row) @@ -28,22 +28,22 @@ unlock_sqlite_migrations() { sqlite3 "$db_path" " PRAGMA busy_timeout=5000; INSERT OR IGNORE INTO knex_migrations_lock(\"index\", is_locked) VALUES (1, 0); - " >/dev/null 2>&1 || true + " > /dev/null 2>&1 || true local is_locked - is_locked="$(sqlite3 "$db_path" "PRAGMA busy_timeout=5000; SELECT is_locked FROM knex_migrations_lock WHERE \"index\"=1 LIMIT 1;" 2>/dev/null || true)" + is_locked="$(sqlite3 "$db_path" "PRAGMA busy_timeout=5000; SELECT is_locked FROM knex_migrations_lock WHERE \"index\"=1 LIMIT 1;" 2> /dev/null || true)" if [[ "$is_locked" == "1" ]]; then bashio::log.warning "Locked SQLite migration table detected, attempting to unlock." sqlite3 "$db_path" " PRAGMA busy_timeout=5000; UPDATE knex_migrations_lock SET is_locked = 0 WHERE \"index\"=1 AND is_locked=1; - " >/dev/null 2>&1 || bashio::log.warning "Failed to clear SQLite migration lock." + " > /dev/null 2>&1 || bashio::log.warning "Failed to clear SQLite migration lock." fi } unlock_postgres_migrations() { - if ! command -v psql >/dev/null 2>&1; then + if ! command -v psql > /dev/null 2>&1; then bashio::log.warning "psql not available; skipping PostgreSQL migration lock check." return 0 fi @@ -59,23 +59,26 @@ unlock_postgres_migrations() { # If table doesn't exist, skip local has_table has_table="$(psql -h "$POSTGRES_HOST" -p "$pg_port" -U "$POSTGRES_USER" -d "$POSTGRES_DATABASE" -Atqc \ - "SELECT 1 FROM information_schema.tables WHERE table_name='knex_migrations_lock' LIMIT 1;" 2>/dev/null || true)" - [[ "$has_table" == "1" ]] || { unset PGPASSWORD; return 0; } + "SELECT 1 FROM information_schema.tables WHERE table_name='knex_migrations_lock' LIMIT 1;" 2> /dev/null || true)" + [[ "$has_table" == "1" ]] || { + unset PGPASSWORD + return 0 + } # Ensure row exists psql -h "$POSTGRES_HOST" -p "$pg_port" -U "$POSTGRES_USER" -d "$POSTGRES_DATABASE" -Atqc \ "INSERT INTO knex_migrations_lock(\"index\", is_locked) VALUES (1, 0) ON CONFLICT (\"index\") DO NOTHING;" \ - >/dev/null 2>&1 || true + > /dev/null 2>&1 || true local is_locked is_locked="$(psql -h "$POSTGRES_HOST" -p "$pg_port" -U "$POSTGRES_USER" -d "$POSTGRES_DATABASE" -Atqc \ - "SELECT is_locked FROM knex_migrations_lock WHERE \"index\"=1 LIMIT 1;" 2>/dev/null || true)" + "SELECT is_locked FROM knex_migrations_lock WHERE \"index\"=1 LIMIT 1;" 2> /dev/null || true)" if [[ "$is_locked" == "1" ]]; then bashio::log.warning "Locked PostgreSQL migration table detected, attempting to unlock." psql -h "$POSTGRES_HOST" -p "$pg_port" -U "$POSTGRES_USER" -d "$POSTGRES_DATABASE" -Atqc \ "UPDATE knex_migrations_lock SET is_locked = 0 WHERE \"index\"=1 AND is_locked=1;" \ - >/dev/null 2>&1 || bashio::log.warning "Failed to clear PostgreSQL migration lock." + > /dev/null 2>&1 || bashio::log.warning "Failed to clear PostgreSQL migration lock." fi unset PGPASSWORD diff --git a/kometa/CHANGELOG.md b/kometa/CHANGELOG.md index dc1ea65e86..21ffc8610e 100644 --- a/kometa/CHANGELOG.md +++ b/kometa/CHANGELOG.md @@ -1,19 +1,19 @@ - + ## 2.4.8 (2026-08-22) - Update to latest version from linuxserver/docker-kometa (changelog : https://github.com/linuxserver/docker-kometa/releases) - + ## 2.4.7 (2026-08-13) - Update to latest version from linuxserver/docker-kometa (changelog : https://github.com/linuxserver/docker-kometa/releases) - + ## 2.4.6 (2026-08-01) - Update to latest version from linuxserver/docker-kometa (changelog : https://github.com/linuxserver/docker-kometa/releases) - + ## 2.4.5 (2026-07-25) - Update to latest version from linuxserver/docker-kometa (changelog : https://github.com/linuxserver/docker-kometa/releases) - + ## 2.4.4 (2026-06-27) - Update to latest version from linuxserver/docker-kometa (changelog : https://github.com/linuxserver/docker-kometa/releases) - + ## 2.4.3 (2026-06-23) - Update to latest version from linuxserver/docker-kometa (changelog : https://github.com/linuxserver/docker-kometa/releases) diff --git a/komga/README.md b/komga/README.md index bcb67e8fde..b2a862fc32 100644 --- a/komga/README.md +++ b/komga/README.md @@ -28,7 +28,7 @@ search index on first boot. ## Configuration | Option | Description | -|--------|-------------| +| -------- | ------------- | | `PUID` / `PGID` | Ownership applied to the add-on configuration directory. Defaults to `0` (root). | | `TZ` | Timezone, e.g. `Europe/Paris`. | | `localdisks` | Local disks to mount, e.g. `sda1` or a disk label. | diff --git a/librespeed/CHANGELOG.md b/librespeed/CHANGELOG.md index 5c2d605bf3..f156d298c2 100644 --- a/librespeed/CHANGELOG.md +++ b/librespeed/CHANGELOG.md @@ -1,7 +1,7 @@ - + ## 6.2.1 (2026-08-15) - Update to latest version from linuxserver/docker-librespeed (changelog : https://github.com/linuxserver/docker-librespeed/releases) - + ## 6.2.0 (2026-07-25) - Update to latest version from linuxserver/docker-librespeed (changelog : https://github.com/linuxserver/docker-librespeed/releases) diff --git a/lidarr/README.md b/lidarr/README.md index 824041f443..3efeabd1db 100644 --- a/lidarr/README.md +++ b/lidarr/README.md @@ -59,7 +59,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/linkwarden/CHANGELOG.md b/linkwarden/CHANGELOG.md index eeab68d221..2d9fdec37d 100644 --- a/linkwarden/CHANGELOG.md +++ b/linkwarden/CHANGELOG.md @@ -1,7 +1,7 @@ - + ## 2.16.1 (2026-08-22) - Update to latest version from linkwarden/linkwarden (changelog : https://github.com/linkwarden/linkwarden/releases) - + ## 2.16.0 (2026-08-01) - Update to latest version from linkwarden/linkwarden (changelog : https://github.com/linkwarden/linkwarden/releases) ## 2.15.1.2 (2026-07-22) diff --git a/linkwarden/README.md b/linkwarden/README.md index 25808cb46e..25049d7ddf 100644 --- a/linkwarden/README.md +++ b/linkwarden/README.md @@ -43,7 +43,7 @@ You'll need to create a new user account at startup. ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `NEXTAUTH_SECRET` | str | **Required** | Secret key for NextAuth.js authentication (must be filled at start) | | `NEXTAUTH_URL` | str | | Custom NextAuth URL (optional, only if Linkwarden is kept externally) | | `NEXT_PUBLIC_DISABLE_REGISTRATION` | bool | `false` | Disable new user registration | diff --git a/linkwarden/rootfs/etc/cont-init.d/99-run.sh b/linkwarden/rootfs/etc/cont-init.d/99-run.sh index ac20ed97ec..47ebc68ad7 100755 --- a/linkwarden/rootfs/etc/cont-init.d/99-run.sh +++ b/linkwarden/rootfs/etc/cont-init.d/99-run.sh @@ -32,7 +32,7 @@ fix_linkwarden_path() { # Preserve any data already written to the non-persistent path if [ -d "$resolved_path" ] && [ ! -L "$resolved_path" ]; then - if ! cp -rn "$resolved_path/." "$actual_path/" 2>/dev/null; then + if ! cp -rn "$resolved_path/." "$actual_path/" 2> /dev/null; then bashio::log.warning "Could not migrate existing data from $resolved_path to $actual_path (may be empty or a permissions issue)" fi rm -rf "$resolved_path" diff --git a/maintainerr/CHANGELOG.md b/maintainerr/CHANGELOG.md index f609b3b6bf..42596dad1a 100644 --- a/maintainerr/CHANGELOG.md +++ b/maintainerr/CHANGELOG.md @@ -1,46 +1,46 @@ - + ## 3.26.0 (2026-09-05) - Update to latest version from maintainerr/maintainerr (changelog : https://github.com/maintainerr/maintainerr/releases) - + ## 3.25.0 (2026-08-29) - Update to latest version from maintainerr/maintainerr (changelog : https://github.com/maintainerr/maintainerr/releases) - + ## 3.24.0 (2026-08-22) - Update to latest version from maintainerr/maintainerr (changelog : https://github.com/maintainerr/maintainerr/releases) - + ## 3.22.1 (2026-08-13) - Update to latest version from maintainerr/maintainerr (changelog : https://github.com/maintainerr/maintainerr/releases) - + ## 3.22.0 (2026-08-08) - Update to latest version from maintainerr/maintainerr (changelog : https://github.com/maintainerr/maintainerr/releases) - + ## 3.21.1 (2026-08-02) - Update to latest version from maintainerr/maintainerr (changelog : https://github.com/maintainerr/maintainerr/releases) - + ## 3.21.0 (2026-08-01) - Update to latest version from maintainerr/maintainerr (changelog : https://github.com/maintainerr/maintainerr/releases) - + ## 3.20.1 (2026-08-01) - Update to latest version from maintainerr/maintainerr (changelog : https://github.com/maintainerr/maintainerr/releases) - + ## 3.18.0 (2026-07-22) - Update to latest version from maintainerr/maintainerr (changelog : https://github.com/maintainerr/maintainerr/releases) - + ## 3.16.0 (2026-07-04) - Update to latest version from maintainerr/maintainerr (changelog : https://github.com/maintainerr/maintainerr/releases) - + ## 3.15.3 (2026-06-27) - Update to latest version from maintainerr/maintainerr (changelog : https://github.com/maintainerr/maintainerr/releases) - + ## 3.15.2 (2026-06-23) - Update to latest version from maintainerr/maintainerr (changelog : https://github.com/maintainerr/maintainerr/releases) - + ## 3.15.1 (2026-06-20) - Update to latest version from maintainerr/maintainerr (changelog : https://github.com/maintainerr/maintainerr/releases) - + ## 3.15.0 (2026-06-11) - Update to latest version from maintainerr/maintainerr (changelog : https://github.com/maintainerr/maintainerr/releases) - + ## 3.14.0 (2026-06-06) - Update to latest version from maintainerr/maintainerr (changelog : https://github.com/maintainerr/maintainerr/releases) diff --git a/maintainerr/config.yaml b/maintainerr/config.yaml index 917b7e5e94..f40be5dc10 100644 --- a/maintainerr/config.yaml +++ b/maintainerr/config.yaml @@ -1,8 +1,7 @@ arch: - aarch64 - amd64 -description: - Rule-based media cleanup tool for Plex, Jellyfin and Emby. Creates collections and optionally deletes unwatched content. +description: Rule-based media cleanup tool for Plex, Jellyfin and Emby. Creates collections and optionally deletes unwatched content. devices: - /dev/dri - /dev/dri/card0 diff --git a/maintainerr/rootfs/ha_entrypoint.sh b/maintainerr/rootfs/ha_entrypoint.sh index 7521aa1aa8..e3cbccbc39 100755 --- a/maintainerr/rootfs/ha_entrypoint.sh +++ b/maintainerr/rootfs/ha_entrypoint.sh @@ -27,9 +27,9 @@ echo "[Maintainerr] Setting up data directory: $DATA_DIR" mkdir -p "$DATA_DIR" "$DATA_DIR/logs" # Copy any seed/existing data from /opt/data to /config/data (don't overwrite) -if [ -d /opt/data ] && [ "$(ls -A /opt/data 2>/dev/null)" ]; then +if [ -d /opt/data ] && [ "$(ls -A /opt/data 2> /dev/null)" ]; then echo "[Maintainerr] Copying existing files from /opt/data to $DATA_DIR..." - cp -rn /opt/data/. "$DATA_DIR/" 2>/dev/null || true + cp -rn /opt/data/. "$DATA_DIR/" 2> /dev/null || true fi # Apply permissions/ownership once so copied files are also covered diff --git a/manyfold/CHANGELOG.md b/manyfold/CHANGELOG.md index 36f8c77f64..884a5fbdb7 100644 --- a/manyfold/CHANGELOG.md +++ b/manyfold/CHANGELOG.md @@ -1,10 +1,10 @@ - + ## 0.148.0 (2026-08-29) - Update to latest version from manyfold3d/manyfold (changelog : https://github.com/manyfold3d/manyfold/releases) - + ## 0.147.2 (2026-08-15) - Update to latest version from manyfold3d/manyfold (changelog : https://github.com/manyfold3d/manyfold/releases) - + ## 0.147.1 (2026-08-01) - Update to latest version from manyfold3d/manyfold (changelog : https://github.com/manyfold3d/manyfold/releases) ## 0.146.1-3 (2026-07-08) @@ -14,7 +14,7 @@ ## 0.146.1-2 (06-07-2026) - Minor bugs fixed - + ## 0.146.1 (2026-07-06) - Add configurable Manyfold public hostname with Home Assistant external URL and homeassistant.local fallbacks. @@ -40,8 +40,8 @@ - Minor bugs fixed ## 0.140.1 - - Bump version to 0.140.1 - - Detailed changes https://github.com/manyfold3d/manyfold/compare/v0.139.3...v0.140.1 +- Bump version to 0.140.1 +- Detailed changes https://github.com/manyfold3d/manyfold/compare/v0.139.3...v0.140.1 ## 0.139.3 (11-05-2026) @@ -58,7 +58,7 @@ ## 0.137.0 - Bumped upstream Manyfold image to `ghcr.io/manyfold3d/manyfold-solo:0.137.0` for both `amd64` and `aarch64`. -- Add funtionalities about sharing and comment federation, some implemented in 0.136.0 +- Add funtionalities about sharing and comment federation, some implemented in 0.136.0 ## 0.135.0 diff --git a/manyfold/README.md b/manyfold/README.md index 3ffcab5581..f061029119 100644 --- a/manyfold/README.md +++ b/manyfold/README.md @@ -147,7 +147,7 @@ After changing values: **How it works:** | Scenario | Behaviour | -|----------|-----------| +| ---------- | ----------- | | **New install**, option left blank | A random secret is auto-generated and saved to `/config/secret_key_base` | | **Addon update**, option still blank | The previously saved `/config/secret_key_base` is reused — no data loss | | **Option manually set** | The value from the addon options is used and saved to `/config/secret_key_base` | @@ -172,7 +172,7 @@ chmod 600 /addon_configs//secret_key_base Replace `` and `` with the actual directory names (e.g. `db21ed7f_manyfold` and `088d77ac_manyfold_solo`). List them with `ls /addon_configs/`. -3. Start the new addon — it will pick up the existing database and secret automatically. +1. Start the new addon — it will pick up the existing database and secret automatically. ## Notes diff --git a/manyfold/rootfs/etc/s6-overlay/s6-rc.d/manyfold/finish b/manyfold/rootfs/etc/s6-overlay/s6-rc.d/manyfold/finish old mode 100755 new mode 100644 diff --git a/manyfold/run.sh b/manyfold/run.sh index c86336b5a9..01a493c87e 100755 --- a/manyfold/run.sh +++ b/manyfold/run.sh @@ -17,140 +17,140 @@ DEFAULT_MAX_FILE_EXTRACT_SIZE="1073741824" DEFAULT_PUBLIC_HOSTNAME="homeassistant.local" log() { - echo "[manyfold-addon] $*" + echo "[manyfold-addon] $*" } die() { - echo "[manyfold-addon] ERROR: $*" >&2 - exit 1 + echo "[manyfold-addon] ERROR: $*" >&2 + exit 1 } read_opt() { - local key="$1" - jq -er --arg k "$key" '.[$k] // empty' "$OPTIONS_JSON" 2>/dev/null || true + local key="$1" + jq -er --arg k "$key" '.[$k] // empty' "$OPTIONS_JSON" 2> /dev/null || true } strip_hostname() { - local raw="$1" + local raw="$1" - raw="${raw#http://}" - raw="${raw#https://}" - raw="${raw%%/*}" + raw="${raw#http://}" + raw="${raw#https://}" + raw="${raw%%/*}" - if [[ "$raw" =~ ^(\[[^]]+\])(:[0-9]+)?$ ]]; then - raw="${BASH_REMATCH[1]}" - else - raw="${raw%%:*}" - fi + if [[ "$raw" =~ ^(\[[^]]+\])(:[0-9]+)?$ ]]; then + raw="${BASH_REMATCH[1]}" + else + raw="${raw%%:*}" + fi - printf '%s\n' "$raw" + printf '%s\n' "$raw" } detect_ha_public_hostname() { - local supervisor_url="${SUPERVISOR:-http://supervisor}" - local response external_url external_host + local supervisor_url="${SUPERVISOR:-http://supervisor}" + local response external_url external_host + + if [[ -z "${SUPERVISOR_TOKEN:-}" ]] || ! command -v curl > /dev/null 2>&1; then + printf '%s\n' "$DEFAULT_PUBLIC_HOSTNAME" + return + fi + + response="$(curl -fsSL \ + -H "Authorization: Bearer ${SUPERVISOR_TOKEN}" \ + "${supervisor_url}/core/api/config" 2> /dev/null || true)" + external_url="$(jq -er '.external_url // empty' <<< "$response" 2> /dev/null || true)" + external_host="$(strip_hostname "$external_url")" + + if [[ -n "$external_host" && "$external_host" != "null" ]]; then + printf '%s\n' "$external_host" + return + fi - if [[ -z "${SUPERVISOR_TOKEN:-}" ]] || ! command -v curl >/dev/null 2>&1; then printf '%s\n' "$DEFAULT_PUBLIC_HOSTNAME" - return - fi - - response="$(curl -fsSL \ - -H "Authorization: Bearer ${SUPERVISOR_TOKEN}" \ - "${supervisor_url}/core/api/config" 2>/dev/null || true)" - external_url="$(jq -er '.external_url // empty' <<< "$response" 2>/dev/null || true)" - external_host="$(strip_hostname "$external_url")" - - if [[ -n "$external_host" && "$external_host" != "null" ]]; then - printf '%s\n' "$external_host" - return - fi - - printf '%s\n' "$DEFAULT_PUBLIC_HOSTNAME" } normalize_path() { - local raw="$1" - if command -v realpath >/dev/null 2>&1; then - realpath -m "$raw" - return - fi + local raw="$1" + if command -v realpath > /dev/null 2>&1; then + realpath -m "$raw" + return + fi - case "$raw" in - /*) printf '%s\n' "$raw" ;; - *) printf '/%s\n' "$raw" ;; - esac + case "$raw" in + /*) printf '%s\n' "$raw" ;; + *) printf '/%s\n' "$raw" ;; + esac } is_allowed_path() { - local resolved="$1" - case "$resolved" in - /share|/share/*|/media|/media/*|/config|/config/*) - return 0 - ;; - *) - return 1 - ;; - esac + local resolved="$1" + case "$resolved" in + /share | /share/* | /media | /media/* | /config | /config/*) + return 0 + ;; + *) + return 1 + ;; + esac } require_mapped_path() { - local label="$1" - local raw="$2" - local resolved + local label="$1" + local raw="$2" + local resolved - resolved="$(normalize_path "$raw")" - if ! is_allowed_path "$resolved"; then - die "${label} '${raw}' resolves to '${resolved}', which is outside /share, /media, and /config" - fi + resolved="$(normalize_path "$raw")" + if ! is_allowed_path "$resolved"; then + die "${label} '${raw}' resolves to '${resolved}', which is outside /share, /media, and /config" + fi - printf '%s\n' "$resolved" + printf '%s\n' "$resolved" } ensure_dir() { - local dir="$1" - mkdir -p "$dir" + local dir="$1" + mkdir -p "$dir" } ensure_existing_or_create() { - local label="$1" - local dir="$2" + local label="$1" + local dir="$2" - if [[ -d "$dir" ]]; then - return - fi + if [[ -d "$dir" ]]; then + return + fi - if mkdir -p "$dir" 2>/dev/null; then - return - fi + if mkdir -p "$dir" 2> /dev/null; then + return + fi - die "${label} '${dir}' does not exist and could not be created. Create it on the host or choose a writable path under /config." + die "${label} '${dir}' does not exist and could not be created. Create it on the host or choose a writable path under /config." } chown_recursive_if_writable() { - local owner="$1" - local path="$2" + local owner="$1" + local path="$2" - if [[ ! -e "$path" ]]; then - log "Skipping ownership update for ${path} (missing path)" - return - fi + if [[ ! -e "$path" ]]; then + log "Skipping ownership update for ${path} (missing path)" + return + fi - if [[ -w "$path" ]]; then - chown -R "$owner" "$path" - return - fi + if [[ -w "$path" ]]; then + chown -R "$owner" "$path" + return + fi - log "Skipping ownership update for ${path} (read-only mapping)" + log "Skipping ownership update for ${path} (read-only mapping)" } generate_secret() { - if command -v openssl >/dev/null 2>&1; then - openssl rand -hex 64 - return - fi + if command -v openssl > /dev/null 2>&1; then + openssl rand -hex 64 + return + fi - head -c 64 /dev/urandom | od -An -tx1 | tr -d ' \n' + head -c 64 /dev/urandom | od -An -tx1 | tr -d ' \n' } # Manyfold's production.rb sets config.assume_ssl = PUBLIC_HOSTNAME.present?, @@ -162,11 +162,11 @@ generate_secret() { # via an initializer dropped into whichever app directory is found, since we # still need PUBLIC_HOSTNAME set for correct link generation elsewhere. disable_assume_ssl() { - local app_dir="$1" - local initializer_dir="${app_dir}/config/initializers" - [[ -d "$initializer_dir" ]] || return 0 + local app_dir="$1" + local initializer_dir="${app_dir}/config/initializers" + [[ -d "$initializer_dir" ]] || return 0 - cat > "${initializer_dir}/manyfold_addon_disable_assume_ssl.rb" << 'EOF' + cat > "${initializer_dir}/manyfold_addon_disable_assume_ssl.rb" << 'EOF' # Added by the Manyfold Home Assistant add-on: this add-on has no # SSL-terminating reverse proxy in front of it, so assuming SSL produces # incorrect https:// redirects on a plain-HTTP port. @@ -175,73 +175,86 @@ EOF } start_manyfold() { - if [[ -x /usr/src/app/bin/docker-entrypoint.sh ]]; then - log "Starting Manyfold via /usr/src/app/bin/docker-entrypoint.sh foreman start" - cd /usr/src/app - disable_assume_ssl /usr/src/app - exec ./bin/docker-entrypoint.sh foreman start - fi - - if [[ -x /app/bin/docker-entrypoint.sh ]]; then - log "Starting Manyfold via /app/bin/docker-entrypoint.sh foreman start" - cd /app - disable_assume_ssl /app - exec ./bin/docker-entrypoint.sh foreman start - fi - - local candidate - for candidate in \ - /usr/local/bin/docker-entrypoint.sh \ - /usr/local/bin/docker-entrypoint \ - /docker-entrypoint.sh \ - /entrypoint.sh - do - if [[ -x "$candidate" ]]; then - log "Starting Manyfold via ${candidate}" - if [[ "$candidate" == *docker-entrypoint* ]]; then - exec "$candidate" foreman start - fi - exec "$candidate" + if [[ -x /usr/src/app/bin/docker-entrypoint.sh ]]; then + log "Starting Manyfold via /usr/src/app/bin/docker-entrypoint.sh foreman start" + cd /usr/src/app + disable_assume_ssl /usr/src/app + exec ./bin/docker-entrypoint.sh foreman start fi - done - if command -v docker-entrypoint >/dev/null 2>&1; then - log "Starting Manyfold via docker-entrypoint" - exec docker-entrypoint foreman start - fi + if [[ -x /app/bin/docker-entrypoint.sh ]]; then + log "Starting Manyfold via /app/bin/docker-entrypoint.sh foreman start" + cd /app + disable_assume_ssl /app + exec ./bin/docker-entrypoint.sh foreman start + fi - if [[ -d /usr/src/app ]]; then - cd /usr/src/app - disable_assume_ssl /usr/src/app - elif [[ -d /app ]]; then - cd /app - disable_assume_ssl /app - fi + local candidate + for candidate in \ + /usr/local/bin/docker-entrypoint.sh \ + /usr/local/bin/docker-entrypoint \ + /docker-entrypoint.sh \ + /entrypoint.sh; do + if [[ -x "$candidate" ]]; then + log "Starting Manyfold via ${candidate}" + if [[ "$candidate" == *docker-entrypoint* ]]; then + exec "$candidate" foreman start + fi + exec "$candidate" + fi + done - if command -v bundle >/dev/null 2>&1; then - log "Starting Manyfold via rails server fallback" - exec bundle exec rails server -b 0.0.0.0 -p 3214 - fi + if command -v docker-entrypoint > /dev/null 2>&1; then + log "Starting Manyfold via docker-entrypoint" + exec docker-entrypoint foreman start + fi - die "Could not find a known Manyfold entrypoint" + if [[ -d /usr/src/app ]]; then + cd /usr/src/app + disable_assume_ssl /usr/src/app + elif [[ -d /app ]]; then + cd /app + disable_assume_ssl /app + fi + + if command -v bundle > /dev/null 2>&1; then + log "Starting Manyfold via rails server fallback" + exec bundle exec rails server -b 0.0.0.0 -p 3214 + fi + + die "Could not find a known Manyfold entrypoint" } [[ -f "$OPTIONS_JSON" ]] || die "Missing options file at ${OPTIONS_JSON}" -PUID="$(read_opt puid)"; PUID="${PUID:-1000}" -PGID="$(read_opt pgid)"; PGID="${PGID:-1000}" -MULTIUSER="$(read_opt multiuser)"; MULTIUSER="${MULTIUSER:-true}" -LIBRARY_PATH_RAW="$(read_opt library_path)"; LIBRARY_PATH_RAW="${LIBRARY_PATH_RAW:-$DEFAULT_LIBRARY_PATH}" -THUMBNAILS_PATH_RAW="$(read_opt thumbnails_path)"; THUMBNAILS_PATH_RAW="${THUMBNAILS_PATH_RAW:-$DEFAULT_THUMBNAILS_PATH}" -LOG_LEVEL="$(read_opt log_level)"; LOG_LEVEL="${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -WEB_CONCURRENCY="$(read_opt web_concurrency)"; WEB_CONCURRENCY="${WEB_CONCURRENCY:-$DEFAULT_WEB_CONCURRENCY}" -RAILS_MAX_THREADS="$(read_opt rails_max_threads)"; RAILS_MAX_THREADS="${RAILS_MAX_THREADS:-$DEFAULT_RAILS_MAX_THREADS}" -DEFAULT_WORKER_CONCURRENCY="$(read_opt default_worker_concurrency)"; DEFAULT_WORKER_CONCURRENCY="${DEFAULT_WORKER_CONCURRENCY:-$DEFAULT_DEFAULT_WORKER_CONCURRENCY}" -PERFORMANCE_WORKER_CONCURRENCY="$(read_opt performance_worker_concurrency)"; PERFORMANCE_WORKER_CONCURRENCY="${PERFORMANCE_WORKER_CONCURRENCY:-$DEFAULT_PERFORMANCE_WORKER_CONCURRENCY}" -MAX_FILE_UPLOAD_SIZE="$(read_opt max_file_upload_size)"; MAX_FILE_UPLOAD_SIZE="${MAX_FILE_UPLOAD_SIZE:-$DEFAULT_MAX_FILE_UPLOAD_SIZE}" -MAX_FILE_EXTRACT_SIZE="$(read_opt max_file_extract_size)"; MAX_FILE_EXTRACT_SIZE="${MAX_FILE_EXTRACT_SIZE:-$DEFAULT_MAX_FILE_EXTRACT_SIZE}" -SECRET_KEY_BASE="$(read_opt secret_key_base)"; SECRET_KEY_BASE="${SECRET_KEY_BASE:-}" -PUBLIC_HOSTNAME_RAW="$(read_opt public_hostname)"; PUBLIC_HOSTNAME_RAW="${PUBLIC_HOSTNAME_RAW:-}" +PUID="$(read_opt puid)" +PUID="${PUID:-1000}" +PGID="$(read_opt pgid)" +PGID="${PGID:-1000}" +MULTIUSER="$(read_opt multiuser)" +MULTIUSER="${MULTIUSER:-true}" +LIBRARY_PATH_RAW="$(read_opt library_path)" +LIBRARY_PATH_RAW="${LIBRARY_PATH_RAW:-$DEFAULT_LIBRARY_PATH}" +THUMBNAILS_PATH_RAW="$(read_opt thumbnails_path)" +THUMBNAILS_PATH_RAW="${THUMBNAILS_PATH_RAW:-$DEFAULT_THUMBNAILS_PATH}" +LOG_LEVEL="$(read_opt log_level)" +LOG_LEVEL="${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" +WEB_CONCURRENCY="$(read_opt web_concurrency)" +WEB_CONCURRENCY="${WEB_CONCURRENCY:-$DEFAULT_WEB_CONCURRENCY}" +RAILS_MAX_THREADS="$(read_opt rails_max_threads)" +RAILS_MAX_THREADS="${RAILS_MAX_THREADS:-$DEFAULT_RAILS_MAX_THREADS}" +DEFAULT_WORKER_CONCURRENCY="$(read_opt default_worker_concurrency)" +DEFAULT_WORKER_CONCURRENCY="${DEFAULT_WORKER_CONCURRENCY:-$DEFAULT_DEFAULT_WORKER_CONCURRENCY}" +PERFORMANCE_WORKER_CONCURRENCY="$(read_opt performance_worker_concurrency)" +PERFORMANCE_WORKER_CONCURRENCY="${PERFORMANCE_WORKER_CONCURRENCY:-$DEFAULT_PERFORMANCE_WORKER_CONCURRENCY}" +MAX_FILE_UPLOAD_SIZE="$(read_opt max_file_upload_size)" +MAX_FILE_UPLOAD_SIZE="${MAX_FILE_UPLOAD_SIZE:-$DEFAULT_MAX_FILE_UPLOAD_SIZE}" +MAX_FILE_EXTRACT_SIZE="$(read_opt max_file_extract_size)" +MAX_FILE_EXTRACT_SIZE="${MAX_FILE_EXTRACT_SIZE:-$DEFAULT_MAX_FILE_EXTRACT_SIZE}" +SECRET_KEY_BASE="$(read_opt secret_key_base)" +SECRET_KEY_BASE="${SECRET_KEY_BASE:-}" +PUBLIC_HOSTNAME_RAW="$(read_opt public_hostname)" +PUBLIC_HOSTNAME_RAW="${PUBLIC_HOSTNAME_RAW:-}" [[ "$PUID" =~ ^[0-9]+$ ]] || die "puid must be a non-negative integer" [[ "$PGID" =~ ^[0-9]+$ ]] || die "pgid must be a non-negative integer" @@ -256,15 +269,15 @@ LIBRARY_PATH="$(require_mapped_path "library_path" "$LIBRARY_PATH_RAW")" THUMBNAILS_PATH="$(require_mapped_path "thumbnails_path" "$THUMBNAILS_PATH_RAW")" if [[ -n "$PUBLIC_HOSTNAME_RAW" ]]; then - PUBLIC_HOSTNAME="$(strip_hostname "$PUBLIC_HOSTNAME_RAW")" + PUBLIC_HOSTNAME="$(strip_hostname "$PUBLIC_HOSTNAME_RAW")" else - PUBLIC_HOSTNAME="$(detect_ha_public_hostname)" + PUBLIC_HOSTNAME="$(detect_ha_public_hostname)" fi [[ -n "$PUBLIC_HOSTNAME" && "$PUBLIC_HOSTNAME" != "null" ]] || PUBLIC_HOSTNAME="$DEFAULT_PUBLIC_HOSTNAME" case "$THUMBNAILS_PATH" in - /config|/config/*) ;; - *) die "thumbnails_path must resolve under /config for persistence" ;; + /config | /config/*) ;; + *) die "thumbnails_path must resolve under /config for persistence" ;; esac ensure_dir "$CONFIG_DIR" @@ -274,19 +287,19 @@ ensure_dir "$THUMBNAILS_PATH" [[ -r "$LIBRARY_PATH" ]] || die "library_path '${LIBRARY_PATH}' is not readable" if [[ -z "$SECRET_KEY_BASE" ]]; then - if [[ -s "$SECRET_FILE" ]]; then - SECRET_KEY_BASE="$(cat "$SECRET_FILE")" - log "Loaded SECRET_KEY_BASE from ${SECRET_FILE}" - else - SECRET_KEY_BASE="$(generate_secret)" + if [[ -s "$SECRET_FILE" ]]; then + SECRET_KEY_BASE="$(cat "$SECRET_FILE")" + log "Loaded SECRET_KEY_BASE from ${SECRET_FILE}" + else + SECRET_KEY_BASE="$(generate_secret)" + printf '%s' "$SECRET_KEY_BASE" > "$SECRET_FILE" + chmod 600 "$SECRET_FILE" + log "Generated and stored SECRET_KEY_BASE at ${SECRET_FILE}" + fi +else printf '%s' "$SECRET_KEY_BASE" > "$SECRET_FILE" chmod 600 "$SECRET_FILE" - log "Generated and stored SECRET_KEY_BASE at ${SECRET_FILE}" - fi -else - printf '%s' "$SECRET_KEY_BASE" > "$SECRET_FILE" - chmod 600 "$SECRET_FILE" - log "Saved provided SECRET_KEY_BASE to ${SECRET_FILE}" + log "Saved provided SECRET_KEY_BASE to ${SECRET_FILE}" fi export SECRET_KEY_BASE diff --git a/mealie/CHANGELOG.md b/mealie/CHANGELOG.md index a094ff97cc..eaa3165f17 100644 --- a/mealie/CHANGELOG.md +++ b/mealie/CHANGELOG.md @@ -1,20 +1,20 @@ - + ## v3.25.1 (2026-09-05) - Update to latest version from mealie-recipes/mealie (changelog : https://github.com/mealie-recipes/mealie/releases) - Build the ingress frontend with pnpm and the upstream lockfile: upstream dropped frontend/yarn.lock in v3.24.0, so the previous yarn install resolved dependencies unpinned and the build broke on a vuetify release without "vuetify/labs/rules" - + ## v3.24.0 (2026-08-29) - Update to latest version from mealie-recipes/mealie (changelog : https://github.com/mealie-recipes/mealie/releases) - + ## v3.23.1 (2026-08-22) - Update to latest version from mealie-recipes/mealie (changelog : https://github.com/mealie-recipes/mealie/releases) - + ## v3.22.0 (2026-08-01) - Update to latest version from mealie-recipes/mealie (changelog : https://github.com/mealie-recipes/mealie/releases) - + ## v3.21.0 (2026-07-25) - Update to latest version from mealie-recipes/mealie (changelog : https://github.com/mealie-recipes/mealie/releases) - + ## v3.20.1 (2026-06-27) - Update to latest version from mealie-recipes/mealie (changelog : https://github.com/mealie-recipes/mealie/releases) diff --git a/mealie/README.md b/mealie/README.md index a11392cd0d..566c0748f9 100644 --- a/mealie/README.md +++ b/mealie/README.md @@ -48,7 +48,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `1000` | Group ID for file permissions | | `PUID` | int | `1000` | User ID for file permissions | | `ssl` | bool | `false` | Enable HTTPS for the web interface | diff --git a/monica/README.md b/monica/README.md index c42fb7fde7..b27be65dd6 100644 --- a/monica/README.md +++ b/monica/README.md @@ -52,7 +52,7 @@ Webui can be found at `:8181`. ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `database` | list | `sqlite` | Database type (sqlite/MariaDB_addon/Mysql_external) | | `APP_KEY` | str | | Application encryption key (auto-generated if empty) | | `DB_DATABASE` | str | | Database name (for external MySQL/MariaDB) | diff --git a/monica/rootfs/etc/cont-init.d/99-run.sh b/monica/rootfs/etc/cont-init.d/99-run.sh index 232ec75112..fd6c761d82 100755 --- a/monica/rootfs/etc/cont-init.d/99-run.sh +++ b/monica/rootfs/etc/cont-init.d/99-run.sh @@ -210,7 +210,7 @@ if [[ "${MEILISEARCH_LOCAL}" == true ]]; then bashio::log.error "${message}" if [ -n "${S6_SVSCANCTL_BIN}" ]; then - if ! "${S6_SVSCANCTL_BIN}" -t "${S6_SUPERVISED_DIR}" 2>/dev/null; then + if ! "${S6_SVSCANCTL_BIN}" -t "${S6_SUPERVISED_DIR}" 2> /dev/null; then bashio::log.error "Unable to signal s6-svscanctl to stop services" fi else @@ -225,7 +225,7 @@ if [[ "${MEILISEARCH_LOCAL}" == true ]]; then } meilisearch_ensure_running() { - if kill -0 "${MEILISEARCH_PID}" 2>/dev/null; then + if kill -0 "${MEILISEARCH_PID}" 2> /dev/null; then return 0 fi @@ -245,12 +245,12 @@ if [[ "${MEILISEARCH_LOCAL}" == true ]]; then } MEILISEARCH_CMD=( - env \ - MEILI_ENV="${MEILISEARCH_ENVIRONMENT}" \ - MEILI_NO_ANALYTICS="${MEILISEARCH_NO_ANALYTICS}" \ - meilisearch \ - --http-addr "${MEILISEARCH_ADDR}" \ - --db-path "${MEILISEARCH_DB_PATH}" + env + MEILI_ENV="${MEILISEARCH_ENVIRONMENT}" + MEILI_NO_ANALYTICS="${MEILISEARCH_NO_ANALYTICS}" + meilisearch + --http-addr "${MEILISEARCH_ADDR}" + --db-path "${MEILISEARCH_DB_PATH}" ) if [ -n "${MEILISEARCH_ENV_KEY}" ]; then @@ -262,7 +262,7 @@ if [[ "${MEILISEARCH_LOCAL}" == true ]]; then bashio::log.info "Waiting for Meilisearch TCP socket" for attempt in $(seq 1 30); do - if bash -c "cat < /dev/null > /dev/tcp/${MEILISEARCH_HOST}/${MEILISEARCH_PORT}" 2>/dev/null; then + if bash -c "cat < /dev/null > /dev/tcp/${MEILISEARCH_HOST}/${MEILISEARCH_PORT}" 2> /dev/null; then break fi diff --git a/mylar3/CHANGELOG.md b/mylar3/CHANGELOG.md index 18d7e03451..9b2811c901 100644 --- a/mylar3/CHANGELOG.md +++ b/mylar3/CHANGELOG.md @@ -1,7 +1,7 @@ - + ## 0.11.0 (2026-08-22) - Update to latest version from linuxserver/docker-mylar3 (changelog : https://github.com/linuxserver/docker-mylar3/releases) - + ## 0.10.0 (2026-06-17) - Update to latest version from linuxserver/docker-mylar3 (changelog : https://github.com/linuxserver/docker-mylar3/releases) diff --git a/mylar3/README.md b/mylar3/README.md index 9696fb7fa5..26dbeebad1 100644 --- a/mylar3/README.md +++ b/mylar3/README.md @@ -55,7 +55,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/navidrome/CHANGELOG.md b/navidrome/CHANGELOG.md index ff7500bee5..1289f645b3 100644 --- a/navidrome/CHANGELOG.md +++ b/navidrome/CHANGELOG.md @@ -1,9 +1,9 @@ - + ## 0.63.2 (2026-07-18) - Update to latest version from navidrome/navidrome (changelog : https://github.com/navidrome/navidrome/releases) ## 0.62.0-2 (19-06-2026) - Minor bugs fixed - + ## 0.62.0 (2026-06-11) - Update to latest version from navidrome/navidrome (changelog : https://github.com/navidrome/navidrome/releases) diff --git a/navidrome/README.md b/navidrome/README.md index 6d031bd54b..f11d53c477 100644 --- a/navidrome/README.md +++ b/navidrome/README.md @@ -42,7 +42,7 @@ See https://www.navidrome.org/docs/usage/configuration-options/ for additional c ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `base_url` | str | `/` | Base URL to configure Navidrome behind a proxy | | `music_folder` | str | `/data/music` | Folder where your music library is stored | | `data_folder` | str | `/data` | Folder to store application data (DB) | diff --git a/netalertx/CHANGELOG.md b/netalertx/CHANGELOG.md index 055fe93523..1f3debf69e 100644 --- a/netalertx/CHANGELOG.md +++ b/netalertx/CHANGELOG.md @@ -1,10 +1,10 @@ - + ## 26.9.0 (2026-09-05) - Update to latest version from jokob-sk/NetAlertX (changelog : https://github.com/jokob-sk/NetAlertX/releases) - + ## 26.8.5 (2026-08-08) - Update to latest version from jokob-sk/NetAlertX (changelog : https://github.com/jokob-sk/NetAlertX/releases) - + ## 26.7.1 (2026-07-04) - Update to latest version from jokob-sk/NetAlertX (changelog : https://github.com/jokob-sk/NetAlertX/releases) ## 26.6.3-1 (2026-06-19) diff --git a/netalertx_fa/CHANGELOG.md b/netalertx_fa/CHANGELOG.md index af47d70631..e0fa335a5c 100644 --- a/netalertx_fa/CHANGELOG.md +++ b/netalertx_fa/CHANGELOG.md @@ -1,10 +1,10 @@ - + ## 26.9.0 (2026-09-05) - Update to latest version from jokob-sk/NetAlertX (changelog : https://github.com/jokob-sk/NetAlertX/releases) - + ## 26.8.5 (2026-08-08) - Update to latest version from jokob-sk/NetAlertX (changelog : https://github.com/jokob-sk/NetAlertX/releases) - + ## 26.7.1 (2026-07-04) - Update to latest version from jokob-sk/NetAlertX (changelog : https://github.com/jokob-sk/NetAlertX/releases) ## 26.6.3-1 (2026-06-19) diff --git a/netbird-server/rootfs/etc/cont-init.d/00-config.sh b/netbird-server/rootfs/etc/cont-init.d/00-config.sh index 9d9a6d95fb..482a2319e4 100755 --- a/netbird-server/rootfs/etc/cont-init.d/00-config.sh +++ b/netbird-server/rootfs/etc/cont-init.d/00-config.sh @@ -8,19 +8,19 @@ set -euo pipefail # ============================================================================== create_or_load_secret() { - local secret_file="$1" - local generator="$2" - local generated="" + local secret_file="$1" + local generator="$2" + local generated="" - if [[ -f "$secret_file" ]]; then - cat "$secret_file" - return - fi + if [[ -f "$secret_file" ]]; then + cat "$secret_file" + return + fi - generated=$(eval "$generator") - echo "$generated" > "$secret_file" - chmod 600 "$secret_file" - echo "$generated" + generated=$(eval "$generator") + echo "$generated" > "$secret_file" + chmod 600 "$secret_file" + echo "$generated" } DATA_DIR="/config/netbird" @@ -34,20 +34,20 @@ RELAY_PORT=8084 RELAY_METRICS_PORT=9093 if [[ -z "$DOMAIN" || "$DOMAIN" == "netbird.example.com" ]]; then - result=$(bashio::api.supervisor GET /core/api/config true || true) - external_host="$(bashio::jq "$result" '.external_url' | cut -d'/' -f3 | cut -d':' -f1)" - internal_host="$(bashio::jq "$result" '.internal_url' | cut -d'/' -f3 | cut -d':' -f1)" + result=$(bashio::api.supervisor GET /core/api/config true || true) + external_host="$(bashio::jq "$result" '.external_url' | cut -d'/' -f3 | cut -d':' -f1)" + internal_host="$(bashio::jq "$result" '.internal_url' | cut -d'/' -f3 | cut -d':' -f1)" - if [[ -n "$external_host" && "$external_host" != "null" ]]; then - DOMAIN="$external_host" - bashio::log.warning "Domain not set; using Home Assistant external_url host: ${DOMAIN}" - elif [[ -n "$internal_host" && "$internal_host" != "null" ]]; then - DOMAIN="$internal_host" - bashio::log.warning "Domain not set; using Home Assistant internal_url host: ${DOMAIN}" - else - bashio::log.error "Set a valid domain in the add-on configuration (domain cannot be empty or netbird.example.com)." - bashio::exit.nok - fi + if [[ -n "$external_host" && "$external_host" != "null" ]]; then + DOMAIN="$external_host" + bashio::log.warning "Domain not set; using Home Assistant external_url host: ${DOMAIN}" + elif [[ -n "$internal_host" && "$internal_host" != "null" ]]; then + DOMAIN="$internal_host" + bashio::log.warning "Domain not set; using Home Assistant internal_url host: ${DOMAIN}" + else + bashio::log.error "Set a valid domain in the add-on configuration (domain cannot be empty or netbird.example.com)." + bashio::exit.nok + fi fi NETBIRD_PORT=443 @@ -56,11 +56,11 @@ NETBIRD_RELAY_PROTO="rels" CADDY_SECURE_DOMAIN=", ${DOMAIN}:${NETBIRD_PORT}" mkdir -p "$DATA_DIR" \ - "$DATA_DIR/management" \ - "$DATA_DIR/secrets" \ - "$DATA_DIR/dashboard" \ - "$DATA_DIR/relay" \ - "$DATA_DIR/caddy" + "$DATA_DIR/management" \ + "$DATA_DIR/secrets" \ + "$DATA_DIR/dashboard" \ + "$DATA_DIR/relay" \ + "$DATA_DIR/caddy" DATASTORE_ENC_KEY=$(create_or_load_secret "$DATA_DIR/secrets/management_datastore_key" "openssl rand -base64 32") RELAY_AUTH_SECRET=$(create_or_load_secret "$DATA_DIR/secrets/relay_auth_secret" "openssl rand -base64 32 | sed 's/=//g'") @@ -68,8 +68,8 @@ RELAY_AUTH_SECRET=$(create_or_load_secret "$DATA_DIR/secrets/relay_auth_secret" # Generate management config if missing MANAGEMENT_CONFIG="$DATA_DIR/management/management.json" if [[ ! -f "$MANAGEMENT_CONFIG" ]]; then - bashio::log.info "Generating management config at ${MANAGEMENT_CONFIG}." - cat < "$MANAGEMENT_CONFIG" + bashio::log.info "Generating management config at ${MANAGEMENT_CONFIG}." + cat << CONFIG > "$MANAGEMENT_CONFIG" { "Stuns": [ { @@ -99,14 +99,14 @@ if [[ ! -f "$MANAGEMENT_CONFIG" ]]; then } CONFIG else - bashio::log.info "Using existing management config at ${MANAGEMENT_CONFIG}." + bashio::log.info "Using existing management config at ${MANAGEMENT_CONFIG}." fi # Generate relay env file if missing RELAY_ENV_FILE="$DATA_DIR/relay/relay.env" if [[ ! -f "$RELAY_ENV_FILE" ]]; then - bashio::log.info "Generating relay env file at ${RELAY_ENV_FILE}." - cat < "$RELAY_ENV_FILE" + bashio::log.info "Generating relay env file at ${RELAY_ENV_FILE}." + cat << CONFIG > "$RELAY_ENV_FILE" NB_LOG_LEVEL=info NB_LISTEN_ADDRESS=:${RELAY_PORT} NB_EXPOSED_ADDRESS=${NETBIRD_RELAY_PROTO}://${DOMAIN}:${NETBIRD_PORT} @@ -118,14 +118,14 @@ NB_STUN_PORTS=${NETBIRD_STUN_PORT} CONFIG fi if ! grep -q '^NB_METRICS_PORT=' "$RELAY_ENV_FILE"; then - echo "NB_METRICS_PORT=${RELAY_METRICS_PORT}" >> "$RELAY_ENV_FILE" + echo "NB_METRICS_PORT=${RELAY_METRICS_PORT}" >> "$RELAY_ENV_FILE" fi # Generate dashboard env file if missing DASHBOARD_ENV_FILE="$DATA_DIR/dashboard/env" if [[ ! -f "$DASHBOARD_ENV_FILE" ]]; then - bashio::log.info "Generating dashboard env file at ${DASHBOARD_ENV_FILE}." - cat < "$DASHBOARD_ENV_FILE" + bashio::log.info "Generating dashboard env file at ${DASHBOARD_ENV_FILE}." + cat << CONFIG > "$DASHBOARD_ENV_FILE" # Endpoints NETBIRD_MGMT_API_ENDPOINT=${NETBIRD_HTTP_PROTOCOL}://${DOMAIN} NETBIRD_MGMT_GRPC_API_ENDPOINT=${NETBIRD_HTTP_PROTOCOL}://${DOMAIN} @@ -143,15 +143,15 @@ NGINX_SSL_PORT=443 # Letsencrypt LETSENCRYPT_DOMAIN=none CONFIG - chmod 600 "$DASHBOARD_ENV_FILE" + chmod 600 "$DASHBOARD_ENV_FILE" fi sed -i 's/^AUTH_SUPPORTED_SCOPES=openid profile email groups$/AUTH_SUPPORTED_SCOPES="openid profile email groups"/' "$DASHBOARD_ENV_FILE" # Generate Caddyfile if missing CADDYFILE="$DATA_DIR/Caddyfile" if [[ ! -f "$CADDYFILE" ]]; then - bashio::log.info "Generating Caddyfile at ${CADDYFILE}." - cat < "$CADDYFILE" + bashio::log.info "Generating Caddyfile at ${CADDYFILE}." + cat << CONFIG > "$CADDYFILE" { servers :80,:443 { protocols h1 h2c h2 h3 @@ -186,7 +186,7 @@ if [[ ! -f "$CADDYFILE" ]]; then } CONFIG else - bashio::log.info "Using existing Caddyfile at ${CADDYFILE}." + bashio::log.info "Using existing Caddyfile at ${CADDYFILE}." fi mkdir -p /run/nginx diff --git a/netbird-server/rootfs/etc/services.d/caddy/run b/netbird-server/rootfs/etc/services.d/caddy/run old mode 100644 new mode 100755 index 6e37ad1778..921885733d --- a/netbird-server/rootfs/etc/services.d/caddy/run +++ b/netbird-server/rootfs/etc/services.d/caddy/run @@ -11,8 +11,8 @@ DATA_DIR="/config/netbird" CADDYFILE="${DATA_DIR}/Caddyfile" if [[ ! -f "$CADDYFILE" ]]; then - bashio::log.error "Missing Caddyfile at ${CADDYFILE}." - bashio::exit.nok + bashio::log.error "Missing Caddyfile at ${CADDYFILE}." + bashio::exit.nok fi export XDG_DATA_HOME="${DATA_DIR}/caddy/data" diff --git a/netbird-server/rootfs/etc/services.d/dashboard/run b/netbird-server/rootfs/etc/services.d/dashboard/run old mode 100644 new mode 100755 index e67341fc93..47b4a56602 --- a/netbird-server/rootfs/etc/services.d/dashboard/run +++ b/netbird-server/rootfs/etc/services.d/dashboard/run @@ -9,13 +9,13 @@ set -euo pipefail ENV_FILE="/config/netbird/dashboard/env" if [[ -f "$ENV_FILE" ]]; then - set -a - # shellcheck disable=SC1090 - . "$ENV_FILE" - set +a + set -a + # shellcheck disable=SC1090 + . "$ENV_FILE" + set +a else - bashio::log.error "Missing dashboard env file at ${ENV_FILE}." - bashio::exit.nok + bashio::log.error "Missing dashboard env file at ${ENV_FILE}." + bashio::exit.nok fi bashio::log.info "Preparing NetBird Dashboard assets..." diff --git a/netbird-server/rootfs/etc/services.d/management/run b/netbird-server/rootfs/etc/services.d/management/run old mode 100644 new mode 100755 index d09c88fef3..677f60e92a --- a/netbird-server/rootfs/etc/services.d/management/run +++ b/netbird-server/rootfs/etc/services.d/management/run @@ -14,18 +14,18 @@ MANAGEMENT_PORT=8081 MANAGEMENT_METRICS_PORT=9091 if [[ ! -f "$MANAGEMENT_CONFIG" ]]; then - bashio::log.error "Missing management configuration at ${MANAGEMENT_CONFIG}." - bashio::exit.nok + bashio::log.error "Missing management configuration at ${MANAGEMENT_CONFIG}." + bashio::exit.nok fi bashio::log.info "Starting NetBird Management..." exec /usr/local/bin/netbird-mgmt management \ - --config "$MANAGEMENT_CONFIG" \ - --port "$MANAGEMENT_PORT" \ - --metrics-port "$MANAGEMENT_METRICS_PORT" \ - --log-level "$LOG_LEVEL" \ - --log-file console \ - --disable-anonymous-metrics=false \ - --single-account-mode-domain=netbird.selfhosted \ - --dns-domain=netbird.selfhosted \ - --idp-sign-key-refresh-enabled + --config "$MANAGEMENT_CONFIG" \ + --port "$MANAGEMENT_PORT" \ + --metrics-port "$MANAGEMENT_METRICS_PORT" \ + --log-level "$LOG_LEVEL" \ + --log-file console \ + --disable-anonymous-metrics=false \ + --single-account-mode-domain=netbird.selfhosted \ + --dns-domain=netbird.selfhosted \ + --idp-sign-key-refresh-enabled diff --git a/netbird-server/rootfs/etc/services.d/relay/run b/netbird-server/rootfs/etc/services.d/relay/run old mode 100644 new mode 100755 index 8685fcd1b0..bf67e04093 --- a/netbird-server/rootfs/etc/services.d/relay/run +++ b/netbird-server/rootfs/etc/services.d/relay/run @@ -10,13 +10,13 @@ set -euo pipefail RELAY_ENV_FILE="/config/netbird/relay/relay.env" if [[ -f "$RELAY_ENV_FILE" ]]; then - set -a - # shellcheck disable=SC1090 - . "$RELAY_ENV_FILE" - set +a + set -a + # shellcheck disable=SC1090 + . "$RELAY_ENV_FILE" + set +a else - bashio::log.error "Missing relay env file at ${RELAY_ENV_FILE}." - bashio::exit.nok + bashio::log.error "Missing relay env file at ${RELAY_ENV_FILE}." + bashio::exit.nok fi bashio::log.info "Starting NetBird Relay..." diff --git a/netbird-server/rootfs/etc/services.d/signal/run b/netbird-server/rootfs/etc/services.d/signal/run old mode 100644 new mode 100755 index 725b733bc1..ddbb022a4a --- a/netbird-server/rootfs/etc/services.d/signal/run +++ b/netbird-server/rootfs/etc/services.d/signal/run @@ -13,7 +13,7 @@ LOG_LEVEL="info" bashio::log.info "Starting NetBird Signal on port ${SIGNAL_PORT} (legacy gRPC on 10000)..." exec /usr/local/bin/netbird-signal run \ - --port "$SIGNAL_PORT" \ - --metrics-port "$SIGNAL_METRICS_PORT" \ - --log-level "$LOG_LEVEL" \ - --log-file console + --port "$SIGNAL_PORT" \ + --metrics-port "$SIGNAL_METRICS_PORT" \ + --log-level "$LOG_LEVEL" \ + --log-file console diff --git a/nextcloud/CHANGELOG.md b/nextcloud/CHANGELOG.md index d932da715c..2c51d9e1b0 100644 --- a/nextcloud/CHANGELOG.md +++ b/nextcloud/CHANGELOG.md @@ -1,13 +1,13 @@ - + ## 34.0.3 (2026-08-13) - Update to latest version from linuxserver/docker-nextcloud (changelog : https://github.com/linuxserver/docker-nextcloud/releases) - + ## 34.0.2 (2026-07-25) - Update to latest version from linuxserver/docker-nextcloud (changelog : https://github.com/linuxserver/docker-nextcloud/releases) - + ## 34.0.1 (2026-06-27) - Update to latest version from linuxserver/docker-nextcloud (changelog : https://github.com/linuxserver/docker-nextcloud/releases) - + ## 34.0.0 (2026-06-11) - Update to latest version from linuxserver/docker-nextcloud (changelog : https://github.com/linuxserver/docker-nextcloud/releases) ## 33.0.5 (2026-06-05) diff --git a/nextcloud/README.md b/nextcloud/README.md index 5458755d5c..6d4d00c4fa 100644 --- a/nextcloud/README.md +++ b/nextcloud/README.md @@ -43,7 +43,7 @@ Webui can be found at `:port`. ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `1000` | Group ID for file permissions | | `PUID` | int | `1000` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | @@ -143,7 +143,7 @@ If you use clients for file syncing, the use of SQLite is highly discouraged. and you want to overcome this, follow the below steps: - 1. Install `mariadb` add-on, configure it with some random infos and start it. It is important to start it successfully in order to be seen by `nextcloud` in the network. -- 2. Install `nextcloud` add-on (or restart it if you have already installed), watch the logs until you will notice the following `warning`: +- 1. Install `nextcloud` add-on (or restart it if you have already installed), watch the logs until you will notice the following `warning`: ```bash WARNING: MariaDB addon was found! It can't be configured automatically due to the way Nextcloud works, but you can configure it manually when running the web UI for the first time using those values : @@ -153,8 +153,8 @@ and you want to overcome this, follow the below steps: Host-name : core-mariadb:3306 ``` -- 3. Go back at `mariadb` add-on, configure it with above credentials and restart it. Make sure the add-on is creating the `nextcloud` database. -- 4. Go in the webui and fill all required info. Here you can view an example: +- 1. Go back at `mariadb` add-on, configure it with above credentials and restart it. Make sure the add-on is creating the `nextcloud` database. +- 1. Go in the webui and fill all required info. Here you can view an example: ![image](https://user-images.githubusercontent.com/19391765/207888717-50b43002-a5e2-4782-b5c9-1f582309df2b.png) diff --git a/nginx_webserver_proxy/README.md b/nginx_webserver_proxy/README.md index 803637603c..d5aaf63a66 100644 --- a/nginx_webserver_proxy/README.md +++ b/nginx_webserver_proxy/README.md @@ -35,7 +35,7 @@ This add-on combines a full reverse proxy with a proper static file server, allo ## Configuration | Option | Default | Description | -|--------|---------|-------------| +| -------- | --------- | ------------- | | `static_site_enabled` | `true` | Enable or disable the static file server on port 80 | | `static_site_root` | `/share/www` | Path to serve static files from | | `static_site_prefix` | `/` | URL prefix for the static site (e.g., `/www` for `http://host/www`) | diff --git a/nzbget/CHANGELOG.md b/nzbget/CHANGELOG.md index d2486a9148..c91b426605 100644 --- a/nzbget/CHANGELOG.md +++ b/nzbget/CHANGELOG.md @@ -1,20 +1,20 @@ - + ## v26.3.262 (2026-09-05) - Update to latest version from linuxserver/docker-nzbget (changelog : https://github.com/linuxserver/docker-nzbget/releases) - Upstream tag : v26.3-ls262 - + ## v26.3.261 (2026-08-29) - Update to latest version from linuxserver/docker-nzbget (changelog : https://github.com/linuxserver/docker-nzbget/releases) - Upstream tag : v26.3-ls261 - + ## v26.2.260 (2026-08-22) - Update to latest version from linuxserver/docker-nzbget (changelog : https://github.com/linuxserver/docker-nzbget/releases) - Upstream tag : v26.2-ls260 - + ## v26.2.258 (2026-08-15) - Update to latest version from linuxserver/docker-nzbget (changelog : https://github.com/linuxserver/docker-nzbget/releases) - Upstream tag : v26.2-ls258 - + ## v26.2.257 (2026-08-08) - Update to latest version from linuxserver/docker-nzbget (changelog : https://github.com/linuxserver/docker-nzbget/releases) - Upstream tag : v26.2-ls257 @@ -22,31 +22,31 @@ - Version renamed from `v26.2-ls256`, which Home Assistant could not order and therefore could not reliably offer as an update: every number of the previous version is kept, as a section of its own. The addon itself and the upstream version it tracks are unchanged - + ## v26.2-ls256 (2026-08-01) - Update to latest version from linuxserver/docker-nzbget (changelog : https://github.com/linuxserver/docker-nzbget/releases) - + ## v26.2-ls255 (2026-07-25) - Update to latest version from linuxserver/docker-nzbget (changelog : https://github.com/linuxserver/docker-nzbget/releases) - + ## v26.2-ls254 (2026-07-18) - Update to latest version from linuxserver/docker-nzbget (changelog : https://github.com/linuxserver/docker-nzbget/releases) - + ## v26.2-ls251 (2026-07-04) - Update to latest version from linuxserver/docker-nzbget (changelog : https://github.com/linuxserver/docker-nzbget/releases) - + ## v26.2-ls250 (2026-06-27) - Update to latest version from linuxserver/docker-nzbget (changelog : https://github.com/linuxserver/docker-nzbget/releases) - + ## v26.2-ls249 (2026-06-20) - Update to latest version from linuxserver/docker-nzbget (changelog : https://github.com/linuxserver/docker-nzbget/releases) - + ## v26.1-ls248 (2026-06-13) - Update to latest version from linuxserver/docker-nzbget (changelog : https://github.com/linuxserver/docker-nzbget/releases) - + ## v26.1-ls247 (2026-06-11) - Update to latest version from linuxserver/docker-nzbget (changelog : https://github.com/linuxserver/docker-nzbget/releases) - + ## v26.1-ls246 (2026-06-06) - Update to latest version from linuxserver/docker-nzbget (changelog : https://github.com/linuxserver/docker-nzbget/releases) diff --git a/nzbget/README.md b/nzbget/README.md index 88d77884d9..2050214c53 100644 --- a/nzbget/README.md +++ b/nzbget/README.md @@ -41,7 +41,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/nzbget/rootfs/etc/services.d/nginx/run b/nzbget/rootfs/etc/services.d/nginx/run old mode 100644 new mode 100755 diff --git a/obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/addon-init/script b/obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/addon-init/script old mode 100755 new mode 100644 index 963956c739..e1783817f5 --- a/obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/addon-init/script +++ b/obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/addon-init/script @@ -8,12 +8,12 @@ # run first. NPM's image uses s6-overlay v3 and has no /etc/cont-init.d. if [ ! -L /etc/letsencrypt ]; then - mkdir -p /data/letsencrypt - if [ -d /etc/letsencrypt ] && [ -n "$(ls -A /etc/letsencrypt 2> /dev/null)" ]; then - cp -a /etc/letsencrypt/. /data/letsencrypt/ 2> /dev/null || true - fi - rm -rf /etc/letsencrypt - ln -sf /data/letsencrypt /etc/letsencrypt + mkdir -p /data/letsencrypt + if [ -d /etc/letsencrypt ] && [ -n "$(ls -A /etc/letsencrypt 2>/dev/null)" ]; then + cp -a /etc/letsencrypt/. /data/letsencrypt/ 2>/dev/null || true + fi + rm -rf /etc/letsencrypt + ln -sf /data/letsencrypt /etc/letsencrypt fi mkdir -p /data/letsencrypt diff --git a/obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/addon-init/up b/obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/addon-init/up old mode 100755 new mode 100644 diff --git a/obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/couchdb/finish b/obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/couchdb/finish old mode 100755 new mode 100644 diff --git a/obsidian_syncserver_solo/CHANGELOG.md b/obsidian_syncserver_solo/CHANGELOG.md index e6f29bbcf4..9964fa3332 100644 --- a/obsidian_syncserver_solo/CHANGELOG.md +++ b/obsidian_syncserver_solo/CHANGELOG.md @@ -1,4 +1,4 @@ - + ## 3.5.2.1 (2026-08-13) - Update to latest version from library/couchdb - Upstream tag : 3.5.2.1-nouveau diff --git a/obsidian_syncserver_ssl/CHANGELOG.md b/obsidian_syncserver_ssl/CHANGELOG.md index abf1f29921..89aaf6fe36 100644 --- a/obsidian_syncserver_ssl/CHANGELOG.md +++ b/obsidian_syncserver_ssl/CHANGELOG.md @@ -1,4 +1,4 @@ - + ## 3.5.2.1 (2026-08-13) - Update to latest version from library/couchdb - Upstream tag : 3.5.2.1-nouveau diff --git a/openproject/CHANGELOG.md b/openproject/CHANGELOG.md index a6b5e46257..bc41f79837 100644 --- a/openproject/CHANGELOG.md +++ b/openproject/CHANGELOG.md @@ -1,19 +1,19 @@ - + ## 17.8.0 (2026-09-05) - Update to latest version from opf/openproject (changelog : https://github.com/opf/openproject/releases) - + ## 17.7.2 (2026-08-13) - Update to latest version from opf/openproject (changelog : https://github.com/opf/openproject/releases) - + ## 17.7.1 (2026-08-08) - Update to latest version from opf/openproject (changelog : https://github.com/opf/openproject/releases) - + ## 17.6.0 (2026-07-18) - Update to latest version from opf/openproject (changelog : https://github.com/opf/openproject/releases) - + ## 17.5.1 (2026-06-17) - Update to latest version from opf/openproject (changelog : https://github.com/opf/openproject/releases) - + ## 17.5.0 (2026-06-11) - Update to latest version from opf/openproject (changelog : https://github.com/opf/openproject/releases) diff --git a/photoprism/CHANGELOG.md b/photoprism/CHANGELOG.md index 4eed9c128e..e9a4730eaf 100644 --- a/photoprism/CHANGELOG.md +++ b/photoprism/CHANGELOG.md @@ -2,7 +2,7 @@ - Version renamed from `ubuntu-2026-07-28`, which Home Assistant could not order and therefore could not reliably offer as an update: every number of the previous version is kept, as a section of its own. The addon itself and the upstream version it tracks are unchanged - + ## ubuntu-2026-07-28 (2026-07-28) - Update to latest version from photoprism/photoprism ## ubuntu-2026-06-01 (2026-06-01) @@ -24,7 +24,7 @@ ## ubuntu-2025-11-30 (2025-11-30) - Update to latest version from photoprism/photoprism -## (2025-12-23) +## (2025-12-23) - Update to latest version from photoprism/photoprism ## ubuntu-2025-11-30-2 (2025-12-06) - Increase healthcheck interval to reduce background CPU usage diff --git a/photoprism/README.md b/photoprism/README.md index b466a638e3..1a1744698f 100644 --- a/photoprism/README.md +++ b/photoprism/README.md @@ -67,7 +67,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `ssl` | bool | `false` | Enable HTTPS for the web interface | | `certfile` | str | `fullchain.pem` | SSL certificate file (must be in /ssl) | | `keyfile` | str | `privkey.pem` | SSL key file (must be in /ssl) | diff --git a/piwigo/README.md b/piwigo/README.md index 356c45301c..8d2d008f59 100644 --- a/piwigo/README.md +++ b/piwigo/README.md @@ -63,7 +63,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/plex/CHANGELOG.md b/plex/CHANGELOG.md index 9d330ee3ed..d12d799ff2 100644 --- a/plex/CHANGELOG.md +++ b/plex/CHANGELOG.md @@ -1,16 +1,16 @@ - + ## 1.43.3.10896.322 (2026-09-05) - Update to latest version from linuxserver/docker-plex (changelog : https://github.com/linuxserver/docker-plex/releases) - Upstream tag : 1.43.3.10896-cb3ebc72d-ls322 - + ## 1.43.3.10896.321 (2026-08-22) - Update to latest version from linuxserver/docker-plex (changelog : https://github.com/linuxserver/docker-plex/releases) - Upstream tag : 1.43.3.10896-cb3ebc72d-ls321 - + ## 1.43.3.10861.319 (2026-08-13) - Update to latest version from linuxserver/docker-plex (changelog : https://github.com/linuxserver/docker-plex/releases) - Upstream tag : 1.43.3.10861-07dfddaeb-ls319 - + ## 1.43.3.10861.318 (2026-08-08) - Update to latest version from linuxserver/docker-plex (changelog : https://github.com/linuxserver/docker-plex/releases) - Upstream tag : 1.43.3.10861-07dfddaeb-ls318 @@ -18,19 +18,19 @@ - Version renamed from `1.43.3.10828-00f62d37d-ls316`, which Home Assistant could not order and therefore could not reliably offer as an update: every number of the previous version is kept, as a section of its own. The addon itself and the upstream version it tracks are unchanged - + ## 1.43.3.10828-00f62d37d-ls316 (2026-08-01) - Update to latest version from linuxserver/docker-plex (changelog : https://github.com/linuxserver/docker-plex/releases) - + ## 1.43.3.10828-00f62d37d-ls315 (2026-07-18) - Update to latest version from linuxserver/docker-plex (changelog : https://github.com/linuxserver/docker-plex/releases) - + ## 1.43.2.10687-563d026ea-ls311 (2026-07-04) - Update to latest version from linuxserver/docker-plex (changelog : https://github.com/linuxserver/docker-plex/releases) - + ## 1.43.2.10687-563d026ea-ls310 (2026-06-23) - Update to latest version from linuxserver/docker-plex (changelog : https://github.com/linuxserver/docker-plex/releases) - + ## 1.43.2.10687-563d026ea-ls308 (2026-06-11) - Update to latest version from linuxserver/docker-plex (changelog : https://github.com/linuxserver/docker-plex/releases) diff --git a/plex/README.md b/plex/README.md index a5ace650eb..71294d7e3e 100644 --- a/plex/README.md +++ b/plex/README.md @@ -49,7 +49,7 @@ Webui can be found at `:32400`. ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/plex/rootfs/etc/cont-init.d/21-folders.sh b/plex/rootfs/etc/cont-init.d/21-folders.sh index 4e0d4e50a1..6ff9091d6b 100755 --- a/plex/rootfs/etc/cont-init.d/21-folders.sh +++ b/plex/rootfs/etc/cont-init.d/21-folders.sh @@ -34,7 +34,7 @@ copy_tree() { local src="$1" local dst="$2" - if command -v rsync >/dev/null 2>&1; then + if command -v rsync > /dev/null 2>&1; then # Trailing slashes are important: copy contents into dst rsync -aH --numeric-ids --inplace --info=progress2 "${src%/}/" "${dst%/}/" else @@ -50,7 +50,7 @@ copy_tree() { LAST_LOCATION="" if [[ -f "$LAST_FILE" ]]; then - LAST_LOCATION="$(cat "$LAST_FILE" 2>/dev/null || true)" + LAST_LOCATION="$(cat "$LAST_FILE" 2> /dev/null || true)" fi OLD_DIR="" diff --git a/portainer/CHANGELOG.md b/portainer/CHANGELOG.md index bc4a3c8e14..f03ecac815 100644 --- a/portainer/CHANGELOG.md +++ b/portainer/CHANGELOG.md @@ -1,13 +1,13 @@ - + ## 2.45.0 (2026-08-29) - Update to latest version from portainer/portainer (changelog : https://github.com/portainer/portainer/releases) - + ## 2.44.0.1 (2026-08-05) - Ingress: request uncompressed responses from Portainer so they carry a Content-Length and stay on the Home Assistant relay's buffered path. Portainer compresses its own responses, and the Accept-Encoding strip in proxy_params.conf never applied because the location block declares its own proxy_set_header directives, which makes nginx discard the server-level ones. Partial mitigation for #2766: the page itself and all assets under 4 MB are now buffered, but the two large JavaScript bundles still exceed the relay's 4 MB buffering threshold. Direct access on the web UI port keeps compression - + ## 2.44.0 (2026-08-01) - Update to latest version from portainer/portainer (changelog : https://github.com/portainer/portainer/releases) - + ## 2.43.0.1 (2026-07-24) - Ingress: disable nginx gzip re-compression of proxied responses so Home Assistant relays them via the buffered path (addresses 502 Bad Gateway via ingress, #2766) diff --git a/portainer/README.md b/portainer/README.md index 67094327df..f0fea7d4ce 100644 --- a/portainer/README.md +++ b/portainer/README.md @@ -76,7 +76,7 @@ The default username is "admin" and the password is described in the startup log ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `ssl` | bool | `false` | Enable HTTPS for web interface | | `certfile` | str | `fullchain.pem` | SSL certificate file (in `/ssl/`) | | `keyfile` | str | `privkey.pem` | SSL private key file (in `/ssl/`) | diff --git a/portainer_agent/CHANGELOG.md b/portainer_agent/CHANGELOG.md index 256b82f833..7155224635 100644 --- a/portainer_agent/CHANGELOG.md +++ b/portainer_agent/CHANGELOG.md @@ -1,4 +1,4 @@ - + ## 2.44.0.2 (2026-08-29) - Update to latest version from portainer/agent - Upstream tag : sts @@ -59,7 +59,7 @@ ## alpine-sts (2025-12-24) - Update to latest version from portainer/agent -## (2025-12-23) +## (2025-12-23) - Update to latest version from portainer/agent - The Home Assistant project has deprecated support for the armv7, armhf and i386 architectures. Support wil be fully dropped in the upcoming Home Assistant 2025.12 release diff --git a/portainer_agent/rootfs/etc/services.d/portainer_agent/run b/portainer_agent/rootfs/etc/services.d/portainer_agent/run index fd47fc233f..0a679c1f79 100755 --- a/portainer_agent/rootfs/etc/services.d/portainer_agent/run +++ b/portainer_agent/rootfs/etc/services.d/portainer_agent/run @@ -12,7 +12,7 @@ export HOSTNAME="${container_name}" args=() if bashio::config.has_value 'PORTAINER_AGENT_ARGS'; then - read -r -a args <<<"$(bashio::config 'PORTAINER_AGENT_ARGS')" + read -r -a args <<< "$(bashio::config 'PORTAINER_AGENT_ARGS')" fi ./agent "${args[@]}" diff --git a/portainer_agent/rootfs/usr/sbin/healthcheck b/portainer_agent/rootfs/usr/sbin/healthcheck index 0fbd41134e..2fd71dc565 100644 --- a/portainer_agent/rootfs/usr/sbin/healthcheck +++ b/portainer_agent/rootfs/usr/sbin/healthcheck @@ -5,7 +5,7 @@ # would fail before this script runs. Nothing here needs the s6 environment. if [ -f "/tmp/healthcheck-signal" ]; then - curl -k --fail https://127.0.0.1:9001/ping || exit 1 + curl -k --fail https://127.0.0.1:9001/ping || exit 1 else - touch /tmp/healthcheck-signal -fi \ No newline at end of file + touch /tmp/healthcheck-signal +fi diff --git a/portainer_be/CHANGELOG.md b/portainer_be/CHANGELOG.md index aabacd5fa5..4cd32312b9 100644 --- a/portainer_be/CHANGELOG.md +++ b/portainer_be/CHANGELOG.md @@ -2,7 +2,7 @@ - Version renamed from `sts`, which Home Assistant could not order and therefore could not reliably offer as an update: the previous version held no number that could order it, so the date of this change is used. The addon itself and the upstream version it tracks are unchanged - + ## sts (2026-08-01) - Update to latest version from portainer/portainer-ee ## 2.43.0 (2026-07-27) diff --git a/portainer_be/README.md b/portainer_be/README.md index 635ad840c2..bf19883849 100644 --- a/portainer_be/README.md +++ b/portainer_be/README.md @@ -77,7 +77,7 @@ The default username is "admin" and the password is the value you set in the add ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `ssl` | bool | `false` | Enable HTTPS for web interface | | `certfile` | str | `fullchain.pem` | SSL certificate file (in `/ssl/`) | | `keyfile` | str | `privkey.pem` | SSL private key file (in `/ssl/`) | diff --git a/postgres_15/README.md b/postgres_15/README.md index c0a4b56dbb..4d767691ee 100644 --- a/postgres_15/README.md +++ b/postgres_15/README.md @@ -41,7 +41,7 @@ Default user: `postgres`, password: set by `POSTGRES_PASSWORD` ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `POSTGRES_PASSWORD` | password | `homeassistant` | Password for the postgres user | | `POSTGRES_USER` | str | | Optional custom username | | `POSTGRES_DB` | str | | Optional default database name | diff --git a/postgres_15/rootfs/etc/cont-init.d/99-run.sh b/postgres_15/rootfs/etc/cont-init.d/99-run.sh index d3acf9b187..c14d44903b 100755 --- a/postgres_15/rootfs/etc/cont-init.d/99-run.sh +++ b/postgres_15/rootfs/etc/cont-init.d/99-run.sh @@ -108,7 +108,7 @@ wait_for_postgres() { while ! pg_isready -h "$DB_HOSTNAME" -p "$DB_PORT" -U "$DB_USERNAME" > /dev/null 2>&1; do tries=$((tries + 1)) [ "$tries" -ge 60 ] && { - bashio::log.error "Postgres did not start after 2 minutes, aborting." + bashio::log.error "Postgres did not start after 2 minutes, aborting." exit 1 } echo "PostgreSQL is starting up... ($tries/60)" diff --git a/prowlarr/CHANGELOG.md b/prowlarr/CHANGELOG.md index 92df573fed..9535278154 100644 --- a/prowlarr/CHANGELOG.md +++ b/prowlarr/CHANGELOG.md @@ -1,28 +1,28 @@ - + ## 2.6.3.5608.14 (2026-09-05) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) - Upstream tag : nightly-2.6.3.5608-ls14 - + ## 2.6.2.5583.12 (2026-08-29) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) - Upstream tag : nightly-2.6.2.5583-ls12 - + ## 2.6.2.5581.11 (2026-08-29) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) - Upstream tag : nightly-2.6.2.5581-ls11 - + ## 2.6.2.5558.10 (2026-08-22) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) - Upstream tag : nightly-2.6.2.5558-ls10 - + ## 2.6.2.5548.10 (2026-08-13) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) - Upstream tag : nightly-2.6.2.5548-ls10 - + ## 2.6.2.5534.9 (2026-08-11) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) - Upstream tag : nightly-2.6.2.5534-ls9 - + ## 2.6.2.5517.9 (2026-08-02) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) - Upstream tag : nightly-2.6.2.5517-ls9 @@ -30,19 +30,19 @@ - Version renamed from `nightly-2.6.1.5509-ls8`, which Home Assistant could not order and therefore could not reliably offer as an update: every number of the previous version is kept, as a section of its own. The addon itself and the upstream version it tracks are unchanged - + ## nightly-2.6.1.5509-ls8 (2026-08-01) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) - + ## nightly-2.6.0.5494-ls8 (2026-07-25) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) - + ## nightly-2.5.2.5487-ls8 (2026-07-22) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) - + ## nightly-2.5.1.5478-ls7 (2026-07-18) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) - + ## develop-2.5.1.5464-ls268 (2026-07-13) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) @@ -52,16 +52,16 @@ ## nightly-2.5.0.5453-ls4 (2026-07-04) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) - + ## nightly-2.5.0.5443-ls4 (2026-06-29) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) ## nightly-2.5.0.5422-ls3 (2026-06-27) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) - + ## nightly-2.5.0.5422-ls2 (2026-06-20) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) - + ## 2.4.0.5397-ls149 (2026-06-11) - Update to latest version from linuxserver/docker-prowlarr (changelog : https://github.com/linuxserver/docker-prowlarr/releases) ## nightly-2.4.0.5391-ls238 (2026-06-05) diff --git a/prowlarr/README.md b/prowlarr/README.md index 1f026d30e5..206010561f 100644 --- a/prowlarr/README.md +++ b/prowlarr/README.md @@ -59,7 +59,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/qbittorrent/README.md b/qbittorrent/README.md index 26b381458a..a59822b3af 100644 --- a/qbittorrent/README.md +++ b/qbittorrent/README.md @@ -55,7 +55,7 @@ Network disk is mounted to `/mnt/`. You need to map the exposed port ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/qbittorrent/rootfs/etc/cont-init.d/93-openvpn.sh b/qbittorrent/rootfs/etc/cont-init.d/93-openvpn.sh index 8633755cf5..c1fb45286d 100755 --- a/qbittorrent/rootfs/etc/cont-init.d/93-openvpn.sh +++ b/qbittorrent/rootfs/etc/cont-init.d/93-openvpn.sh @@ -55,7 +55,7 @@ if bashio::config.has_value "openvpn_config"; then fi if [[ -z "${openvpn_config}" ]]; then bashio::log.info 'openvpn_config option left empty. Attempting automatic selection.' - mapfile -t configs < <(find /config/openvpn -maxdepth 1 \( -type f -name '*.conf' -o -name '*.ovpn' \) -print) + mapfile -t configs < <(find /config/openvpn -maxdepth 1 \( -type f -name '*.conf' -o -name '*.ovpn' \) -print) if [ "${#configs[@]}" -eq 0 ]; then bashio::log.fatal 'OpenVPN is enabled but no .conf or .ovpn file was found in /config/openvpn.' bashio::addon.stop @@ -91,7 +91,7 @@ openvpn_runtime_config="${OPENVPN_STATE_DIR}/${interface_name}.conf" cp "${openvpn_config}" "${openvpn_runtime_config}" chmod 600 "${openvpn_runtime_config}" -dos2unix "${openvpn_runtime_config}" >/dev/null 2>&1 || true +dos2unix "${openvpn_runtime_config}" > /dev/null 2>&1 || true sed -i '/^[[:space:]]*[;#]/d' "${openvpn_runtime_config}" sed -i 's/#.*//' "${openvpn_runtime_config}" sed -i '/^[[:space:]]*$/d' "${openvpn_runtime_config}" diff --git a/qbittorrent/rootfs/etc/cont-init.d/94-wireguard.sh b/qbittorrent/rootfs/etc/cont-init.d/94-wireguard.sh index 833084bd48..ec9a1702bb 100755 --- a/qbittorrent/rootfs/etc/cont-init.d/94-wireguard.sh +++ b/qbittorrent/rootfs/etc/cont-init.d/94-wireguard.sh @@ -36,7 +36,7 @@ if bashio::config.has_value "wireguard_config"; then fi if [[ -z "${wireguard_config}" ]]; then bashio::log.info 'wireguard_config option left empty. Attempting automatic selection.' - mapfile -t configs < <(find /config/wireguard -maxdepth 1 -type f -name '*.conf' -print) + mapfile -t configs < <(find /config/wireguard -maxdepth 1 -type f -name '*.conf' -print) if [ "${#configs[@]}" -eq 0 ]; then bashio::log.fatal 'WireGuard is enabled but no .conf file was found in /config/wireguard.' bashio::addon.stop @@ -71,7 +71,7 @@ wireguard_runtime_config="${WIREGUARD_STATE_DIR}/${interface_name}.conf" cp "${wireguard_config}" "${wireguard_runtime_config}" chmod 600 "${wireguard_runtime_config}" -dos2unix "${wireguard_runtime_config}" >/dev/null 2>&1 || true +dos2unix "${wireguard_runtime_config}" > /dev/null 2>&1 || true sed -i '/^[[:space:]]*[;#]/d' "${wireguard_runtime_config}" sed -i 's/#.*//' "${wireguard_runtime_config}" sed -i '/^[[:space:]]*$/d' "${wireguard_runtime_config}" diff --git a/qbittorrent/rootfs/etc/cont-init.d/95-vpn-monitor.sh b/qbittorrent/rootfs/etc/cont-init.d/95-vpn-monitor.sh index 1e9f430032..8a62c1b9a4 100755 --- a/qbittorrent/rootfs/etc/cont-init.d/95-vpn-monitor.sh +++ b/qbittorrent/rootfs/etc/cont-init.d/95-vpn-monitor.sh @@ -23,7 +23,7 @@ _fetch_public_ip() { mapfile -t shuffled_urls < <(printf "%s\n" "${urls[@]}" | shuf) # Loop through the now-randomized list for url in "${shuffled_urls[@]}"; do - resp=$(curl -fsS --max-time 5 "${url}" 2>/dev/null || true) + resp=$(curl -fsS --max-time 5 "${url}" 2> /dev/null || true) resp="${resp//[[:space:]]/}" # Validate IPv4 or IPv6 diff --git a/qbittorrent/rootfs/etc/s6-overlay/s6-rc.d/svc-qbittorrent/run b/qbittorrent/rootfs/etc/s6-overlay/s6-rc.d/svc-qbittorrent/run old mode 100644 new mode 100755 diff --git a/qbittorrent/rootfs/etc/services.d/timer/run b/qbittorrent/rootfs/etc/services.d/timer/run old mode 100644 new mode 100755 diff --git a/qbittorrent/rootfs/etc/services.d/vpn-monitor/run b/qbittorrent/rootfs/etc/services.d/vpn-monitor/run index 707b20f628..d454796aa2 100755 --- a/qbittorrent/rootfs/etc/services.d/vpn-monitor/run +++ b/qbittorrent/rootfs/etc/services.d/vpn-monitor/run @@ -33,7 +33,7 @@ _fetch_public_ip() { mapfile -t shuffled_urls < <(printf "%s\n" "${urls[@]}" | shuf) for url in "${shuffled_urls[@]}"; do - resp=$(curl -fsS --max-time 5 "${curl_iface_opts[@]}" "${url}" 2>/dev/null || true) + resp=$(curl -fsS --max-time 5 "${curl_iface_opts[@]}" "${url}" 2> /dev/null || true) resp="${resp//[[:space:]]/}" if [[ "${resp}" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] || [[ "${resp}" =~ ^[0-9a-fA-F:]+$ ]]; then @@ -81,7 +81,7 @@ get_ip_info() { url="${info_url%/}/${ip}/json" fi - if json="$(curl -fsS --max-time 10 "${url}" 2>/dev/null || true)" && [[ -n "${json}" ]]; then + if json="$(curl -fsS --max-time 10 "${url}" 2> /dev/null || true)" && [[ -n "${json}" ]]; then country="$( printf '%s\n' "${json}" \ | sed -n 's/.*"country"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' \ @@ -151,7 +151,7 @@ elif [[ "${vpn_wireguard}" == true ]]; then VPN_INTERFACE=$(cat "/var/run/wireguard/interface") bashio::log.info "VPN monitor set to query external IP through interface ${VPN_INTERFACE} (interface binding)." fi -if [[ -z "${VPN_INTERFACE}" ]] || ! ip link show "${VPN_INTERFACE}" > /dev/null 2>&1 ; then +if [[ -z "${VPN_INTERFACE}" ]] || ! ip link show "${VPN_INTERFACE}" > /dev/null 2>&1; then bashio::log.error "VPN interface not found." bashio::addon.stop exit 1 @@ -178,7 +178,8 @@ read -r VPN_IP VPN_COUNTRY <<< "${VPN_INFO_OUT}" bashio::log.info "VPN external IP: ${VPN_IP} (${VPN_COUNTRY})" while true; do - sleep "${VPN_CHECK_INTERVAL}" & wait $! + sleep "${VPN_CHECK_INTERVAL}" & + wait $! if ! current_out="$(get_ip_info)"; then bashio::log.warning "Failed to refresh external IP; keeping previous assumptions." diff --git a/qbittorrent/rootfs/etc/services.d/vpn-upnp/run b/qbittorrent/rootfs/etc/services.d/vpn-upnp/run old mode 100644 new mode 100755 index 9aba7d6705..dd3c6cd87b --- a/qbittorrent/rootfs/etc/services.d/vpn-upnp/run +++ b/qbittorrent/rootfs/etc/services.d/vpn-upnp/run @@ -100,7 +100,7 @@ _pnat_get_gw() { for n in {1..254}; do local try_ip="$(echo "${ipv4}" | cut -d'.' -f1-3).${n}" if [ "${try_ip}" != "${ipv4}" ]; then - if nc -4 -vw1 "${try_ip}" 1 &>/dev/null 2>&1; then + if nc -4 -vw1 "${try_ip}" 1 &> /dev/null 2>&1; then config["IPv4Gateway"]=${try_ip} return 0 fi @@ -174,7 +174,7 @@ _qbt_check_sid() { fi } -_qbt_isreachable(){ +_qbt_isreachable() { _cmd "nc -4 -vw 5 ${config["Server"]} ${config["Port"]} &>/dev/null 2>&1" return $? } @@ -249,13 +249,13 @@ pnat_set() { _parse_config "/config/qBittorrent/qBittorrent.conf" -config["Interval"]=$(( ${VPN_UPNP_INTERVAL} + (${VPN_UPNP_INTERVAL} / 2) )) +config["Interval"]=$((${VPN_UPNP_INTERVAL} + (${VPN_UPNP_INTERVAL} / 2))) bashio::log.info "VPN UPnP enabled, starting NAT-PMP/UPnP monitor with an interval of ${VPN_UPNP_INTERVAL} seconds (UPnP lease interval: ${config["Interval"]} seconds)." -while true; -do - sleep ${VPN_UPNP_INTERVAL} & wait $! +while true; do + sleep ${VPN_UPNP_INTERVAL} & + wait $! if pnat_set; then bashio::log.info "NAT-PMP/UPnP Ok!" diff --git a/qbittorrent/rootfs/usr/local/sbin/vpn b/qbittorrent/rootfs/usr/local/sbin/vpn old mode 100755 new mode 100644 diff --git a/radarr/CHANGELOG.md b/radarr/CHANGELOG.md index b01d557ea7..cef7876822 100644 --- a/radarr/CHANGELOG.md +++ b/radarr/CHANGELOG.md @@ -1,11 +1,11 @@ - + ## 6.3.0.10514.1 (2026-08-11) - Bump the addon version so Home Assistant offers the rebuilt image. The `6.3.0.10514` tag was rebuilt on 2026-08-03 and now ships LinuxServer.io `ls313` instead of the `ls311` build that existing installations pulled, but because the addon version string was unchanged the Supervisor saw nothing new and never offered the update. Radarr itself is still 6.3.0.10514 — only the LinuxServer.io base image moved ## 6.3.0.10514 (2026-07-13) - Update to latest version from linuxserver/docker-radarr (changelog : https://github.com/linuxserver/docker-radarr/releases) - + ## 6.2.1.10461 (2026-06-11) - Update to latest version from linuxserver/docker-radarr (changelog : https://github.com/linuxserver/docker-radarr/releases) diff --git a/radarr/README.md b/radarr/README.md index c08f0e2b28..7430bc9081 100644 --- a/radarr/README.md +++ b/radarr/README.md @@ -60,7 +60,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/readarr/README.md b/readarr/README.md index 57f572cb33..008c691977 100644 --- a/readarr/README.md +++ b/readarr/README.md @@ -57,7 +57,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/readarr/rootfs/etc/services.d/nginx/run b/readarr/rootfs/etc/services.d/nginx/run old mode 100644 new mode 100755 diff --git a/requestrr/README.md b/requestrr/README.md index a26d644b16..ede1065e15 100644 --- a/requestrr/README.md +++ b/requestrr/README.md @@ -60,7 +60,7 @@ Run the addon first, then customize the config file created in `/addon_configs/d ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/sabnzbd/CHANGELOG.md b/sabnzbd/CHANGELOG.md index 2fb75b05c6..bc59b8aa7d 100644 --- a/sabnzbd/CHANGELOG.md +++ b/sabnzbd/CHANGELOG.md @@ -1,7 +1,7 @@ - + ## 5.1.2 (2026-08-29) - Update to latest version from linuxserver/docker-sabnzbd (changelog : https://github.com/linuxserver/docker-sabnzbd/releases) - + ## 5.1.1.3 (2026-08-25) - Fixed ingress returning `403 External internet access denied` when Home Assistant is reached from outside the local network. SABnzbd's `verify_xff_header` option, which is on by default, refuses any request whose `X-Forwarded-For` chain contains a non-local address, so the proxy no longer forwards that header. @@ -11,10 +11,10 @@ ## 5.1.1 (2026-08-22) - Update to latest version from linuxserver/docker-sabnzbd (changelog : https://github.com/linuxserver/docker-sabnzbd/releases) - + ## 5.1.0 (2026-08-13) - Update to latest version from linuxserver/docker-sabnzbd (changelog : https://github.com/linuxserver/docker-sabnzbd/releases) - + ## 5.0.4 (2026-06-11) - Update to latest version from linuxserver/docker-sabnzbd (changelog : https://github.com/linuxserver/docker-sabnzbd/releases) diff --git a/sabnzbd/README.md b/sabnzbd/README.md index 5b810a8c72..2d8a7479a7 100644 --- a/sabnzbd/README.md +++ b/sabnzbd/README.md @@ -41,7 +41,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/sabnzbd/rootfs/etc/services.d/nginx/finish b/sabnzbd/rootfs/etc/services.d/nginx/finish old mode 100755 new mode 100644 diff --git a/scrutiny/CHANGELOG.md b/scrutiny/CHANGELOG.md index 87e673d510..3e0dcf0622 100644 --- a/scrutiny/CHANGELOG.md +++ b/scrutiny/CHANGELOG.md @@ -1,16 +1,16 @@ - + ## v1.70.0 (2026-08-29) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.69.1 (2026-08-22) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.69.0 (2026-08-15) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.68.0 (2026-08-01) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.67.0-8 (2026-07-18) - Keep content-level backup validation and atomic replacement tests while removing a blocking synthetic FIFO test fixture from cross-architecture builds. @@ -28,19 +28,19 @@ ## v1.67.0 (2026-07-18) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.66.0 (2026-07-13) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.65.0 (2026-07-04) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.64.0 (2026-06-20) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.63.0 (2026-06-13) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.62.4 (2026-06-11) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) ## v1.62.3 (2026-06-05) diff --git a/scrutiny/README.md b/scrutiny/README.md index b42cb0af37..de81a11025 100644 --- a/scrutiny/README.md +++ b/scrutiny/README.md @@ -52,7 +52,7 @@ It automatically mounts all local drives. ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `Updates` | list | `Hourly` | Update schedule (Quarterly/Hourly/Daily/Weekly/Custom) | | `Updates_custom_time` | str | | Custom update interval (e.g., "5m", "2h", "1w", "2mo") | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/scrutiny/rootfs/usr/local/bin/scrutiny-ha-influxdb-preflight b/scrutiny/rootfs/usr/local/bin/scrutiny-ha-influxdb-preflight index 7d99aac7d8..1630139b71 100644 --- a/scrutiny/rootfs/usr/local/bin/scrutiny-ha-influxdb-preflight +++ b/scrutiny/rootfs/usr/local/bin/scrutiny-ha-influxdb-preflight @@ -15,212 +15,212 @@ source_manifest="" archive_manifest="" log() { - local level="$1" - local message="$2" - printf 'time="%s" level=%s msg="%s" type=ha-influxdb-upgrade-preflight\n' \ - "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "$level" "$message" + local level="$1" + local message="$2" + printf 'time="%s" level=%s msg="%s" type=ha-influxdb-upgrade-preflight\n' \ + "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "$level" "$message" } cleanup() { - rm -f "$temporary_backup" "$marker_tmp" - if [[ -n "$source_manifest" ]]; then rm -f "$source_manifest"; fi - if [[ -n "$archive_manifest" ]]; then rm -f "$archive_manifest"; fi + rm -f "$temporary_backup" "$marker_tmp" + if [[ -n "$source_manifest" ]]; then rm -f "$source_manifest"; fi + if [[ -n "$archive_manifest" ]]; then rm -f "$archive_manifest"; fi } trap cleanup EXIT has_existing_data() { - if [[ -e "${data_dir}/influxd.bolt" || -e "${data_dir}/influxd.sqlite" ]]; then - return 0 - fi + if [[ -e "${data_dir}/influxd.bolt" || -e "${data_dir}/influxd.sqlite" ]]; then + return 0 + fi - if [[ -d "${data_dir}/engine" ]] && find "${data_dir}/engine" -mindepth 1 -print -quit | grep -q .; then - return 0 - fi + if [[ -d "${data_dir}/engine" ]] && find "${data_dir}/engine" -mindepth 1 -print -quit | grep -q .; then + return 0 + fi - return 1 + return 1 } validate_archive() { - local archive="$1" - [[ -s "$archive" ]] || return 1 - gzip -t "$archive" >/dev/null 2>&1 || return 1 - tar -tzf "$archive" >/dev/null 2>&1 + local archive="$1" + [[ -s "$archive" ]] || return 1 + gzip -t "$archive" >/dev/null 2>&1 || return 1 + tar -tzf "$archive" >/dev/null 2>&1 } reset_manifests() { - rm -f "$source_manifest" "$archive_manifest" - source_manifest="" - archive_manifest="" + rm -f "$source_manifest" "$archive_manifest" + source_manifest="" + archive_manifest="" } validate_backup_against_source() { - local archive="$1" - local relative_path - local source_path - local archive_member - local listing - local source_checksum - local archive_checksum - local source_target - local archive_target + local archive="$1" + local relative_path + local source_path + local archive_member + local listing + local source_checksum + local archive_checksum + local source_target + local archive_target - validate_archive "$archive" || return 1 - source_manifest="$(mktemp)" - archive_manifest="$(mktemp)" + validate_archive "$archive" || return 1 + source_manifest="$(mktemp)" + archive_manifest="$(mktemp)" - ( - cd "$data_dir" - find . -mindepth 1 -print | sed -e 's#^\./##' -e 's#/$##' | LC_ALL=C sort - ) > "$source_manifest" + ( + cd "$data_dir" + find . -mindepth 1 -print | sed -e 's#^\./##' -e 's#/$##' | LC_ALL=C sort + ) >"$source_manifest" - tar -tzf "$archive" | \ - sed -e "s#^${archive_root}/##" -e '/^$/d' -e 's#/$##' | \ - LC_ALL=C sort > "$archive_manifest" + tar -tzf "$archive" | + sed -e "s#^${archive_root}/##" -e '/^$/d' -e 's#/$##' | + LC_ALL=C sort >"$archive_manifest" - if ! cmp -s "$source_manifest" "$archive_manifest"; then - reset_manifests - return 1 - fi + if ! cmp -s "$source_manifest" "$archive_manifest"; then + reset_manifests + return 1 + fi - while IFS= read -r relative_path; do - source_path="${data_dir}/${relative_path}" - archive_member="${archive_root}/${relative_path}" - listing="$(tar -tvzf "$archive" -- "$archive_member" 2>/dev/null)" || { - reset_manifests - return 1 - } + while IFS= read -r relative_path; do + source_path="${data_dir}/${relative_path}" + archive_member="${archive_root}/${relative_path}" + listing="$(tar -tvzf "$archive" -- "$archive_member" 2>/dev/null)" || { + reset_manifests + return 1 + } - if [[ -L "$source_path" ]]; then - [[ "${listing:0:1}" == "l" ]] || { - reset_manifests - return 1 - } - source_target="$(readlink "$source_path")" - archive_target="${listing##* -> }" - [[ "$source_target" == "$archive_target" ]] || { - reset_manifests - return 1 - } - elif [[ -f "$source_path" ]]; then - [[ "${listing:0:1}" == "-" || "${listing:0:1}" == "h" ]] || { - reset_manifests - return 1 - } - source_checksum="$(sha256sum "$source_path" | awk '{print $1}')" - archive_checksum="$(tar -xOzf "$archive" -- "$archive_member" | sha256sum | awk '{print $1}')" - [[ "$source_checksum" == "$archive_checksum" ]] || { - reset_manifests - return 1 - } - elif [[ -d "$source_path" ]]; then - [[ "${listing:0:1}" == "d" ]] || { - reset_manifests - return 1 - } - else - reset_manifests - return 1 - fi - done < "$source_manifest" + if [[ -L "$source_path" ]]; then + [[ "${listing:0:1}" == "l" ]] || { + reset_manifests + return 1 + } + source_target="$(readlink "$source_path")" + archive_target="${listing##* -> }" + [[ "$source_target" == "$archive_target" ]] || { + reset_manifests + return 1 + } + elif [[ -f "$source_path" ]]; then + [[ "${listing:0:1}" == "-" || "${listing:0:1}" == "h" ]] || { + reset_manifests + return 1 + } + source_checksum="$(sha256sum "$source_path" | awk '{print $1}')" + archive_checksum="$(tar -xOzf "$archive" -- "$archive_member" | sha256sum | awk '{print $1}')" + [[ "$source_checksum" == "$archive_checksum" ]] || { + reset_manifests + return 1 + } + elif [[ -d "$source_path" ]]; then + [[ "${listing:0:1}" == "d" ]] || { + reset_manifests + return 1 + } + else + reset_manifests + return 1 + fi + done <"$source_manifest" - reset_manifests + reset_manifests } marker_value() { - local key="$1" - awk -F= -v key="$key" '$1 == key {sub(/^[^=]*=/, ""); print; exit}' "$marker_file" + local key="$1" + awk -F= -v key="$key" '$1 == key {sub(/^[^=]*=/, ""); print; exit}' "$marker_file" } write_marker() { - local state="$1" - local checksum="${2:-}" - local validation="${3:-}" + local state="$1" + local checksum="${2:-}" + local validation="${3:-}" - { - printf 'state=%s\n' "$state" - if [[ -n "$validation" ]]; then printf 'validation=%s\n' "$validation"; fi - if [[ -n "$checksum" ]]; then printf 'backup_sha256=%s\n' "$checksum"; fi - } > "$marker_tmp" - mv "$marker_tmp" "$marker_file" + { + printf 'state=%s\n' "$state" + if [[ -n "$validation" ]]; then printf 'validation=%s\n' "$validation"; fi + if [[ -n "$checksum" ]]; then printf 'backup_sha256=%s\n' "$checksum"; fi + } >"$marker_tmp" + mv "$marker_tmp" "$marker_file" } validate_existing_marker() { - local state - local validation - local expected_checksum - local actual_checksum + local state + local validation + local expected_checksum + local actual_checksum - state="$(marker_value state)" - validation="$(marker_value validation)" + state="$(marker_value state)" + validation="$(marker_value validation)" - case "$state" in - no-legacy-data) - if [[ -n "$validation" && "$validation" != "no-data-v1" ]]; then - log error "no-data migration marker uses an unknown validation method" - return 1 - fi - if [[ -z "$validation" ]]; then - write_marker no-legacy-data "" no-data-v1 - log warning "upgraded no-data migration marker with explicit validation state" - fi - return 0 - ;; - legacy-backup) - if [[ "$validation" != "$validation_method" ]]; then - log error "legacy backup marker lacks content-level validation proof" - return 1 - fi - expected_checksum="$(marker_value backup_sha256)" - if [[ -z "$expected_checksum" ]] || ! validate_archive "$backup_file"; then - log error "legacy backup marker exists but its archive cannot be verified" - return 1 - fi - actual_checksum="$(sha256sum "$backup_file" | awk '{print $1}')" - if [[ "$actual_checksum" != "$expected_checksum" ]]; then - log error "legacy backup checksum does not match the migration marker" - return 1 - fi - return 0 - ;; - *) - log error "legacy migration marker lacks content-level validation proof" - return 1 - ;; - esac + case "$state" in + no-legacy-data) + if [[ -n "$validation" && "$validation" != "no-data-v1" ]]; then + log error "no-data migration marker uses an unknown validation method" + return 1 + fi + if [[ -z "$validation" ]]; then + write_marker no-legacy-data "" no-data-v1 + log warning "upgraded no-data migration marker with explicit validation state" + fi + return 0 + ;; + legacy-backup) + if [[ "$validation" != "$validation_method" ]]; then + log error "legacy backup marker lacks content-level validation proof" + return 1 + fi + expected_checksum="$(marker_value backup_sha256)" + if [[ -z "$expected_checksum" ]] || ! validate_archive "$backup_file"; then + log error "legacy backup marker exists but its archive cannot be verified" + return 1 + fi + actual_checksum="$(sha256sum "$backup_file" | awk '{print $1}')" + if [[ "$actual_checksum" != "$expected_checksum" ]]; then + log error "legacy backup checksum does not match the migration marker" + return 1 + fi + return 0 + ;; + *) + log error "legacy migration marker lacks content-level validation proof" + return 1 + ;; + esac } mkdir -p "$data_dir" if [[ -f "$marker_file" ]]; then - if validate_existing_marker; then exit 0; fi - exit 1 + if validate_existing_marker; then exit 0; fi + exit 1 fi if ! has_existing_data; then - write_marker no-legacy-data "" no-data-v1 - log info "no existing InfluxDB data detected; recorded no-data migration state" - exit 0 + write_marker no-legacy-data "" no-data-v1 + log info "no existing InfluxDB data detected; recorded no-data migration state" + exit 0 fi mkdir -p "$backup_dir" if [[ -e "$backup_file" ]] && validate_backup_against_source "$backup_file"; then - log info "using existing content-verified InfluxDB backup at ${backup_file}" + log info "using existing content-verified InfluxDB backup at ${backup_file}" else - if [[ -e "$backup_file" ]]; then - log warning "existing InfluxDB backup is stale, incomplete, or invalid and will be atomically replaced" - fi + if [[ -e "$backup_file" ]]; then + log warning "existing InfluxDB backup is stale, incomplete, or invalid and will be atomically replaced" + fi - log warning "creating offline InfluxDB backup at ${backup_file}" - tar -C "$(dirname "$data_dir")" -czf "$temporary_backup" "$archive_root" + log warning "creating offline InfluxDB backup at ${backup_file}" + tar -C "$(dirname "$data_dir")" -czf "$temporary_backup" "$archive_root" - if ! validate_backup_against_source "$temporary_backup"; then - log error "created InfluxDB backup failed content-level validation" - exit 1 - fi + if ! validate_backup_against_source "$temporary_backup"; then + log error "created InfluxDB backup failed content-level validation" + exit 1 + fi - mv -f "$temporary_backup" "$backup_file" - log info "InfluxDB backup created and content-verified at ${backup_file}" + mv -f "$temporary_backup" "$backup_file" + log info "InfluxDB backup created and content-verified at ${backup_file}" fi backup_checksum="$(sha256sum "$backup_file" | awk '{print $1}')" diff --git a/scrutiny_fa/CHANGELOG.md b/scrutiny_fa/CHANGELOG.md index 836804d440..c03259baa7 100644 --- a/scrutiny_fa/CHANGELOG.md +++ b/scrutiny_fa/CHANGELOG.md @@ -1,16 +1,16 @@ - + ## v1.70.0 (2026-08-29) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.69.1 (2026-08-22) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.69.0 (2026-08-15) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.68.0 (2026-08-01) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.67.0-8 (2026-07-18) - Verify every backup file checksum and symbolic-link target, record the content-validation method in the migration marker, atomically preserve the previous archive until replacement validation succeeds, and remove the blocking synthetic FIFO test fixture. @@ -31,19 +31,19 @@ ## v1.67.0 (2026-07-18) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.66.0 (2026-07-13) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.65.0 (2026-07-04) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.64.0 (2026-06-20) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.63.0 (2026-06-13) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.62.4 (2026-06-11) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) ## v1.62.3 (2026-06-05) diff --git a/scrutiny_fa/README.md b/scrutiny_fa/README.md index 1caea65aed..2e30f51a1d 100644 --- a/scrutiny_fa/README.md +++ b/scrutiny_fa/README.md @@ -52,7 +52,7 @@ It automatically mounts all local drives. ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `Updates` | list | `Hourly` | Update schedule (Quarterly/Hourly/Daily/Weekly/Custom) | | `Updates_custom_time` | str | | Custom update interval (e.g., "5m", "2h", "1w", "2mo") | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/scrutiny_fa/rootfs_overlay/etc/services.d/nginx/finish b/scrutiny_fa/rootfs_overlay/etc/services.d/nginx/finish old mode 100755 new mode 100644 diff --git a/scrutiny_fa/scrutiny-ha-influxdb-preflight b/scrutiny_fa/scrutiny-ha-influxdb-preflight index 5f7cfcb6ab..370f397e5c 100644 --- a/scrutiny_fa/scrutiny-ha-influxdb-preflight +++ b/scrutiny_fa/scrutiny-ha-influxdb-preflight @@ -15,212 +15,212 @@ source_manifest="" archive_manifest="" log() { - local level="$1" - local message="$2" - printf 'time="%s" level=%s msg="%s" type=ha-influxdb-upgrade-preflight\n' \ - "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "$level" "$message" + local level="$1" + local message="$2" + printf 'time="%s" level=%s msg="%s" type=ha-influxdb-upgrade-preflight\n' \ + "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "$level" "$message" } cleanup() { - rm -f "$temporary_backup" "$marker_tmp" - if [[ -n "$source_manifest" ]]; then rm -f "$source_manifest"; fi - if [[ -n "$archive_manifest" ]]; then rm -f "$archive_manifest"; fi + rm -f "$temporary_backup" "$marker_tmp" + if [[ -n "$source_manifest" ]]; then rm -f "$source_manifest"; fi + if [[ -n "$archive_manifest" ]]; then rm -f "$archive_manifest"; fi } trap cleanup EXIT has_existing_data() { - if [[ -e "${data_dir}/influxd.bolt" || -e "${data_dir}/influxd.sqlite" ]]; then - return 0 - fi + if [[ -e "${data_dir}/influxd.bolt" || -e "${data_dir}/influxd.sqlite" ]]; then + return 0 + fi - if [[ -d "${data_dir}/engine" ]] && find "${data_dir}/engine" -mindepth 1 -print -quit | grep -q .; then - return 0 - fi + if [[ -d "${data_dir}/engine" ]] && find "${data_dir}/engine" -mindepth 1 -print -quit | grep -q .; then + return 0 + fi - return 1 + return 1 } validate_archive() { - local archive="$1" - [[ -s "$archive" ]] || return 1 - gzip -t "$archive" >/dev/null 2>&1 || return 1 - tar -tzf "$archive" >/dev/null 2>&1 + local archive="$1" + [[ -s "$archive" ]] || return 1 + gzip -t "$archive" >/dev/null 2>&1 || return 1 + tar -tzf "$archive" >/dev/null 2>&1 } reset_manifests() { - rm -f "$source_manifest" "$archive_manifest" - source_manifest="" - archive_manifest="" + rm -f "$source_manifest" "$archive_manifest" + source_manifest="" + archive_manifest="" } validate_backup_against_source() { - local archive="$1" - local relative_path - local source_path - local archive_member - local listing - local source_checksum - local archive_checksum - local source_target - local archive_target + local archive="$1" + local relative_path + local source_path + local archive_member + local listing + local source_checksum + local archive_checksum + local source_target + local archive_target - validate_archive "$archive" || return 1 - source_manifest="$(mktemp)" - archive_manifest="$(mktemp)" + validate_archive "$archive" || return 1 + source_manifest="$(mktemp)" + archive_manifest="$(mktemp)" - ( - cd "$data_dir" - find . -mindepth 1 -print | sed -e 's#^\./##' -e 's#/$##' | LC_ALL=C sort - ) > "$source_manifest" + ( + cd "$data_dir" + find . -mindepth 1 -print | sed -e 's#^\./##' -e 's#/$##' | LC_ALL=C sort + ) >"$source_manifest" - tar -tzf "$archive" | \ - sed -e "s#^${archive_root}/##" -e '/^$/d' -e 's#/$##' | \ - LC_ALL=C sort > "$archive_manifest" + tar -tzf "$archive" | + sed -e "s#^${archive_root}/##" -e '/^$/d' -e 's#/$##' | + LC_ALL=C sort >"$archive_manifest" - if ! cmp -s "$source_manifest" "$archive_manifest"; then - reset_manifests - return 1 - fi + if ! cmp -s "$source_manifest" "$archive_manifest"; then + reset_manifests + return 1 + fi - while IFS= read -r relative_path; do - source_path="${data_dir}/${relative_path}" - archive_member="${archive_root}/${relative_path}" - listing="$(tar -tvzf "$archive" -- "$archive_member" 2>/dev/null)" || { - reset_manifests - return 1 - } + while IFS= read -r relative_path; do + source_path="${data_dir}/${relative_path}" + archive_member="${archive_root}/${relative_path}" + listing="$(tar -tvzf "$archive" -- "$archive_member" 2>/dev/null)" || { + reset_manifests + return 1 + } - if [[ -L "$source_path" ]]; then - [[ "${listing:0:1}" == "l" ]] || { - reset_manifests - return 1 - } - source_target="$(readlink "$source_path")" - archive_target="${listing##* -> }" - [[ "$source_target" == "$archive_target" ]] || { - reset_manifests - return 1 - } - elif [[ -f "$source_path" ]]; then - [[ "${listing:0:1}" == "-" || "${listing:0:1}" == "h" ]] || { - reset_manifests - return 1 - } - source_checksum="$(sha256sum "$source_path" | awk '{print $1}')" - archive_checksum="$(tar -xOzf "$archive" -- "$archive_member" | sha256sum | awk '{print $1}')" - [[ "$source_checksum" == "$archive_checksum" ]] || { - reset_manifests - return 1 - } - elif [[ -d "$source_path" ]]; then - [[ "${listing:0:1}" == "d" ]] || { - reset_manifests - return 1 - } - else - reset_manifests - return 1 - fi - done < "$source_manifest" + if [[ -L "$source_path" ]]; then + [[ "${listing:0:1}" == "l" ]] || { + reset_manifests + return 1 + } + source_target="$(readlink "$source_path")" + archive_target="${listing##* -> }" + [[ "$source_target" == "$archive_target" ]] || { + reset_manifests + return 1 + } + elif [[ -f "$source_path" ]]; then + [[ "${listing:0:1}" == "-" || "${listing:0:1}" == "h" ]] || { + reset_manifests + return 1 + } + source_checksum="$(sha256sum "$source_path" | awk '{print $1}')" + archive_checksum="$(tar -xOzf "$archive" -- "$archive_member" | sha256sum | awk '{print $1}')" + [[ "$source_checksum" == "$archive_checksum" ]] || { + reset_manifests + return 1 + } + elif [[ -d "$source_path" ]]; then + [[ "${listing:0:1}" == "d" ]] || { + reset_manifests + return 1 + } + else + reset_manifests + return 1 + fi + done <"$source_manifest" - reset_manifests + reset_manifests } marker_value() { - local key="$1" - awk -F= -v key="$key" '$1 == key {sub(/^[^=]*=/, ""); print; exit}' "$marker_file" + local key="$1" + awk -F= -v key="$key" '$1 == key {sub(/^[^=]*=/, ""); print; exit}' "$marker_file" } write_marker() { - local state="$1" - local checksum="${2:-}" - local validation="${3:-}" + local state="$1" + local checksum="${2:-}" + local validation="${3:-}" - { - printf 'state=%s\n' "$state" - if [[ -n "$validation" ]]; then printf 'validation=%s\n' "$validation"; fi - if [[ -n "$checksum" ]]; then printf 'backup_sha256=%s\n' "$checksum"; fi - } > "$marker_tmp" - mv "$marker_tmp" "$marker_file" + { + printf 'state=%s\n' "$state" + if [[ -n "$validation" ]]; then printf 'validation=%s\n' "$validation"; fi + if [[ -n "$checksum" ]]; then printf 'backup_sha256=%s\n' "$checksum"; fi + } >"$marker_tmp" + mv "$marker_tmp" "$marker_file" } validate_existing_marker() { - local state - local validation - local expected_checksum - local actual_checksum + local state + local validation + local expected_checksum + local actual_checksum - state="$(marker_value state)" - validation="$(marker_value validation)" + state="$(marker_value state)" + validation="$(marker_value validation)" - case "$state" in - no-legacy-data) - if [[ -n "$validation" && "$validation" != "no-data-v1" ]]; then - log error "no-data migration marker uses an unknown validation method" - return 1 - fi - if [[ -z "$validation" ]]; then - write_marker no-legacy-data "" no-data-v1 - log warning "upgraded no-data migration marker with explicit validation state" - fi - return 0 - ;; - legacy-backup) - if [[ "$validation" != "$validation_method" ]]; then - log error "legacy backup marker lacks content-level validation proof" - return 1 - fi - expected_checksum="$(marker_value backup_sha256)" - if [[ -z "$expected_checksum" ]] || ! validate_archive "$backup_file"; then - log error "legacy backup marker exists but its archive cannot be verified" - return 1 - fi - actual_checksum="$(sha256sum "$backup_file" | awk '{print $1}')" - if [[ "$actual_checksum" != "$expected_checksum" ]]; then - log error "legacy backup checksum does not match the migration marker" - return 1 - fi - return 0 - ;; - *) - log error "legacy migration marker lacks content-level validation proof" - return 1 - ;; - esac + case "$state" in + no-legacy-data) + if [[ -n "$validation" && "$validation" != "no-data-v1" ]]; then + log error "no-data migration marker uses an unknown validation method" + return 1 + fi + if [[ -z "$validation" ]]; then + write_marker no-legacy-data "" no-data-v1 + log warning "upgraded no-data migration marker with explicit validation state" + fi + return 0 + ;; + legacy-backup) + if [[ "$validation" != "$validation_method" ]]; then + log error "legacy backup marker lacks content-level validation proof" + return 1 + fi + expected_checksum="$(marker_value backup_sha256)" + if [[ -z "$expected_checksum" ]] || ! validate_archive "$backup_file"; then + log error "legacy backup marker exists but its archive cannot be verified" + return 1 + fi + actual_checksum="$(sha256sum "$backup_file" | awk '{print $1}')" + if [[ "$actual_checksum" != "$expected_checksum" ]]; then + log error "legacy backup checksum does not match the migration marker" + return 1 + fi + return 0 + ;; + *) + log error "legacy migration marker lacks content-level validation proof" + return 1 + ;; + esac } mkdir -p "$data_dir" if [[ -f "$marker_file" ]]; then - if validate_existing_marker; then exit 0; fi - exit 1 + if validate_existing_marker; then exit 0; fi + exit 1 fi if ! has_existing_data; then - write_marker no-legacy-data "" no-data-v1 - log info "no existing InfluxDB data detected; recorded no-data migration state" - exit 0 + write_marker no-legacy-data "" no-data-v1 + log info "no existing InfluxDB data detected; recorded no-data migration state" + exit 0 fi mkdir -p "$backup_dir" if [[ -e "$backup_file" ]] && validate_backup_against_source "$backup_file"; then - log info "using existing content-verified InfluxDB backup at ${backup_file}" + log info "using existing content-verified InfluxDB backup at ${backup_file}" else - if [[ -e "$backup_file" ]]; then - log warning "existing InfluxDB backup is stale, incomplete, or invalid and will be atomically replaced" - fi + if [[ -e "$backup_file" ]]; then + log warning "existing InfluxDB backup is stale, incomplete, or invalid and will be atomically replaced" + fi - log warning "creating offline InfluxDB backup at ${backup_file}" - tar -C "$(dirname "$data_dir")" -czf "$temporary_backup" "$archive_root" + log warning "creating offline InfluxDB backup at ${backup_file}" + tar -C "$(dirname "$data_dir")" -czf "$temporary_backup" "$archive_root" - if ! validate_backup_against_source "$temporary_backup"; then - log error "created InfluxDB backup failed content-level validation" - exit 1 - fi + if ! validate_backup_against_source "$temporary_backup"; then + log error "created InfluxDB backup failed content-level validation" + exit 1 + fi - mv -f "$temporary_backup" "$backup_file" - log info "InfluxDB backup created and content-verified at ${backup_file}" + mv -f "$temporary_backup" "$backup_file" + log info "InfluxDB backup created and content-verified at ${backup_file}" fi backup_checksum="$(sha256sum "$backup_file" | awk '{print $1}')" diff --git a/scrutiny_fa_original/CHANGELOG.md b/scrutiny_fa_original/CHANGELOG.md index d7fb64b2dc..20eb8afc96 100644 --- a/scrutiny_fa_original/CHANGELOG.md +++ b/scrutiny_fa_original/CHANGELOG.md @@ -1,16 +1,16 @@ - + ## v0.9.3.1 (2026-08-18) - Fix startup crash: `collector-once` failed with `s6-svwait: fatal: unable to subscribe to events for /run/service/scrutiny` because the add-on entrypoint never started real s6 supervision. Keep the upstream image's own `/init` as PID 1, same as `scrutiny_original` (#2991) and `scrutiny`/`scrutiny_fa` (#2878). - + ## v0.9.3 (2026-08-13) - Update to latest version from analogj/scrutiny (changelog : https://github.com/analogj/scrutiny/releases) - + ## v0.9.2 (2026-06-20) - Update to latest version from analogj/scrutiny (changelog : https://github.com/analogj/scrutiny/releases) - + ## v1.63.0 (2026-06-13) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.62.4 (2026-06-11) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) ## v1.62.3 (2026-06-05) diff --git a/scrutiny_fa_original/README.md b/scrutiny_fa_original/README.md index d304fd7341..539bea6913 100644 --- a/scrutiny_fa_original/README.md +++ b/scrutiny_fa_original/README.md @@ -52,7 +52,7 @@ It automatically mounts all local drives. ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `Updates` | list | `Hourly` | Update schedule (Quarterly/Hourly/Daily/Weekly/Custom) | | `Updates_custom_time` | str | | Custom update interval (e.g., "5m", "2h", "1w", "2mo") | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/scrutiny_original/CHANGELOG.md b/scrutiny_original/CHANGELOG.md index 10c77de694..f0cc2590b3 100644 --- a/scrutiny_original/CHANGELOG.md +++ b/scrutiny_original/CHANGELOG.md @@ -1,16 +1,16 @@ - + ## v0.9.3.1 (2026-08-18) - Fix startup crash: `collector-once` failed with `s6-svwait: fatal: unable to subscribe to events for /run/service/scrutiny` because the add-on entrypoint never started real s6 supervision. Keep the upstream image's own `/init` as PID 1 (same fix already shipped for `scrutiny`/`scrutiny_fa` in #2878). Closes #2989. - + ## v0.9.3 (2026-08-13) - Update to latest version from analogj/scrutiny (changelog : https://github.com/analogj/scrutiny/releases) - + ## v0.9.2 (2026-06-20) - Update to latest version from analogj/scrutiny (changelog : https://github.com/analogj/scrutiny/releases) - + ## v1.63.0 (2026-06-13) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) - + ## v1.62.4 (2026-06-11) - Update to latest version from Starosdev/scrutiny (changelog : https://github.com/Starosdev/scrutiny/releases) ## v1.62.3 (2026-06-05) diff --git a/scrutiny_original/README.md b/scrutiny_original/README.md index 73ccb0ab02..d98cae6df0 100644 --- a/scrutiny_original/README.md +++ b/scrutiny_original/README.md @@ -52,7 +52,7 @@ It automatically mounts all local drives. ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `Updates` | list | `Hourly` | Update schedule (Quarterly/Hourly/Daily/Weekly/Custom) | | `Updates_custom_time` | str | | Custom update interval (e.g., "5m", "2h", "1w", "2mo") | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/seafile/CHANGELOG.md b/seafile/CHANGELOG.md index a0a709eaca..5c81162334 100644 --- a/seafile/CHANGELOG.md +++ b/seafile/CHANGELOG.md @@ -17,7 +17,7 @@ ## 12.0.14 (2025-12-28) - Update to latest version from franchetti/seafile-arm -## (2025-12-23) +## (2025-12-23) - Update to latest version from franchetti/seafile-arm - The Home Assistant project has deprecated support for the armv7, armhf and i386 architectures. Support wil be fully dropped in the upcoming Home Assistant 2025.12 release diff --git a/seafile/README.md b/seafile/README.md index 1e89c325d0..dd30f3bb59 100644 --- a/seafile/README.md +++ b/seafile/README.md @@ -68,7 +68,7 @@ Webui can be found at (Seahub) and 0' "${JSONSOURCE}" >/dev/null; then +if jq -e '.env_vars? | length > 0' "${JSONSOURCE}" > /dev/null; then bashio::log.info "Applying env_vars" while IFS=$'\t' read -r ENV_NAME ENV_VALUE; do if [[ -z "${ENV_NAME}" || "${ENV_NAME}" == "null" ]]; then @@ -57,7 +57,7 @@ if jq -e '.env_vars? | length > 0' "${JSONSOURCE}" >/dev/null; then ENV_VALUE_ESCAPED=$(printf "%q" "${ENV_VALUE}") ENV_LINE="export ${ENV_NAME}=${ENV_VALUE_ESCAPED}" - sed -i "1a ${ENV_LINE}" /home/seafile/*.sh 2>/dev/null + sed -i "1a ${ENV_LINE}" /home/seafile/*.sh 2> /dev/null find /opt/seafile -name '*.sh' -print0 | xargs -0 sed -i "1a ${ENV_LINE}" done < <(jq -r '.env_vars[] | [.name, .value] | @tsv' "${JSONSOURCE}") fi @@ -108,8 +108,8 @@ sed -i "s|/shared|$DATA_LOCATION|g" /home/seafile/*.sh ADMIN_EMAIL_VAL="$(bashio::config 'SEAFILE_ADMIN_EMAIL')" ADMIN_PASSWORD_VAL="$(bashio::config 'SEAFILE_ADMIN_PASSWORD')" -if [[ -n "${ADMIN_EMAIL_VAL}" && "${ADMIN_EMAIL_VAL}" != "null" \ - && -n "${ADMIN_PASSWORD_VAL}" && "${ADMIN_PASSWORD_VAL}" != "null" ]]; then +if [[ -n "${ADMIN_EMAIL_VAL}" && "${ADMIN_EMAIL_VAL}" != "null" && + -n "${ADMIN_PASSWORD_VAL}" && "${ADMIN_PASSWORD_VAL}" != "null" ]]; then bashio::log.info "Seeding admin credentials" mkdir -p "${DATA_LOCATION}/conf" @@ -126,13 +126,13 @@ if [[ -n "${ADMIN_EMAIL_VAL}" && "${ADMIN_EMAIL_VAL}" != "null" \ sed -i '/^SEAFILE_ADMIN_PASSWORD=/d' "${SEAFILE_ENV_FILE}" case "${ADMIN_EMAIL_VAL}" in - *$'\n'*|*$'\r'*) + *$'\n'* | *$'\r'*) bashio::exit.nok "SEAFILE_ADMIN_EMAIL must not contain newlines" ;; esac case "${ADMIN_PASSWORD_VAL}" in - *$'\n'*|*$'\r'*) + *$'\n'* | *$'\r'*) bashio::exit.nok "SEAFILE_ADMIN_PASSWORD must not contain newlines" ;; esac @@ -223,7 +223,7 @@ done URLEOF chmod +x /home/seafile/apply_addon_urls.sh sed -i '/print "Launching seafile"/i /home/seafile/apply_addon_urls.sh' /home/seafile/launch.sh -if ! grep -q 'apply_addon_urls.sh' /home/seafile/launch.sh 2>/dev/null; then +if ! grep -q 'apply_addon_urls.sh' /home/seafile/launch.sh 2> /dev/null; then bashio::log.warning "Could not inject URL configuration into launch.sh; URLs may use upstream defaults" fi @@ -237,7 +237,7 @@ bashio::log.info "Defining database" # provided (Home Assistant stores multi-select options this way). Fallback to # the raw value to stay compatible with older configurations that used a # string. -DATABASE_SELECTION=$(bashio::config 'database[0]' 2>/dev/null || true) +DATABASE_SELECTION=$(bashio::config 'database[0]' 2> /dev/null || true) DATABASE_SELECTION=${DATABASE_SELECTION:-$(bashio::config 'database')} case "${DATABASE_SELECTION}" in diff --git a/seerr/README.md b/seerr/README.md index e4c33f64d5..09fe04e9ae 100644 --- a/seerr/README.md +++ b/seerr/README.md @@ -25,7 +25,7 @@ Use `env_vars` to pass extra environment variables when needed. Seerr configurat ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `NODE_MEMORY_LIMIT` | int | `512` | Maximum Node.js heap memory in MB. Increase if Seerr crashes with large libraries; decrease on memory-constrained systems. | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | diff --git a/seerr/config.yaml b/seerr/config.yaml index b3eaffa55c..7278535d8c 100644 --- a/seerr/config.yaml +++ b/seerr/config.yaml @@ -1,8 +1,7 @@ arch: - aarch64 - amd64 -description: - Open-source media request and discovery manager for Jellyfin, Plex, and Emby +description: Open-source media request and discovery manager for Jellyfin, Plex, and Emby devices: - /dev/dri - /dev/dri/card0 diff --git a/seerr/rootfs/etc/services.d/nginx/run b/seerr/rootfs/etc/services.d/nginx/run old mode 100644 new mode 100755 diff --git a/seerr/rootfs/etc/services.d/seerr/finish b/seerr/rootfs/etc/services.d/seerr/finish old mode 100755 new mode 100644 diff --git a/signalk/CHANGELOG.md b/signalk/CHANGELOG.md index c0d8ad4ee1..d91a2a01b9 100644 --- a/signalk/CHANGELOG.md +++ b/signalk/CHANGELOG.md @@ -1,16 +1,16 @@ - + ## 2.31.1 (2026-08-22) - Update to latest version from SignalK/signalk-server (changelog : https://github.com/SignalK/signalk-server/releases) - + ## 2.31.0 (2026-08-15) - Update to latest version from SignalK/signalk-server (changelog : https://github.com/SignalK/signalk-server/releases) - + ## 2.30.0 (2026-07-04) - Update to latest version from SignalK/signalk-server (changelog : https://github.com/SignalK/signalk-server/releases) ## 2.28.0-2 (2026-06-28) - Add Bonjour/mDNS development headers so native npm modules such as mdns can rebuild after add-on updates. - + ## 2.28.0 (2026-06-20) - Update to latest version from SignalK/signalk-server (changelog : https://github.com/SignalK/signalk-server/releases) diff --git a/signalk/rootfs/etc/cont-init.d/99-run.sh b/signalk/rootfs/etc/cont-init.d/99-run.sh index 69ca67c93f..85cbada4a3 100755 --- a/signalk/rootfs/etc/cont-init.d/99-run.sh +++ b/signalk/rootfs/etc/cont-init.d/99-run.sh @@ -42,6 +42,5 @@ if [[ ! -f /data/version || "$current_version" != "$(cat /data/version)" ]]; the fi fi - bashio::log.info "Starting application" sudo -u "$USER" -s /bin/sh -c "/home/node/signalk/startup.sh" diff --git a/social_to_mealie/CHANGELOG.md b/social_to_mealie/CHANGELOG.md index 2c14fa78ad..eb96214a2b 100644 --- a/social_to_mealie/CHANGELOG.md +++ b/social_to_mealie/CHANGELOG.md @@ -1,7 +1,7 @@ - + ## 1.7.2 (2026-07-18) - Update to latest version from GerardPolloRebozado/social-to-mealie (changelog : https://github.com/GerardPolloRebozado/social-to-mealie/releases) - + ## 1.7.1 (2026-07-13) - Update to latest version from GerardPolloRebozado/social-to-mealie (changelog : https://github.com/GerardPolloRebozado/social-to-mealie/releases) diff --git a/social_to_mealie/README.md b/social_to_mealie/README.md index 31ad7e5e3d..c5aa0b0334 100644 --- a/social_to_mealie/README.md +++ b/social_to_mealie/README.md @@ -47,7 +47,7 @@ Webui can be found at . ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `OPENAI_URL` | str | `https://api.openai.com/v1` | URL for the OpenAI-compatible endpoint | | `OPENAI_API_KEY` | str | `` | API key for the OpenAI-compatible provider | | `TRANSCRIPTION_MODEL` | str | `whisper-1` | Whisper model to use for transcription | diff --git a/sonarr/CHANGELOG.md b/sonarr/CHANGELOG.md index 89f95173c8..ee383c4252 100644 --- a/sonarr/CHANGELOG.md +++ b/sonarr/CHANGELOG.md @@ -1,23 +1,23 @@ - + ## 4.0.19.3009 (2026-09-05) - Update to latest version from linuxserver/docker-sonarr (changelog : https://github.com/linuxserver/docker-sonarr/releases) - + ## 4.0.19.3007 (2026-08-29) - Update to latest version from linuxserver/docker-sonarr (changelog : https://github.com/linuxserver/docker-sonarr/releases) - + ## 4.0.19.3001 (2026-08-11) - Update to latest version from linuxserver/docker-sonarr (changelog : https://github.com/linuxserver/docker-sonarr/releases) - Upstream tag : develop-4.0.19.3001-ls184 - + ## 4.0.19.2997 (2026-08-08) - Update to latest version from linuxserver/docker-sonarr (changelog : https://github.com/linuxserver/docker-sonarr/releases) - + ## 4.0.19.2995 (2026-08-01) - Update to latest version from linuxserver/docker-sonarr (changelog : https://github.com/linuxserver/docker-sonarr/releases) - + ## 4.0.19.2979 (2026-06-27) - Update to latest version from linuxserver/docker-sonarr (changelog : https://github.com/linuxserver/docker-sonarr/releases) - + ## 4.0.17.2969 (2026-06-06) - Update to latest version from linuxserver/docker-sonarr (changelog : https://github.com/linuxserver/docker-sonarr/releases) diff --git a/sonarr/README.md b/sonarr/README.md index 2175c43b18..ee31e18e30 100644 --- a/sonarr/README.md +++ b/sonarr/README.md @@ -60,7 +60,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/sponsorblockcast/README.md b/sponsorblockcast/README.md index 905c20c2aa..e7dbfa7207 100644 --- a/sponsorblockcast/README.md +++ b/sponsorblockcast/README.md @@ -46,7 +46,7 @@ The addon automatically discovers local Chromecast devices and monitors YouTube ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `CSS_CATEGORIES` | str | `sponsor, intro, outro, selfpromo` | SponsorBlock categories to skip (comma-separated) | | `CSS_DISCOVER_INTERVAL` | str | `5m` | Interval to restart the DNS discovery client | | `CSS_DEVICES` | str | `[]` | Comma-separated list of device addresses; disables discovery | diff --git a/spotify_to_plex/CHANGELOG.md b/spotify_to_plex/CHANGELOG.md index b698a8a94c..64f5f582e0 100644 --- a/spotify_to_plex/CHANGELOG.md +++ b/spotify_to_plex/CHANGELOG.md @@ -1,4 +1,4 @@ - + ## 1.0.107 (2026-08-15) - Update to latest version from jjdenhertog/spotify-to-plex ## 1.0.104 (2026-07-06) diff --git a/spotify_to_plex/README.md b/spotify_to_plex/README.md index e6ba819b0c..c16ed0c0f0 100644 --- a/spotify_to_plex/README.md +++ b/spotify_to_plex/README.md @@ -41,7 +41,7 @@ Before starting the add-on you need a Spotify developer application (https://dev Fill the add-on options: | Option | Description | -|--------|-------------| +| -------- | ------------- | | `SPOTIFY_API_CLIENT_ID` | Client ID of your Spotify developer application | | `SPOTIFY_API_CLIENT_SECRET` | Client secret of your Spotify developer application | | `SPOTIFY_API_REDIRECT_URI` | OAuth redirect URI (must match the one configured in your Spotify app) | diff --git a/tandoor_recipes/CHANGELOG.md b/tandoor_recipes/CHANGELOG.md index 271cc41b73..f048067ca5 100644 --- a/tandoor_recipes/CHANGELOG.md +++ b/tandoor_recipes/CHANGELOG.md @@ -1,10 +1,10 @@ - + ## 2.6.13 (2026-07-13) - Update to latest version from TandoorRecipes/recipes (changelog : https://github.com/TandoorRecipes/recipes/releases) - + ## 2.6.12 (2026-07-04) - Update to latest version from TandoorRecipes/recipes (changelog : https://github.com/TandoorRecipes/recipes/releases) - + ## 2.6.11 (2026-06-23) - Update to latest version from TandoorRecipes/recipes (changelog : https://github.com/TandoorRecipes/recipes/releases) diff --git a/tandoor_recipes/README.md b/tandoor_recipes/README.md index 6b3ed4669a..e1acdf8b1c 100644 --- a/tandoor_recipes/README.md +++ b/tandoor_recipes/README.md @@ -44,7 +44,7 @@ Complete documentation: https://docs.tandoor.dev/install/docker/ ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `SECRET_KEY` | str | `YOUR_SECRET_KEY` | **REQUIRED**: Django secret key for security | | `ALLOWED_HOSTS` | str | | **REQUIRED**: Comma-separated Home Assistant URLs for ingress | | `DB_TYPE` | list | `sqlite` | Database type (sqlite or postgresql_external) | diff --git a/tdarr/CHANGELOG.md b/tdarr/CHANGELOG.md index 6166ab7e8c..42388251c2 100644 --- a/tdarr/CHANGELOG.md +++ b/tdarr/CHANGELOG.md @@ -1,22 +1,22 @@ - + ## 2.86.01 (2026-08-08) - Update to latest version from haveagitgat/tdarr - + ## 2.85.01 (2026-07-25) - Update to latest version from haveagitgat/tdarr - + ## 2.84.01 (2026-07-21) - Update to latest version from haveagitgat/tdarr - + ## 2.83.01 (2026-07-13) - Update to latest version from haveagitgat/tdarr - + ## 2.81.01 (2026-06-27) - Update to latest version from haveagitgat/tdarr - + ## 2.80.01 (2026-06-23) - Update to latest version from haveagitgat/tdarr - + ## 2.78.01 (2026-06-13) - Update to latest version from haveagitgat/tdarr @@ -61,7 +61,7 @@ ## 2.58.02 (2025-12-24) - Update to latest version from haveagitgat/tdarr -## (2025-12-23) +## (2025-12-23) - Update to latest version from haveagitgat/tdarr ## 2.58.02 (2025-11-22) diff --git a/tdarr/README.md b/tdarr/README.md index 7af7eeae0c..db21231934 100644 --- a/tdarr/README.md +++ b/tdarr/README.md @@ -62,7 +62,7 @@ The server port is `8266` for connecting external Tdarr nodes. ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `CONFIG_LOCATION` | str | `/config/addons_config/tdarr` | Path where Tdarr config is stored | | `TZ` | str | | Timezone (e.g., `Europe/London`) | | `localdisks` | str | | Local drives to mount (e.g., `sda1,sdb1,MYNAS`) | diff --git a/teamspeak/README.md b/teamspeak/README.md index 0a7cdbb8ec..805cd49eba 100644 --- a/teamspeak/README.md +++ b/teamspeak/README.md @@ -61,7 +61,7 @@ Connect using the TeamSpeak client at `homeassistant.local:9987`. ### Ports | Port | Protocol | Description | -|------|----------|-------------| +| ------ | ---------- | ------------- | | `9987` | UDP | Voice communication | | `10011` | TCP | ServerQuery (raw) | | `30033` | TCP | File transfer | diff --git a/transmission/CHANGELOG.md b/transmission/CHANGELOG.md index 918fed3b92..eba70f714e 100644 --- a/transmission/CHANGELOG.md +++ b/transmission/CHANGELOG.md @@ -1,4 +1,4 @@ - + ## 4.1.3 (2026-07-04) - Update to latest version from linuxserver/docker-transmission (changelog : https://github.com/linuxserver/docker-transmission/releases) ## 4.1.2 (2026-06-05) diff --git a/transmission/README.md b/transmission/README.md index 3f0f2fe702..5711a052d0 100644 --- a/transmission/README.md +++ b/transmission/README.md @@ -56,7 +56,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/transmission_openvpn/CHANGELOG.md b/transmission_openvpn/CHANGELOG.md index 7c0a719898..1a67c2d785 100644 --- a/transmission_openvpn/CHANGELOG.md +++ b/transmission_openvpn/CHANGELOG.md @@ -1,10 +1,10 @@ - + ## v5.5.2 (2026-08-22) - Update to latest version from haugene/docker-transmission-openvpn (changelog : https://github.com/haugene/docker-transmission-openvpn/releases) - + ## v5.5.1 (2026-08-08) - Update to latest version from haugene/docker-transmission-openvpn (changelog : https://github.com/haugene/docker-transmission-openvpn/releases) - + ## v5.4.2 (2026-08-01) - Update to latest version from haugene/docker-transmission-openvpn (changelog : https://github.com/haugene/docker-transmission-openvpn/releases) diff --git a/transmission_openvpn/config.yaml b/transmission_openvpn/config.yaml index cdba03ce04..6a69f602cc 100644 --- a/transmission_openvpn/config.yaml +++ b/transmission_openvpn/config.yaml @@ -123,7 +123,7 @@ schema: OPENVPN_PASSWORD: str PGID: int PUID: int - TRANSMISSION_HOME: str + TRANSMISSION_HOME: str TRANSMISSION_DOWNLOAD_DIR: str TRANSMISSION_INCOMPLETE_DIR: str TRANSMISSION_WATCH_DIR: str diff --git a/transmission_openvpn/rootfs/etc/openvpn/update-resolv-conf b/transmission_openvpn/rootfs/etc/openvpn/update-resolv-conf old mode 100755 new mode 100644 index 56288cd998..5d7c94b4c3 --- a/transmission_openvpn/rootfs/etc/openvpn/update-resolv-conf +++ b/transmission_openvpn/rootfs/etc/openvpn/update-resolv-conf @@ -7,51 +7,51 @@ [ "$script_type" ] || exit 0 case "$script_type" in - up) - # Backup original resolv.conf - if [ ! -f /etc/resolv.conf.ovpn-bak ]; then - cp /etc/resolv.conf /etc/resolv.conf.ovpn-bak 2>/dev/null || true - fi +up) + # Backup original resolv.conf + if [ ! -f /etc/resolv.conf.ovpn-bak ]; then + cp /etc/resolv.conf /etc/resolv.conf.ovpn-bak 2>/dev/null || true + fi - dns_servers="" - dns_domain="" - dns_search="" + dns_servers="" + dns_domain="" + dns_search="" - # Parse foreign_option_* environment variables set by OpenVPN - for optionname in ${!foreign_option_*}; do - option="${!optionname}" - case "$option" in - dhcp-option\ DNS\ *) - dns_servers="${dns_servers} ${option#dhcp-option DNS }" - ;; - dhcp-option\ DOMAIN\ *) - dns_domain="${option#dhcp-option DOMAIN }" - ;; - dhcp-option\ DOMAIN-SEARCH\ *) - dns_search="${dns_search} ${option#dhcp-option DOMAIN-SEARCH }" - ;; - esac - done + # Parse foreign_option_* environment variables set by OpenVPN + for optionname in ${!foreign_option_*}; do + option="${!optionname}" + case "$option" in + dhcp-option\ DNS\ *) + dns_servers="${dns_servers} ${option#dhcp-option DNS }" + ;; + dhcp-option\ DOMAIN\ *) + dns_domain="${option#dhcp-option DOMAIN }" + ;; + dhcp-option\ DOMAIN-SEARCH\ *) + dns_search="${dns_search} ${option#dhcp-option DOMAIN-SEARCH }" + ;; + esac + done - # Write new resolv.conf with VPN DNS servers - if [ -n "$dns_servers" ]; then - { - for server in $dns_servers; do - echo "nameserver $server" - done - [ -n "$dns_domain" ] && echo "domain $dns_domain" - [ -n "$dns_search" ] && echo "search${dns_search}" - } > /etc/resolv.conf - fi - ;; + # Write new resolv.conf with VPN DNS servers + if [ -n "$dns_servers" ]; then + { + for server in $dns_servers; do + echo "nameserver $server" + done + [ -n "$dns_domain" ] && echo "domain $dns_domain" + [ -n "$dns_search" ] && echo "search${dns_search}" + } >/etc/resolv.conf + fi + ;; - down) - # Restore original resolv.conf - if [ -f /etc/resolv.conf.ovpn-bak ]; then - cp /etc/resolv.conf.ovpn-bak /etc/resolv.conf - rm -f /etc/resolv.conf.ovpn-bak - fi - ;; +down) + # Restore original resolv.conf + if [ -f /etc/resolv.conf.ovpn-bak ]; then + cp /etc/resolv.conf.ovpn-bak /etc/resolv.conf + rm -f /etc/resolv.conf.ovpn-bak + fi + ;; esac exit 0 diff --git a/ubooquity/README.md b/ubooquity/README.md index 53a8672d94..6fb4d072e4 100644 --- a/ubooquity/README.md +++ b/ubooquity/README.md @@ -66,7 +66,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/unpackerr/CHANGELOG.md b/unpackerr/CHANGELOG.md index 1b90928afc..8714ebfd24 100644 --- a/unpackerr/CHANGELOG.md +++ b/unpackerr/CHANGELOG.md @@ -1,4 +1,4 @@ - + ## v0.16.1 (2026-09-05) - Update to latest version from Unpackerr/unpackerr (changelog : https://github.com/Unpackerr/unpackerr/releases) diff --git a/unpackerr/README.md b/unpackerr/README.md index 602500bdca..f3ecc6d3f2 100644 --- a/unpackerr/README.md +++ b/unpackerr/README.md @@ -65,7 +65,7 @@ Unpackerr monitors completed downloads and extracts archives automatically. ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `1000` | Group ID for file permissions | | `PUID` | int | `1000` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/unpackerr/rootfs/etc/cont-init.d/90-vpn.sh b/unpackerr/rootfs/etc/cont-init.d/90-vpn.sh index 2b4a522772..7755f95a2b 100755 --- a/unpackerr/rootfs/etc/cont-init.d/90-vpn.sh +++ b/unpackerr/rootfs/etc/cont-init.d/90-vpn.sh @@ -30,5 +30,5 @@ esac # Disable port forwarder when VPN_AUTO_PORT_FORWARD is explicitly false VPN_AUTO_PORT_FORWARD="${VPN_AUTO_PORT_FORWARD:-}" if [ "${VPN_AUTO_PORT_FORWARD,,}" = "false" ]; then - sed -i "1a sleep infinity" /etc/s6*/s6*/service-forwarder/run 2>/dev/null || true + sed -i "1a sleep infinity" /etc/s6*/s6*/service-forwarder/run 2> /dev/null || true fi diff --git a/webtop/README.md b/webtop/README.md index 65f0cfa2bf..e81fbd4ba4 100644 --- a/webtop/README.md +++ b/webtop/README.md @@ -49,7 +49,7 @@ See all potential ENV variables here : https://docs.linuxserver.io/images/docker ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/webtop_kde/CHANGELOG.md b/webtop_kde/CHANGELOG.md index 123cad2347..97a481804a 100644 --- a/webtop_kde/CHANGELOG.md +++ b/webtop_kde/CHANGELOG.md @@ -1,8 +1,8 @@ - + ## 4.16.0.96 (2026-09-05) - Update to latest version from linuxserver/docker-webtop (changelog : https://github.com/linuxserver/docker-webtop/releases) - Upstream tag : 4.16-r0-ls92 - + ## 4.16.0.95 (2026-08-29) - Update to latest version from linuxserver/docker-webtop (changelog : https://github.com/linuxserver/docker-webtop/releases) - Upstream tag : 4.16-r0-ls95 @@ -10,7 +10,7 @@ - Version renamed from `4.16-r0-ls94`, which Home Assistant could not order and therefore could not reliably offer as an update: every number of the previous version is kept, as a section of its own. The addon itself and the upstream version it tracks are unchanged - + ## 4.16-r0-ls94 (2026-08-01) - Update to latest version from linuxserver/docker-webtop (changelog : https://github.com/linuxserver/docker-webtop/releases) ## 4.16-r0-ls93.2 (28-07-2026) @@ -23,19 +23,19 @@ - Share the Selkies startup scripts with the `claude_desktop` add-on by symlink (`20-folders.sh`, `21-gpu_permissions.sh`, `80-configuration.sh`, `90-ingress.sh` and the nginx includes), so the fixes made there now apply here too. This brings in: GPU render-node permissions granted before the graphical services start (fixes `libEGL warning: failed to open /dev/dri/card0: Permission denied` and the resulting "waiting for stream" hang); the s6 envdir and `XDG_RUNTIME_DIR` created up front; the cache redirected to tmpfs; `/tmp/.X11-unix` pre-created so Xorg can bind its socket as a non-root user; the `init-video` and `init-selkies-config` oneshots made non-fatal so a partially permitted device setup no longer crash-loops the add-on; and an ingress config that keeps the correct (non-SSL) nginx server block. The Microsoft Edge install moves to its own webtop-only `81-microsoft_edge.sh`, which also picks up the ownership fixup that previously ran in `20-folders.sh` before Edge was installed and so never matched anything. - + ## 4.16-r0-ls93 (2026-07-21) - Update to latest version from linuxserver/docker-webtop (changelog : https://github.com/linuxserver/docker-webtop/releases) - + ## 4.16-r0-ls95 (2026-07-18) - Update to latest version from linuxserver/docker-webtop (changelog : https://github.com/linuxserver/docker-webtop/releases) - + ## 4.16-r0-ls94 (2026-06-23) - Update to latest version from linuxserver/docker-webtop (changelog : https://github.com/linuxserver/docker-webtop/releases) - + ## 4.16-r0-ls93 (2026-06-20) - Update to latest version from linuxserver/docker-webtop (changelog : https://github.com/linuxserver/docker-webtop/releases) - + ## 4.16-r0-ls92 (2026-06-11) - Update to latest version from linuxserver/docker-webtop (changelog : https://github.com/linuxserver/docker-webtop/releases) ## 4.16-r0-ls95 (2026-06-05) @@ -44,7 +44,7 @@ ## 4.16-r0-ls94 (2026-05-23) - Update to latest version from linuxserver/docker-webtop (changelog : https://github.com/linuxserver/docker-webtop/releases) -## (2026-05-22) +## (2026-05-22) - Update to latest version from linuxserver/docker-webtop (changelog : https://github.com/linuxserver/docker-webtop/releases) ## 4.16-r0-ls94 (2026-05-22) diff --git a/whoogle/README.md b/whoogle/README.md index dc05fa23ee..03a064926b 100644 --- a/whoogle/README.md +++ b/whoogle/README.md @@ -42,7 +42,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `TZ` | str | `Europe/Amsterdam` | Timezone | | `WHOOGLE_CONFIG_LANGUAGE` | str | `lang_en` | Interface language | | `WHOOGLE_CONFIG_URL` | str | | Base URL for the service | diff --git a/zoneminder/CHANGELOG.md b/zoneminder/CHANGELOG.md index ebdca14610..367157b8af 100644 --- a/zoneminder/CHANGELOG.md +++ b/zoneminder/CHANGELOG.md @@ -1,4 +1,4 @@ - + ## 1.38.4 (2026-08-13) - Update to latest version from zoneminder-containers/zoneminder-base (changelog : https://github.com/zoneminder-containers/zoneminder-base/releases) diff --git a/zoneminder/rootfs/etc/cont-init.d/99-run.sh b/zoneminder/rootfs/etc/cont-init.d/99-run.sh index 00b1ef5414..0430f05cf5 100755 --- a/zoneminder/rootfs/etc/cont-init.d/99-run.sh +++ b/zoneminder/rootfs/etc/cont-init.d/99-run.sh @@ -73,7 +73,7 @@ case "$(bashio::config "DB_CONNECTION")" in local out out="$("${mysql_base[@]}" -e \ "SELECT schema_name FROM information_schema.schemata WHERE schema_name='${db}';" \ - 2>/dev/null || true)" + 2> /dev/null || true)" [ -n "$out" ] } @@ -82,7 +82,7 @@ case "$(bashio::config "DB_CONNECTION")" in # If schema doesn't exist, count should be 0 "${mysql_base[@]}" -e \ "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='${db}';" \ - 2>/dev/null || echo 0 + 2> /dev/null || echo 0 } is_likely_zoneminder_db() { @@ -99,7 +99,7 @@ case "$(bashio::config "DB_CONNECTION")" in "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='${db}' AND LOWER(table_name) IN ('config','monitors');" \ - 2>/dev/null || echo 0)" + 2> /dev/null || echo 0)" # Firefly-ish signature tables (heuristic blacklist) local ff_sig @@ -110,14 +110,14 @@ case "$(bashio::config "DB_CONNECTION")" in 'accounts','transactions','transaction_journals','categories', 'budgets','bills','tags','piggy_banks','rules','rule_groups' );" \ - 2>/dev/null || echo 0)" + 2> /dev/null || echo 0)" [ "${zm_required:-0}" -ge 2 ] && [ "${ff_sig:-0}" -eq 0 ] } create_db_if_missing() { local db="$1" - "${mysql_base[@]}" -e "CREATE DATABASE IF NOT EXISTS \`${db}\`;" >/dev/null + "${mysql_base[@]}" -e "CREATE DATABASE IF NOT EXISTS \`${db}\`;" > /dev/null } # --- Legacy fix: previous buggy addon used DB name 'firefly' --- @@ -154,9 +154,9 @@ case "$(bashio::config "DB_CONNECTION")" in create_db_if_missing "$ZM_DB_NAME" dump_bin="" - if command -v mysqldump >/dev/null 2>&1; then + if command -v mysqldump > /dev/null 2>&1; then dump_bin="mysqldump" - elif command -v mariadb-dump >/dev/null 2>&1; then + elif command -v mariadb-dump > /dev/null 2>&1; then dump_bin="mariadb-dump" fi @@ -167,8 +167,8 @@ case "$(bashio::config "DB_CONNECTION")" in -u "${ZM_DB_USER}" -p"${ZM_DB_PASS}" \ -h "${ZM_DB_HOST}" -P "${ZM_DB_PORT}" \ --routines --events --triggers \ - "${LEGACY_DB_NAME}" | \ - mysql \ + "${LEGACY_DB_NAME}" \ + | mysql \ -u "${ZM_DB_USER}" -p"${ZM_DB_PASS}" \ -h "${ZM_DB_HOST}" -P "${ZM_DB_PORT}" \ "${ZM_DB_NAME}"; then diff --git a/zoraxy/CHANGELOG.md b/zoraxy/CHANGELOG.md index da680d2acf..e792ed77ae 100644 --- a/zoraxy/CHANGELOG.md +++ b/zoraxy/CHANGELOG.md @@ -1,4 +1,4 @@ - + ## 3.3.4 (2026-08-29) - Update to latest version from tobychui/zoraxy (changelog : https://github.com/tobychui/zoraxy/releases) ## 3.3.3.1 (29-08-2026) diff --git a/zoraxy/rootfs/etc/services.d/zoraxy/run b/zoraxy/rootfs/etc/services.d/zoraxy/run old mode 100644 new mode 100755 diff --git a/zzz_archived_code-server/CHANGELOG.md b/zzz_archived_code-server/CHANGELOG.md index 799a5d943f..a99f90689f 100644 --- a/zzz_archived_code-server/CHANGELOG.md +++ b/zzz_archived_code-server/CHANGELOG.md @@ -1,31 +1,31 @@ - + ## 4.135.0 (2026-08-29) - Update to latest version from linuxserver/docker-code-server (changelog : https://github.com/linuxserver/docker-code-server/releases) - + ## 4.133.0 (2026-08-22) - Update to latest version from linuxserver/docker-code-server (changelog : https://github.com/linuxserver/docker-code-server/releases) - + ## 4.132.0 (2026-08-13) - Update to latest version from linuxserver/docker-code-server (changelog : https://github.com/linuxserver/docker-code-server/releases) - + ## 4.131.0 (2026-08-01) - Update to latest version from linuxserver/docker-code-server (changelog : https://github.com/linuxserver/docker-code-server/releases) - + ## 4.130.0 (2026-07-25) - Update to latest version from linuxserver/docker-code-server (changelog : https://github.com/linuxserver/docker-code-server/releases) - + ## 4.129.0 (2026-07-18) - Update to latest version from linuxserver/docker-code-server (changelog : https://github.com/linuxserver/docker-code-server/releases) - + ## 4.128.0 (2026-07-13) - Update to latest version from linuxserver/docker-code-server (changelog : https://github.com/linuxserver/docker-code-server/releases) - + ## 4.127.0 (2026-07-04) - Update to latest version from linuxserver/docker-code-server (changelog : https://github.com/linuxserver/docker-code-server/releases) - + ## 4.126.0 (2026-06-27) - Update to latest version from linuxserver/docker-code-server (changelog : https://github.com/linuxserver/docker-code-server/releases) - + ## 4.125.0 (2026-06-20) - Update to latest version from linuxserver/docker-code-server (changelog : https://github.com/linuxserver/docker-code-server/releases) ## 4.123.0 (2026-06-05) diff --git a/zzz_archived_jellyseerr/CHANGELOG.md b/zzz_archived_jellyseerr/CHANGELOG.md index d0f041fb29..b1b603396d 100644 --- a/zzz_archived_jellyseerr/CHANGELOG.md +++ b/zzz_archived_jellyseerr/CHANGELOG.md @@ -1,4 +1,4 @@ - + ## v3.4.1 (2026-08-01) - Update to latest version from Fallenbagel/jellyseerr (changelog : https://github.com/Fallenbagel/jellyseerr/releases) ## v3.3.0 (2026-06-05) diff --git a/zzz_archived_jellyseerr/config.yaml b/zzz_archived_jellyseerr/config.yaml index 23e0ff2c92..414ce15f6a 100644 --- a/zzz_archived_jellyseerr/config.yaml +++ b/zzz_archived_jellyseerr/config.yaml @@ -1,8 +1,7 @@ arch: - aarch64 - amd64 -description: - Fork of overseerr for jellyfin support (deprecated, migrate to Seerr add-on) +description: Fork of overseerr for jellyfin support (deprecated, migrate to Seerr add-on) devices: - /dev/dri - /dev/dri/card0 diff --git a/zzz_archived_kapowarr/README.md b/zzz_archived_kapowarr/README.md index 7819490f88..d075a2c5e3 100644 --- a/zzz_archived_kapowarr/README.md +++ b/zzz_archived_kapowarr/README.md @@ -26,7 +26,7 @@ and converted the way you want them. ## Configuration | Option | Description | -|--------|-------------| +| -------- | ------------- | | `PUID` / `PGID` | Ownership applied to the add-on configuration directory, and the user Kapowarr runs as. Defaults to `0` (root). | | `TZ` | Timezone, e.g. `Europe/Paris`. | | `localdisks` | Local disks to mount, e.g. `sda1` or a disk label. | diff --git a/zzz_archived_kapowarr/rootfs/etc/services.d/kapowarr/run b/zzz_archived_kapowarr/rootfs/etc/services.d/kapowarr/run old mode 100644 new mode 100755 diff --git a/zzz_archived_kapowarr/rootfs/etc/services.d/nginx/run b/zzz_archived_kapowarr/rootfs/etc/services.d/nginx/run old mode 100644 new mode 100755 diff --git a/zzz_archived_omada/rootfs/etc/cont-init.d/99-run.sh b/zzz_archived_omada/rootfs/etc/cont-init.d/99-run.sh old mode 100644 new mode 100755 diff --git a/zzz_archived_omada_v3/CHANGELOG.md b/zzz_archived_omada_v3/CHANGELOG.md index 71e29b4449..092fc8ca76 100644 --- a/zzz_archived_omada_v3/CHANGELOG.md +++ b/zzz_archived_omada_v3/CHANGELOG.md @@ -1,5 +1,5 @@ -## (2025-12-23) +## (2025-12-23) - Update to latest version from mbentley/omada-controller ## 5.3-amd64-2025-11-09-2 (2025-11-18) - Minor bugs fixed diff --git a/zzz_archived_overseerr/README.md b/zzz_archived_overseerr/README.md index b29cf846f1..20b6d8d0dc 100644 --- a/zzz_archived_overseerr/README.md +++ b/zzz_archived_overseerr/README.md @@ -61,7 +61,7 @@ Configurations can be done through the app webUI, except for the following optio ### Options | Option | Type | Default | Description | -|--------|------|---------|-------------| +| -------- | ------ | --------- | ------------- | | `PGID` | int | `0` | Group ID for file permissions | | `PUID` | int | `0` | User ID for file permissions | | `TZ` | str | | Timezone (e.g., `Europe/London`) | diff --git a/zzz_archived_overseerr/rootfs/etc/cont-init.d/00-config_location.sh b/zzz_archived_overseerr/rootfs/etc/cont-init.d/00-config_location.sh old mode 100644 new mode 100755 diff --git a/zzz_archived_overseerr/rootfs/etc/cont-init.d/20-folders.sh b/zzz_archived_overseerr/rootfs/etc/cont-init.d/20-folders.sh old mode 100644 new mode 100755 diff --git a/zzz_archived_paperless_ngx/CHANGELOG.md b/zzz_archived_paperless_ngx/CHANGELOG.md index 550032cfd3..b1122e8bb3 100644 --- a/zzz_archived_paperless_ngx/CHANGELOG.md +++ b/zzz_archived_paperless_ngx/CHANGELOG.md @@ -1,16 +1,16 @@ - + ## 3.1.3 (2026-09-05) - Update to latest version from paperless-ngx/paperless-ngx (changelog : https://github.com/paperless-ngx/paperless-ngx/releases) - + ## 3.1.0 (2026-08-29) - Update to latest version from paperless-ngx/paperless-ngx (changelog : https://github.com/paperless-ngx/paperless-ngx/releases) - + ## 3.0.5 (2026-08-02) - Update to latest version from paperless-ngx/paperless-ngx (changelog : https://github.com/paperless-ngx/paperless-ngx/releases) - + ## 3.0.4 (2026-08-01) - Update to latest version from paperless-ngx/paperless-ngx (changelog : https://github.com/paperless-ngx/paperless-ngx/releases) - + ## 3.0.2 (2026-07-25) - Update to latest version from paperless-ngx/paperless-ngx (changelog : https://github.com/paperless-ngx/paperless-ngx/releases) ## 2.20.15 (2026-06-05) diff --git a/zzz_archived_paperless_ngx/rootfs/etc/cont-init.d/99-run.sh b/zzz_archived_paperless_ngx/rootfs/etc/cont-init.d/99-run.sh index f7d3cfe2d5..f55750eb16 100755 --- a/zzz_archived_paperless_ngx/rootfs/etc/cont-init.d/99-run.sh +++ b/zzz_archived_paperless_ngx/rootfs/etc/cont-init.d/99-run.sh @@ -90,7 +90,10 @@ set +u # container_environment, which is read by `with-contenv` when each service starts. S6_ENV_DIR="" for candidate in /var/run/s6/container_environment /run/s6/container_environment; do - if [ -d "$candidate" ]; then S6_ENV_DIR="$candidate"; break; fi + if [ -d "$candidate" ]; then + S6_ENV_DIR="$candidate" + break + fi done # For all relevant variables diff --git a/zzz_archived_tor/rootfs/etc/s6-overlay/s6-rc.d/init-tor/run b/zzz_archived_tor/rootfs/etc/s6-overlay/s6-rc.d/init-tor/run index 4afd5a026b..0dba87d38e 100755 --- a/zzz_archived_tor/rootfs/etc/s6-overlay/s6-rc.d/init-tor/run +++ b/zzz_archived_tor/rootfs/etc/s6-overlay/s6-rc.d/init-tor/run @@ -38,8 +38,7 @@ fi # Checks if client names where configured when using stealth mode if bashio::config.true 'hidden_services' \ && bashio::config.true 'stealth' \ - && ! bashio::config.has_value 'client_names'; -then + && ! bashio::config.has_value 'client_names'; then bashio::log.fatal bashio::log.fatal 'Add-on configuration is incomplete.' bashio::log.fatal @@ -62,19 +61,19 @@ chmod -R 0700 /ssl/tor # Find the matching Tor log level if bashio::config.has_value 'log_level'; then case "$(bashio::string.lower "$(bashio::config 'log_level')")" in - all|trace) + all | trace) log_level="debug" ;; debug) log_level="info" ;; - info|notice) + info | notice) log_level="notice" ;; warning) log_level="warn" ;; - error|fatal|off) + error | fatal | off) log_level="err" ;; esac @@ -99,7 +98,7 @@ if bashio::config.true 'hidden_services'; then echo "HiddenServiceDir ${hidden_service_dir}" >> "${torrc}" for port in $(bashio::config 'ports'); do - count=$(echo "${port}" | sed 's/[^:]//g'| awk '{ print length }') + count=$(echo "${port}" | sed 's/[^:]//g' | awk '{ print length }') if [[ "${count}" == 0 ]]; then host='homeassistant' virtual_port="${port}" @@ -132,8 +131,7 @@ fi # Configure bridges if bashio::config.exists 'bridges' \ - && ! bashio::config.is_empty 'bridges'; -then + && ! bashio::config.is_empty 'bridges'; then bashio::log.info 'Use bridges:' echo "UseBridges 1" >> "${torrc}" @@ -164,10 +162,10 @@ if bashio::config.true 'hidden_services'; then sleep 1 done - address=$(<"${hostname_file}") - grep -m 1 "Bootstrapped 100% (done): Done" <&3 >/dev/null 2>&1 + address=$(< "${hostname_file}") + grep -m 1 "Bootstrapped 100% (done): Done" <&3 > /dev/null 2>&1 - kill "$(pgrep tor)" >/dev/null 2>&1 + kill "$(pgrep tor)" > /dev/null 2>&1 bashio::log.info '---------------------------------------------------------' bashio::log.info 'Your Home Assistant instance is available on Tor!' @@ -176,14 +174,12 @@ if bashio::config.true 'hidden_services'; then fi # Configure stealth mode -if bashio::config.true 'hidden_services' && bashio::config.true 'stealth'; -then +if bashio::config.true 'hidden_services' && bashio::config.true 'stealth'; then # Following the documentation at: # https://community.torproject.org/onion-services/advanced/client-auth/ while read -r clientname; do # Generate key is they do not exist yet - if ! bashio::fs.file_exists "${authorized_clients_dir}/${clientname}.auth" - then + if ! bashio::fs.file_exists "${authorized_clients_dir}/${clientname}.auth"; then key=$(openssl genpkey -algorithm x25519) private_key=$( @@ -198,12 +194,12 @@ then public_key=$( openssl pkey -pubout \ - <<< "${key}" \ - | sed -e '/----.*PUBLIC KEY----\|^[[:space:]]*$/d' \ - | base64 -d \ - | tail -c 32 \ - | base32 \ - | sed 's/=//g' + <<< "${key}" \ + | sed -e '/----.*PUBLIC KEY----\|^[[:space:]]*$/d' \ + | base64 -d \ + | tail -c 32 \ + | base32 \ + | sed 's/=//g' ) # Create authorized client file diff --git a/zzz_archived_tor/rootfs/etc/s6-overlay/s6-rc.d/tor/run b/zzz_archived_tor/rootfs/etc/s6-overlay/s6-rc.d/tor/run old mode 100644 new mode 100755