From 0d3c7619b4f92873edd368ef9edafadb6e95a6c3 Mon Sep 17 00:00:00 2001 From: alexbelgium <44178713+alexbelgium@users.noreply.github.com> Date: Sun, 17 Aug 2025 00:34:15 +0000 Subject: [PATCH] fix: auto-fix linting issues --- .claude/example_validated_init.sh | 20 +- .claude/ha_autoapps_secure.sh | 34 +- .claude/ha_input_validation.sh | 78 +-- .claude/ha_secure_download.sh | 20 +- .templates/00-smb_mounts.sh | 4 +- .templates/bashio-standalone.sh | 498 +++++++++--------- .templates/ha_entrypoint.sh | 18 +- birdnet-pi/rootfs/etc/cont-init.d/99-run.sh | 6 +- collabora/config.json | 16 +- collabora/rootfs/etc/cont-init.d/99-run.sh | 2 +- emby/rootfs/etc/services.d/nginx/run | 0 emby_beta/rootfs/etc/services.d/nginx/run | 0 filebrowser/README.md | 12 +- grampsweb/config.yaml | 5 +- nextcloud/rootfs/etc/services.d/cron/run | 0 nzbget/rootfs/etc/services.d/nginx/run | 0 omni-tools/rootfs/etc/cont-init.d/99-run.sh | 2 +- photoprism/README.md | 2 +- plex/config.json | 2 +- .../s6-overlay/s6-rc.d/svc-qbittorrent/run | 0 qbittorrent/rootfs/etc/services.d/nginx/run | 0 qbittorrent/rootfs/etc/services.d/timer/run | 0 scrutiny/rootfs/etc/services.d/nginx/run | 0 sonarr/rootfs/etc/services.d/nginx/run | 0 tandoor_recipes/config.json | 6 +- tdarr/README.md | 2 +- .../rootfs/etc/services.d/bitwarden/run | 0 .../rootfs/etc/services.d/nginx/run | 0 28 files changed, 375 insertions(+), 352 deletions(-) mode change 100644 => 100755 .templates/bashio-standalone.sh mode change 100644 => 100755 emby/rootfs/etc/services.d/nginx/run mode change 100644 => 100755 emby_beta/rootfs/etc/services.d/nginx/run mode change 100644 => 100755 nextcloud/rootfs/etc/services.d/cron/run mode change 100644 => 100755 nzbget/rootfs/etc/services.d/nginx/run mode change 100644 => 100755 qbittorrent/rootfs/etc/s6-overlay/s6-rc.d/svc-qbittorrent/run mode change 100644 => 100755 qbittorrent/rootfs/etc/services.d/nginx/run mode change 100644 => 100755 qbittorrent/rootfs/etc/services.d/timer/run mode change 100644 => 100755 scrutiny/rootfs/etc/services.d/nginx/run mode change 100644 => 100755 sonarr/rootfs/etc/services.d/nginx/run mode change 100644 => 100755 zzz_archived_bitwarden/rootfs/etc/services.d/bitwarden/run mode change 100644 => 100755 zzz_archived_bitwarden/rootfs/etc/services.d/nginx/run diff --git a/.claude/example_validated_init.sh b/.claude/example_validated_init.sh index b5ed955d4..bb822d683 100755 --- a/.claude/example_validated_init.sh +++ b/.claude/example_validated_init.sh @@ -25,7 +25,7 @@ if [[ "${ADDON_TYPE:-media}" == "media" ]]; then if bashio::config.has_value "transcoding_quality"; then validate_string "transcoding_quality" "^(low|medium|high|ultra)$" "Transcoding quality (low, medium, high, ultra)" false fi - + # Validate maximum concurrent streams if bashio::config.has_value "max_streams"; then validate_numeric "max_streams" 1 20 "Maximum concurrent streams (1-20)" false @@ -38,7 +38,7 @@ if [[ "${ADDON_TYPE:-file}" == "file" ]]; then if bashio::config.has_value "base_folder"; then validate_path "base_folder" "/config" "Base folder for file browsing" false fi - + # Validate disable thumbnails setting if bashio::config.has_value "disable_thumbnails"; then validate_boolean "disable_thumbnails" "Disable thumbnail generation" false @@ -51,12 +51,12 @@ if [[ "${ADDON_TYPE:-network}" == "network" ]]; then if bashio::config.has_value "target_ip"; then validate_ip "target_ip" "Target device IP address" fi - + # Validate gateway IP if bashio::config.has_value "gateway_ip"; then validate_ip "gateway_ip" "Network gateway IP address" fi - + # Validate block duration if bashio::config.has_value "block_duration"; then validate_numeric "block_duration" 1 3600 "Block duration in seconds (1-3600)" @@ -70,25 +70,25 @@ fi # Validate authentication settings if bashio::config.has_value "enable_auth"; then validate_boolean "enable_auth" "Enable authentication" - + if bashio::config.true "enable_auth"; then # If auth is enabled, validate credentials validate_string "username" "^[a-zA-Z0-9_-]{3,20}$" "Username (3-20 alphanumeric characters)" - + # Validate password strength if bashio::config.has_value "password"; then local password password=$(bashio::config "password") - + if [[ ${#password} -lt 8 ]]; then bashio::log.fatal "Password too short. Minimum 8 characters required." exit 1 fi - + if [[ ! "$password" =~ [A-Z] ]] || [[ ! "$password" =~ [a-z] ]] || [[ ! "$password" =~ [0-9] ]]; then bashio::log.warning "โš ๏ธ Weak password detected. Consider using uppercase, lowercase, and numbers." fi - + bashio::log.debug "โœ… Validated password strength" fi fi @@ -108,4 +108,4 @@ bashio::log.info "Starting application with validated configuration..." export VALIDATED_CONFIG="true" export CONFIG_VALIDATION_TIME="$(date -Iseconds)" -bashio::log.debug "Environment prepared with validated configuration" \ No newline at end of file +bashio::log.debug "Environment prepared with validated configuration" diff --git a/.claude/ha_autoapps_secure.sh b/.claude/ha_autoapps_secure.sh index 27c343047..45e3ca90e 100755 --- a/.claude/ha_autoapps_secure.sh +++ b/.claude/ha_autoapps_secure.sh @@ -13,17 +13,17 @@ echo "๐Ÿ“ฆ Installing packages securely: $PACKAGES" # Install dependencies securely install_dependencies() { echo "๐Ÿ”ง Installing required dependencies..." - + # Install bash if needed if ! command -v bash > /dev/null 2>&1; then (apt-get update && apt-get install -yqq --no-install-recommends bash || apk add --no-cache bash) > /dev/null fi - - # Install curl if needed + + # Install curl if needed if ! command -v curl > /dev/null 2>&1; then (apt-get update && apt-get install -yqq --no-install-recommends curl || apk add --no-cache curl) > /dev/null fi - + # Install ca-certificates for SSL verification (apt-get update && apt-get install -yqq --no-install-recommends ca-certificates || apk add --no-cache ca-certificates) > /dev/null 2>&1 || true } @@ -33,9 +33,9 @@ secure_download() { local url="$1" local output_file="$2" local expected_sha256="${3:-}" - + echo "๐Ÿ”’ Downloading: $(basename "$output_file")" - + # Download with security headers and timeouts if ! curl -fsSL \ --retry 3 \ @@ -48,15 +48,15 @@ secure_download() { echo "โŒ Failed to download: $url" >&2 return 1 fi - + # Verify checksum if provided if [ -n "$expected_sha256" ]; then local actual_sha256 actual_sha256=$(sha256sum "$output_file" | cut -d' ' -f1) - + if [ "$actual_sha256" != "$expected_sha256" ]; then echo "โŒ Checksum verification failed for $output_file" >&2 - echo "Expected: $expected_sha256" >&2 + echo "Expected: $expected_sha256" >&2 echo "Actual: $actual_sha256" >&2 rm -f "$output_file" return 1 @@ -65,7 +65,7 @@ secure_download() { else echo "โš ๏ธ No checksum provided - consider adding one for security" fi - + # Set secure permissions chmod 755 "$output_file" } @@ -73,21 +73,21 @@ secure_download() { # Main execution main() { echo "๐Ÿ›ก๏ธ Starting secure package installation..." - + # Install dependencies install_dependencies - + # For now, we'll download without checksum but with secure practices # TODO: Add checksums for ha_automatic_packages.sh in future releases echo "๐Ÿ“ฅ Downloading package installer..." - + local script_url="https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_automatic_packages.sh" local script_file="/ha_automatic_packages.sh" - + # Download securely (without checksum for now - to be added) if secure_download "$script_url" "$script_file" ""; then echo "๐Ÿƒ Executing package installer..." - + # Execute with error handling if bash "$script_file" "${PACKAGES:-}"; then echo "โœ… Package installation completed successfully" @@ -95,7 +95,7 @@ main() { echo "โŒ Package installation failed" >&2 exit 1 fi - + # Clean up rm -f "$script_file" echo "๐Ÿงน Cleanup completed" @@ -106,4 +106,4 @@ main() { } # Execute main function -main "$@" \ No newline at end of file +main "$@" diff --git a/.claude/ha_input_validation.sh b/.claude/ha_input_validation.sh index 91480c785..d337a616b 100755 --- a/.claude/ha_input_validation.sh +++ b/.claude/ha_input_validation.sh @@ -13,27 +13,27 @@ validate_string() { local pattern="$2" local description="$3" local required="${4:-true}" - + if ! bashio::config.has_value "$config_key"; then if [[ "$required" == "true" ]]; then bashio::log.fatal "Required configuration '$config_key' not found" bashio::log.fatal "Expected: $description" exit 1 else - return 0 # Optional field not provided + return 0 # Optional field not provided fi fi - + local value value=$(bashio::config "$config_key") - + if [[ ! $value =~ $pattern ]]; then bashio::log.fatal "Invalid format for '$config_key': '$value'" bashio::log.fatal "Expected: $description" bashio::log.fatal "Pattern: $pattern" exit 1 fi - + bashio::log.debug "โœ… Validated $config_key: $value" } @@ -44,7 +44,7 @@ validate_numeric() { local max_val="$3" local description="$4" local required="${5:-true}" - + if ! bashio::config.has_value "$config_key"; then if [[ "$required" == "true" ]]; then bashio::log.fatal "Required configuration '$config_key' not found" @@ -53,24 +53,24 @@ validate_numeric() { return 0 fi fi - + local value value=$(bashio::config "$config_key") - + # Check if it's a valid number if ! [[ "$value" =~ ^[0-9]+$ ]]; then bashio::log.fatal "Invalid numeric value for '$config_key': '$value'" bashio::log.fatal "Expected: $description" exit 1 fi - + # Check bounds if [[ $value -lt $min_val ]] || [[ $value -gt $max_val ]]; then bashio::log.fatal "Value for '$config_key' out of range: $value" bashio::log.fatal "Expected: $description (range: $min_val-$max_val)" exit 1 fi - + bashio::log.debug "โœ… Validated $config_key: $value" } @@ -79,7 +79,7 @@ validate_boolean() { local config_key="$1" local description="$2" local required="${3:-true}" - + if ! bashio::config.has_value "$config_key"; then if [[ "$required" == "true" ]]; then bashio::log.fatal "Required configuration '$config_key' not found" @@ -88,16 +88,16 @@ validate_boolean() { return 0 fi fi - + local value value=$(bashio::config "$config_key") - + if [[ ! "$value" =~ ^(true|false)$ ]]; then bashio::log.fatal "Invalid boolean value for '$config_key': '$value'" bashio::log.fatal "Expected: $description (true or false)" exit 1 fi - + bashio::log.debug "โœ… Validated $config_key: $value" } @@ -107,7 +107,7 @@ validate_path() { local base_path="$2" local description="$3" local required="${4:-true}" - + if ! bashio::config.has_value "$config_key"; then if [[ "$required" == "true" ]]; then bashio::log.fatal "Required configuration '$config_key' not found" @@ -116,10 +116,10 @@ validate_path() { return 0 fi fi - + local value value=$(bashio::config "$config_key") - + # Check for directory traversal attempts if [[ "$value" =~ \.\. ]] || [[ "$value" =~ ^/ ]]; then bashio::log.fatal "Invalid path for '$config_key': '$value'" @@ -127,30 +127,30 @@ validate_path() { bashio::log.fatal "Expected: $description" exit 1 fi - + # Normalize path and check if it's within base path local full_path="$base_path/$value" local real_path - real_path=$(realpath -m "$full_path" 2>/dev/null || echo "$full_path") + real_path=$(realpath -m "$full_path" 2> /dev/null || echo "$full_path") local real_base real_base=$(realpath -m "$base_path") - + if [[ ! "$real_path" =~ ^"$real_base" ]]; then bashio::log.fatal "Path '$config_key' outside allowed base: '$value'" bashio::log.fatal "Expected: $description" exit 1 fi - + bashio::log.debug "โœ… Validated path $config_key: $value" } # Function to validate URL validate_url() { local config_key="$1" - local allowed_schemes="$2" # e.g., "http|https" + local allowed_schemes="$2" # e.g., "http|https" local description="$3" local required="${4:-true}" - + if ! bashio::config.has_value "$config_key"; then if [[ "$required" == "true" ]]; then bashio::log.fatal "Required configuration '$config_key' not found" @@ -159,20 +159,20 @@ validate_url() { return 0 fi fi - + local value value=$(bashio::config "$config_key") - + # Basic URL validation local url_pattern="^($allowed_schemes)://[A-Za-z0-9.-]+(:[0-9]+)?(/.*)?$" - + if [[ ! "$value" =~ $url_pattern ]]; then bashio::log.fatal "Invalid URL for '$config_key': '$value'" bashio::log.fatal "Expected: $description" bashio::log.fatal "Allowed schemes: $allowed_schemes" exit 1 fi - + bashio::log.debug "โœ… Validated URL $config_key: $value" } @@ -181,7 +181,7 @@ validate_ip() { local config_key="$1" local description="$2" local required="${3:-true}" - + if ! bashio::config.has_value "$config_key"; then if [[ "$required" == "true" ]]; then bashio::log.fatal "Required configuration '$config_key' not found" @@ -190,13 +190,13 @@ validate_ip() { return 0 fi fi - + local value value=$(bashio::config "$config_key") - + # IPv4 validation local ipv4_pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}$" - + if [[ "$value" =~ $ipv4_pattern ]]; then # Validate each octet is 0-255 IFS='.' read -ra octets <<< "$value" @@ -212,38 +212,38 @@ validate_ip() { bashio::log.fatal "Expected: $description" exit 1 fi - + bashio::log.debug "โœ… Validated IP $config_key: $value" } # Function to validate common add-on configurations validate_common_config() { bashio::log.info "๐Ÿ” Validating common configuration parameters..." - + # Validate SSL configuration if present if bashio::config.has_value "ssl"; then validate_boolean "ssl" "Enable/disable SSL" - + if bashio::config.true "ssl"; then validate_string "certfile" "^[a-zA-Z0-9._-]+\.pem$" "SSL certificate filename" true validate_string "keyfile" "^[a-zA-Z0-9._-]+\.pem$" "SSL private key filename" true fi fi - + # Validate user/group IDs if present if bashio::config.has_value "PUID"; then validate_numeric "PUID" 0 65535 "User ID (0-65535)" fi - + if bashio::config.has_value "PGID"; then validate_numeric "PGID" 0 65535 "Group ID (0-65535)" fi - + # Validate timezone if present if bashio::config.has_value "TZ"; then validate_string "TZ" "^[A-Za-z0-9/_+-]+$" "Timezone (e.g., Europe/London)" false fi - + bashio::log.info "โœ… Common configuration validation completed" } @@ -253,4 +253,4 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then bashio::log.info "This library provides secure validation functions for add-on configurations" echo "" bashio::log.info "Usage: source /ha_input_validation.sh" -fi \ No newline at end of file +fi diff --git a/.claude/ha_secure_download.sh b/.claude/ha_secure_download.sh index 920d11c25..46ee704bb 100755 --- a/.claude/ha_secure_download.sh +++ b/.claude/ha_secure_download.sh @@ -11,13 +11,13 @@ secure_download() { local url="$1" local output_file="$2" local expected_sha256="$3" - + echo "๐Ÿ”’ Securely downloading: $(basename "$output_file")" - + # Download with retry logic local retries=3 local retry_delay=2 - + for i in $(seq 1 $retries); do if curl -fsSL --retry 3 --retry-delay 1 --connect-timeout 10 --max-time 30 "$url" -o "$output_file"; then break @@ -29,13 +29,13 @@ secure_download() { sleep $retry_delay fi done - + # Verify SHA256 checksum if provided if [ -n "$expected_sha256" ]; then echo "๐Ÿ” Verifying integrity..." local actual_sha256 actual_sha256=$(sha256sum "$output_file" | cut -d' ' -f1) - + if [ "$actual_sha256" = "$expected_sha256" ]; then echo "โœ… Integrity verification passed" else @@ -48,7 +48,7 @@ secure_download() { else echo "โš ๏ธ No checksum provided - skipping integrity verification" fi - + # Set secure permissions chmod 755 "$output_file" echo "๐Ÿ”ง Set secure permissions (755)" @@ -57,17 +57,17 @@ secure_download() { # Function to install common dependencies securely install_dependencies() { echo "๐Ÿ“ฆ Installing secure dependencies..." - + # Install bash if needed if ! command -v bash > /dev/null 2>&1; then (apt-get update && apt-get install -yqq --no-install-recommends bash || apk add --no-cache bash) > /dev/null fi - + # Install curl if needed if ! command -v curl > /dev/null 2>&1; then (apt-get update && apt-get install -yqq --no-install-recommends curl || apk add --no-cache curl) > /dev/null fi - + # Install ca-certificates for SSL verification (apt-get update && apt-get install -yqq --no-install-recommends ca-certificates || apk add --no-cache ca-certificates) > /dev/null 2>&1 || true } @@ -83,4 +83,4 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then echo "" echo "Example:" echo " secure_download 'https://example.com/script.sh' '/tmp/script.sh' 'abc123...'" -fi \ No newline at end of file +fi diff --git a/.templates/00-smb_mounts.sh b/.templates/00-smb_mounts.sh index 5666b2456..25df7f132 100755 --- a/.templates/00-smb_mounts.sh +++ b/.templates/00-smb_mounts.sh @@ -149,8 +149,8 @@ if bashio::config.has_value 'networkdisks'; then fi diskname="$disk" - diskname="${diskname//\\//}" # replace \ with / - diskname="${diskname##*/}" # Get only last part of the name + diskname="${diskname//\\//}" # replace \ with / + diskname="${diskname##*/}" # Get only last part of the name MOUNTED=false # Start diff --git a/.templates/bashio-standalone.sh b/.templates/bashio-standalone.sh old mode 100644 new mode 100755 index cddf31304..ff4da02b9 --- a/.templates/bashio-standalone.sh +++ b/.templates/bashio-standalone.sh @@ -9,47 +9,50 @@ # Whether to emit ANSI colors (disabled if not a TTY) if [ -t 1 ]; then - _BASHIO_COLOR=1 + _BASHIO_COLOR=1 else - _BASHIO_COLOR=0 + _BASHIO_COLOR=0 fi _bashio_color() { - # $1=name; returns ANSI sequence or empty - if [ "$_BASHIO_COLOR" != "1" ]; then return 0; fi - 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' ;; - esac + # $1=name; returns ANSI sequence or empty + if [ "$_BASHIO_COLOR" != "1" ]; then return 0; fi + 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' ;; + esac } _bashio_log() { - # $1=color name, $2...=msg - local c="$1"; shift - local pre; pre="$(_bashio_color "$c")" - local rst; rst="$(_bashio_color reset)" - printf '%s%s%s\n' "$pre" "$*" "$rst" + # $1=color name, $2...=msg + local c="$1" + shift + local pre + pre="$(_bashio_color "$c")" + local rst + rst="$(_bashio_color reset)" + printf '%s%s%s\n' "$pre" "$*" "$rst" } # Optional JSON options source (single flat object or nested). # Set STANDALONE_OPTIONS_JSON to a path (e.g., /data/options.json). # If jq is present, keys can be fetched as .key or .nested.key _bashio_json_get() { - # $1=key (dot.notation). echoes value or empty; returns 0 always - local key="${1:-}" - local file="${STANDALONE_OPTIONS_JSON:-}" - if [ -z "$file" ] || [ ! -f "$file" ] || ! command -v jq >/dev/null 2>&1; then - return 0 - fi - # jq -r returns "null" for missing; convert to empty - local val - val="$(jq -er --arg k "$key" '. as $r | getpath(($k|split("."))) // empty' "$file" 2>/dev/null || true)" - [ "$val" = "null" ] && val="" - printf '%s' "$val" + # $1=key (dot.notation). echoes value or empty; returns 0 always + local key="${1:-}" + local file="${STANDALONE_OPTIONS_JSON:-}" + if [ -z "$file" ] || [ ! -f "$file" ] || ! command -v jq > /dev/null 2>&1; then + return 0 + fi + # jq -r returns "null" for missing; convert to empty + local val + val="$(jq -er --arg k "$key" '. as $r | getpath(($k|split("."))) // empty' "$file" 2> /dev/null || true)" + [ "$val" = "null" ] && val="" + printf '%s' "$val" } # Map a bashio "key" to an env var name. @@ -59,127 +62,128 @@ _bashio_json_get() { # 3) dot->underscore, dash->underscore (upper & lower) # 4) with prefixes: CFG_, CONFIG_, ADDON_, OPTION_, OPT_ _bashio_env_get() { - # $1=key - local key="${1:-}" - [ -z "$key" ] && return 0 + # $1=key + local key="${1:-}" + [ -z "$key" ] && return 0 - local variants=() - variants+=("$key") - variants+=("$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')") - variants+=("$(printf '%s' "$key" | tr '.' '_' | tr '-' '_' )") - variants+=("$(printf '%s' "$key" | tr '.' '_' | tr '-' '_' | tr '[:lower:]' '[:upper:]')") + local variants=() + variants+=("$key") + variants+=("$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')") + variants+=("$(printf '%s' "$key" | tr '.' '_' | tr '-' '_')") + variants+=("$(printf '%s' "$key" | tr '.' '_' | tr '-' '_' | tr '[:lower:]' '[:upper:]')") - 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 } # Helper: true/false parsing _bashio_is_true() { - # $1=value - case "${1:-}" in - 1|true|TRUE|yes|YES|on|On) return 0 ;; - *) return 1 ;; - esac + # $1=value + case "${1:-}" in + 1 | true | TRUE | yes | YES | on | On) return 0 ;; + *) return 1 ;; + esac } # Net wait using /dev/tcp (POSIX bash) with a timeout _bashio_tcp_wait() { - # $1=host $2=port $3=timeout(s, default 30) - local host="$1" port="$2" to="${3:-30}" - 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 + # $1=host $2=port $3=timeout(s, default 30) + local host="$1" port="$2" to="${3:-30}" + 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 } # -------- logs --------------------------------------------------------------- -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 "$*"; } # compatibility aliases often used -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.info() { bashio::log.blue "$@"; } +bashio::log.warning() { bashio::log.yellow "$@"; } +bashio::log.error() { bashio::log.red "$@"; } +bashio::log.debug() { printf '%s\n' "$*"; } # -------- supervisor & addon meta ------------------------------------------- # In standalone, "ping" always fails unless forced bashio::supervisor.ping() { - if _bashio_is_true "${STANDALONE_FORCE_SUPERVISOR_PING:-}"; then - return 0 - fi - return 1 + if _bashio_is_true "${STANDALONE_FORCE_SUPERVISOR_PING:-}"; then + return 0 + fi + return 1 } # Add-on metadata (use env or sensible defaults) -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 [ "${ADDON_VERSION_LATEST:-}" != "" ] && [ "${ADDON_VERSION_LATEST:-}" != "${BUILD_VERSION:-}" ]; then - printf '%s' "true"; return 0 - fi - printf '%s' "false" + if [ "${ADDON_VERSION_LATEST:-}" != "" ] && [ "${ADDON_VERSION_LATEST:-}" != "${BUILD_VERSION:-}" ]; then + printf '%s' "true" + return 0 + fi + printf '%s' "false" } -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, falling back 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}")" - [ -z "$v" ] && v="$(_bashio_env_get "ADDON_PORT_${arg}")" - printf '%s' "${v:-$arg}" - else - printf '%s' "$(_bashio_env_get "$arg")" - fi + local arg="${1:-}" + if [[ "$arg" =~ ^[0-9]+$ ]]; then + local v + v="$(_bashio_env_get "PORT_${arg}")" + [ -z "$v" ] && v="$(_bashio_env_get "ADDON_PORT_${arg}")" + printf '%s' "${v:-$arg}" + else + printf '%s' "$(_bashio_env_get "$arg")" + fi } # -------- system info -------------------------------------------------------- bashio::info.operating_system() { - if [ -r /etc/os-release ]; then - . /etc/os-release - printf '%s' "${PRETTY_NAME:-${NAME:-Linux}}" - else - printf '%s' "Linux" - fi + if [ -r /etc/os-release ]; then + . /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 ------------------------------------------------------------- @@ -187,24 +191,30 @@ bashio::info.supervisor() { printf '%s' "standalone"; } # 1) ENV (several name variants/prefixes) # 2) JSON file via STANDALONE_OPTIONS_JSON (jq required) bashio::config() { - local key="${1:-}" - local v - v="$(_bashio_env_get "$key")" - if [ -z "$v" ]; then - v="$(_bashio_json_get "$key")" - fi - printf '%s' "${v:-}" + local key="${1:-}" + local v + v="$(_bashio_env_get "$key")" + if [ -z "$v" ]; then + v="$(_bashio_json_get "$key")" + fi + printf '%s' "${v:-}" } -bashio::config.has_value() { local k="$1"; [ -n "$(bashio::config "$k")" ]; } -bashio::config.true() { local k="$1"; _bashio_is_true "$(bashio::config "$k")"; } +bashio::config.has_value() { + local k="$1" + [ -n "$(bashio::config "$k")" ] +} +bashio::config.true() { + local k="$1" + _bashio_is_true "$(bashio::config "$k")" +} # Some add-ons call "require.ssl" (noop by default) -bashio::config.require.ssl(){ printf '%s' "${REQUIRE_SSL:-true}"; } +bashio::config.require.ssl() { printf '%s' "${REQUIRE_SSL:-true}"; } # -------- variables & fs helpers -------------------------------------------- -bashio::var.true() { _bashio_is_true "${1:-}"; } +bashio::var.true() { _bashio_is_true "${1:-}"; } bashio::var.has_value() { [ -n "${1:-}" ]; } bashio::fs.directory_exists() { [ -d "$1" ]; } @@ -213,8 +223,8 @@ bashio::fs.directory_exists() { [ -d "$1" ]; } # 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 "$host" "$port" "$to" + local host="$1" port="$2" to="${3:-30}" + _bashio_tcp_wait "$host" "$port" "$to" } # Discovery stubs; map to common env names, or JSON: @@ -222,33 +232,33 @@ bashio::net.wait_for() { # bashio::services "mqtt" "host" # bashio::services "mysql" "port" bashio::services() { - local svc="${1:-}" key="${2:-}" - [ -z "$svc" ] && return 0 - local upper svc_upper var v - upper="$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')" - svc_upper="$(printf '%s' "$svc" | tr '[:lower:]' '[:upper:]')" + local svc="${1:-}" key="${2:-}" + [ -z "$svc" ] && return 0 + 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")" - if [ -z "$v" ] && [ -n "${STANDALONE_OPTIONS_JSON:-}" ]; 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")" + if [ -z "$v" ] && [ -n "${STANDALONE_OPTIONS_JSON:-}" ]; then + v="$(_bashio_json_get "services.${svc}.${key}")" + [ -z "$v" ] && v="$(_bashio_json_get "${svc}.${key}")" + fi + printf '%s' "${v:-}" } # ----- extras for broader compatibility -------------------------------------- @@ -258,165 +268,177 @@ _BASHIO_CACHE_DIR="${BASHIO_CACHE_DIR:-/tmp/.bashio}" 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() { mkdir -p "$_BASHIO_CACHE_DIR"; 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() { + mkdir -p "$_BASHIO_CACHE_DIR" + printf '%s' "${2:-}" > "$_BASHIO_CACHE_DIR/${1}.cache" +} # Filesystem helpers frequently used -bashio::fs.file_exists() { [ -f "$1" ]; } -bashio::fs.directory_exists() { [ -d "$1" ]; } # already defined earlier; keep if present -bashio::fs.file_contains() { local f="$1" p="$2"; [ -f "$f" ] && grep -q -- "$p" "$f"; } +bashio::fs.file_exists() { [ -f "$1" ]; } +bashio::fs.directory_exists() { [ -d "$1" ]; } # already defined earlier; keep if present +bashio::fs.file_contains() { + local f="$1" p="$2" + [ -f "$f" ] && grep -q -- "$p" "$f" +} # 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 "$@"; } # env presence (even if empty) used by config.exists _bashio_env_has() { - local key="$1" p v name - [ -z "$key" ] && return 1 - local variants=( - "$key" - "$(printf '%s' "$key" | tr '.' '_' )" - "$(printf '%s' "$key" | tr '.' '_' | tr '[:lower:]' '[:upper:]')" - "$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')" - ) - for v in "${variants[@]}"; do - for p in "" "CFG_" "CONFIG_" "ADDON_" "OPTION_" "OPT_"; do - name="${p}${v}" - if [ -n "${!name+x}" ]; then # defined, even if empty - printf '%s' "$name" - return 0 - fi + local key="$1" p v name + [ -z "$key" ] && return 1 + local variants=( + "$key" + "$(printf '%s' "$key" | tr '.' '_')" + "$(printf '%s' "$key" | tr '.' '_' | tr '[:lower:]' '[:upper:]')" + "$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')" + ) + for v in "${variants[@]}"; do + for p in "" "CFG_" "CONFIG_" "ADDON_" "OPTION_" "OPT_"; do + name="${p}${v}" + if [ -n "${!name+x}" ]; then # defined, even if empty + printf '%s' "$name" + return 0 + fi + done done - done - return 1 + return 1 } # config.exists : key is present (env or JSON), even if value is empty bashio::config.exists() { - local key="$1" file="${STANDALONE_OPTIONS_JSON:-}" - _bashio_env_has "$key" && return 0 - if [ -n "$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 + local key="$1" file="${STANDALONE_OPTIONS_JSON:-}" + _bashio_env_has "$key" && return 0 + if [ -n "$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 } # addon.option : write/delete option in JSON when possible; fallback no-op/env bashio::addon.option() { - local key="$1" value="${2-__BASHIO_UNSET__}" file="${STANDALONE_OPTIONS_JSON:-}" - if [ -n "$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" + local key="$1" value="${2-__BASHIO_UNSET__}" file="${STANDALONE_OPTIONS_JSON:-}" + if [ -n "$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 + # Fallbacks: export as env or treat delete as no-op + if [ "$value" != "__BASHIO_UNSET__" ]; then + export "$(printf '%s' "$key" | tr '.' '_' | tr '-' '_')"="$value" fi - return 0 - fi - # Fallbacks: export as env or treat delete as no-op - if [ "$value" != "__BASHIO_UNSET__" ]; then - export "$(printf '%s' "$key" | tr '.' '_' | tr '-' '_')"="$value" - fi } # services.available : check if we can resolve at least a host for the service 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" ] } # var helpers -bashio::var.false() { ! _bashio_is_true "${1:-}"; } -bashio::var.has_value() { [ -n "${1:-}" ]; } # already present; keep if defined +bashio::var.false() { ! _bashio_is_true "${1:-}"; } +bashio::var.has_value() { [ -n "${1:-}" ]; } # already present; keep if defined # exits used by many add-ons -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.check : Supervisor does a config check; allow an overridable command # 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 } # --- improvements & extra shims --------------------------------------------- # Respect NO_COLOR and dumb terminals if [ -n "${NO_COLOR:-}" ] || [ "${TERM:-}" = "dumb" ]; then - _BASHIO_COLOR=0 + _BASHIO_COLOR=0 fi # net.wait_for: prefer nc if available, fallback to /dev/tcp _bashio_tcp_wait_nc() { - # $1=host $2=port $3=timeout(s) - 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 + # $1=host $2=port $3=timeout(s) + 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 } 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:-}" - [ -z "$h" ] && return 1 - if command -v getent >/dev/null 2>&1; then - getent ahostsv4 "$h" | awk '{print $1; exit}' - else - # fallback: try busybox nslookup - nslookup "$h" 2>/dev/null | awk '/^Address: /{print $2; exit}' - fi + local h="${1:-}" + [ -z "$h" ] && return 1 + if command -v getent > /dev/null 2>&1; then + getent ahostsv4 "$h" | awk '{print $1; exit}' + else + # fallback: try busybox nslookup + 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}" } # Home Assistant token (no Supervisor; read from env or JSON) bashio::homeassistant.token() { - local t="${HOMEASSISTANT_TOKEN:-${HASS_TOKEN:-}}" - if [ -z "$t" ] && [ -n "${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:-}" ] && 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:-}" } # config.array: # Accepts CSV ("a,b,c"), space/newline-separated text, or JSON array ["a","b"]. # Prints one item per line (common pattern in add-ons: `mapfile -t arr < <(bashio::config.array key)`). bashio::config.array() { - local key="${1:-}" raw val - raw="$(bashio::config "$key")" - [ -z "$raw" ] && return 0 + local key="${1:-}" raw val + raw="$(bashio::config "$key")" + [ -z "$raw" ] && return 0 - # JSON array? - 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 + # JSON array? + 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 - # CSV -> newline - if printf '%s' "$raw" | grep -q ','; then - printf '%s' "$raw" | tr ',' '\n' - return 0 - fi + # CSV -> newline + if printf '%s' "$raw" | grep -q ','; then + printf '%s' "$raw" | tr ',' '\n' + return 0 + fi - # Already space/newline-separated - printf '%s\n' "$raw" + # Already space/newline-separated + printf '%s\n' "$raw" } # Optional: common require.* shims (treat as advisory in standalone) bashio::config.require.username() { :; } bashio::config.require.password() { :; } -bashio::config.require.port() { :; } +bashio::config.require.port() { :; } # -------- end ---------------------------------------------------------------- diff --git a/.templates/ha_entrypoint.sh b/.templates/ha_entrypoint.sh index 897e1f254..d3c84b123 100755 --- a/.templates/ha_entrypoint.sh +++ b/.templates/ha_entrypoint.sh @@ -1,8 +1,7 @@ #!/command/with-contenv bashio # shellcheck shell=bash -set -e # Exit immediately if a command exits with a non-zero status - +set -e # Exit immediately if a command exits with a non-zero status # Detect if this is PID1 (main container process) โ€” do this once at the start PID1=false @@ -38,7 +37,7 @@ for candidate in "${candidate_shebangs[@]}"; do # Test if command exists and can actually execute a shell command (for shells) if [ -x "$command_path" ]; then # Try as both 'sh -c' and 'bashio echo' style - if "$command_path" -c 'echo yes' >/dev/null 2>&1 || "$command_path" echo "yes" >/dev/null 2>&1; then + if "$command_path" -c 'echo yes' > /dev/null 2>&1 || "$command_path" echo "yes" > /dev/null 2>&1; then shebang="$candidate" break fi @@ -91,7 +90,7 @@ done # Start run scripts in services.d and s6-overlay/s6-rc.d if PID1 if $PID1; then - shopt -s nullglob # Don't expand unmatched globs to themselves + shopt -s nullglob # Don't expand unmatched globs to themselves for runfile in /etc/services.d/*/run /etc/s6-overlay/s6-rc.d/*/run; do [ -f "$runfile" ] || continue echo "Starting: $runfile" @@ -103,7 +102,8 @@ if $PID1; then sed -i -E 's|s6-svwait[[:space:]]+-d[[:space:]]+([^[:space:]]+)|bash -c '\''while [ -f \1/supervise/pid ]; do sleep 0.5; done'\''|g' "$runfile" sed -i -E 's|s6-svwait[[:space:]]+-u[[:space:]]+([^[:space:]]+)|bash -c '\''until [ -f \1/supervise/pid ]; do sleep 0.5; done'\''|g' "$runfile" chmod +x "$runfile" - ( exec "$runfile" ) & true + (exec "$runfile") & + true done shopt -u nullglob fi @@ -119,19 +119,19 @@ if $PID1; then terminate() { echo "Termination signal received, forwarding to subprocesses..." # Terminate all direct child processes - if command -v pgrep &>/dev/null; then + if command -v pgrep &> /dev/null; then for pid in $(pgrep -P $$); do echo "Terminating child PID $pid" - kill -TERM "$pid" 2>/dev/null || echo "Failed to terminate PID $pid" + kill -TERM "$pid" 2> /dev/null || echo "Failed to terminate PID $pid" done else # Fallback: Scan /proc for children for pid in /proc/[0-9]*/; do pid=${pid#/proc/} pid=${pid%/} - if [[ "$pid" -ne 1 ]] && grep -q "^PPid:\s*$$" "/proc/$pid/status" 2>/dev/null; then + if [[ "$pid" -ne 1 ]] && grep -q "^PPid:\s*$$" "/proc/$pid/status" 2> /dev/null; then echo "Terminating child PID $pid" - kill -TERM "$pid" 2>/dev/null || echo "Failed to terminate PID $pid" + kill -TERM "$pid" 2> /dev/null || echo "Failed to terminate PID $pid" fi done fi diff --git a/birdnet-pi/rootfs/etc/cont-init.d/99-run.sh b/birdnet-pi/rootfs/etc/cont-init.d/99-run.sh index 0a4ee3f0a..458c739e4 100755 --- a/birdnet-pi/rootfs/etc/cont-init.d/99-run.sh +++ b/birdnet-pi/rootfs/etc/cont-init.d/99-run.sh @@ -73,9 +73,9 @@ if [ -n "${ALSA_CARD:-}" ]; then fi # Define permissions for audio -AUDIO_GID=$(stat -c %g /dev/snd/* | head -n1) && \ -( groupmod -o -g "$AUDIO_GID" audio 2>/dev/null || groupadd -o -g "$AUDIO_GID" audio || true ) && \ -usermod -aG audio "${USER:-pi}" || true +AUDIO_GID=$(stat -c %g /dev/snd/* | head -n1) \ + && (groupmod -o -g "$AUDIO_GID" audio 2> /dev/null || groupadd -o -g "$AUDIO_GID" audio || true) \ + && usermod -aG audio "${USER:-pi}" || true # Fix timezone as per installer CURRENT_TIMEZONE="$(timedatectl show --value --property=Timezone)" diff --git a/collabora/config.json b/collabora/config.json index c1e2fb75e..4298fc4c0 100644 --- a/collabora/config.json +++ b/collabora/config.json @@ -16,12 +16,12 @@ ], "name": "WIP - Collabora", "options": { - "domain": "", - "username": "", - "password": "", "aliasgroup1": "", "dictionaries": "", - "extra_params": "" + "domain": "", + "extra_params": "", + "password": "", + "username": "" }, "ports": { "9980/tcp": 9980 @@ -30,13 +30,13 @@ "9980/tcp": "Web interface" }, "schema": { - "domain": "str?", - "username": "str?", - "password": "password?", + "TZ": "str?", "aliasgroup1": "str?", "dictionaries": "str?", + "domain": "str?", "extra_params": "str?", - "TZ": "str?" + "password": "password?", + "username": "str?" }, "slug": "collabora", "url": "https://github.com/alexbelgium/hassio-addons", diff --git a/collabora/rootfs/etc/cont-init.d/99-run.sh b/collabora/rootfs/etc/cont-init.d/99-run.sh index 12303f91f..87c320206 100755 --- a/collabora/rootfs/etc/cont-init.d/99-run.sh +++ b/collabora/rootfs/etc/cont-init.d/99-run.sh @@ -48,7 +48,7 @@ ln -sf "${CONFIG_DEST}" "${COOL_CONFIG}" SYSTEMPLATE_DIR="/opt/cool/systemplate/etc" if [ -d "${SYSTEMPLATE_DIR}" ]; then cp /etc/hosts "${SYSTEMPLATE_DIR}/hosts" - cp /etc/hostname "${SYSTEMPLATE_DIR}/hostname" 2>/dev/null || true + cp /etc/hostname "${SYSTEMPLATE_DIR}/hostname" 2> /dev/null || true cp /etc/resolv.conf "${SYSTEMPLATE_DIR}/resolv.conf" fi chown 1001 /opt/cool/systemplate 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/rootfs/etc/services.d/nginx/run b/emby_beta/rootfs/etc/services.d/nginx/run old mode 100644 new mode 100755 diff --git a/filebrowser/README.md b/filebrowser/README.md index 6da58b462..edd19d21f 100644 --- a/filebrowser/README.md +++ b/filebrowser/README.md @@ -57,12 +57,12 @@ The web UI can be found at `:8071` or through the Home Assistant sideba | `keyfile` | str | `privkey.pem` | SSL private key file (in `/ssl/`) | | `NoAuth` | bool | `true` | Disable authentication (resets database when changed) | | `disable_thumbnails` | bool | `true` | Disable thumbnail generation for improved performance | -| `base_folder` | str | *(optional)* | Root folder for file browser (defaults to all mapped folders) | -| `localdisks` | str | *(optional)* | Local drives to mount (e.g., `sda1,sdb1,MYNAS`) | -| `networkdisks` | str | *(optional)* | SMB shares to mount (e.g., `//SERVER/SHARE`) | -| `cifsusername` | str | *(optional)* | SMB username for network shares | -| `cifspassword` | str | *(optional)* | SMB password for network shares | -| `cifsdomain` | str | *(optional)* | SMB domain for network shares | +| `base_folder` | str | _(optional)_ | Root folder for file browser (defaults to all mapped folders) | +| `localdisks` | str | _(optional)_ | Local drives to mount (e.g., `sda1,sdb1,MYNAS`) | +| `networkdisks` | str | _(optional)_ | SMB shares to mount (e.g., `//SERVER/SHARE`) | +| `cifsusername` | str | _(optional)_ | SMB username for network shares | +| `cifspassword` | str | _(optional)_ | SMB password for network shares | +| `cifsdomain` | str | _(optional)_ | SMB domain for network shares | ### Example Configuration diff --git a/grampsweb/config.yaml b/grampsweb/config.yaml index 2bb8b77af..7ae6abbe5 100644 --- a/grampsweb/config.yaml +++ b/grampsweb/config.yaml @@ -78,12 +78,13 @@ environment: } image: ghcr.io/alexbelgium/grampsweb-{arch} init: false -options: { +options: + { "CELERY_NUM_WORKERS": 2, "GUNICORN_NUM_WORKERS": 8, "certfile": "fullchain.pem", "keyfile": "privkey.pem", - "ssl": false + "ssl": false, } map: - type: addon_config diff --git a/nextcloud/rootfs/etc/services.d/cron/run b/nextcloud/rootfs/etc/services.d/cron/run old mode 100644 new mode 100755 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/omni-tools/rootfs/etc/cont-init.d/99-run.sh b/omni-tools/rootfs/etc/cont-init.d/99-run.sh index cd39d5284..27b247708 100755 --- a/omni-tools/rootfs/etc/cont-init.d/99-run.sh +++ b/omni-tools/rootfs/etc/cont-init.d/99-run.sh @@ -7,4 +7,4 @@ # Start omni-tools container content bashio::log.info "Starting application" -/./docker-entrypoint.sh nginx -g "daemon off;" &>/proc/1/fd/1 +/./docker-entrypoint.sh nginx -g "daemon off;" &> /proc/1/fd/1 diff --git a/photoprism/README.md b/photoprism/README.md index d0ac69fb0..fe798353b 100644 --- a/photoprism/README.md +++ b/photoprism/README.md @@ -48,7 +48,7 @@ Webui can be found at or through the sidebar using I Configurations can be done through the app webUI, except for the following options. **System Requirements**: Minimum 2 cores and 4GB RAM -**Default Credentials**: +**Default Credentials**: - Username: admin - Password: please_change_password diff --git a/plex/config.json b/plex/config.json index 2e26b2917..a69e0c521 100644 --- a/plex/config.json +++ b/plex/config.json @@ -170,10 +170,10 @@ "cifspassword": "str?", "cifsusername": "str?", "claim": "str", + "clear_codecs_folder": "bool?", "localdisks": "str?", "networkdisks": "str?", "skip_permissions_check": "bool?", - "clear_codecs_folder": "bool?", "smbv1": "bool?" }, "slug": "plex_nas", 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/nginx/run b/qbittorrent/rootfs/etc/services.d/nginx/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/scrutiny/rootfs/etc/services.d/nginx/run b/scrutiny/rootfs/etc/services.d/nginx/run old mode 100644 new mode 100755 diff --git a/sonarr/rootfs/etc/services.d/nginx/run b/sonarr/rootfs/etc/services.d/nginx/run old mode 100644 new mode 100755 diff --git a/tandoor_recipes/config.json b/tandoor_recipes/config.json index c0bedf57e..5fb122aaa 100644 --- a/tandoor_recipes/config.json +++ b/tandoor_recipes/config.json @@ -98,6 +98,9 @@ "80/tcp": "Web interface" }, "schema": { + "AI_API_KEY": "str?", + "AI_MODEL_NAME": "str?", + "AI_RATELIMIT": "str?", "ALLOWED_HOSTS": "str?", "DB_TYPE": "list(sqlite|postgresql_external)", "DEBUG": "list(1|0)", @@ -107,9 +110,6 @@ "POSTGRES_PORT": "str?", "POSTGRES_USER": "str?", "SECRET_KEY": "str", - "AI_MODEL_NAME": "str?", - "AI_API_KEY": "str?", - "AI_RATELIMIT": "str?", "externalfiles_folder": "str?" }, "services": [ diff --git a/tdarr/README.md b/tdarr/README.md index b2b75981e..6a320c2d2 100644 --- a/tdarr/README.md +++ b/tdarr/README.md @@ -77,7 +77,7 @@ cifsdomain: "workgroup" ### Setting up Distributed Transcoding -1. **Configure the Server**: +1. **Configure the Server**: - Access the Web UI at `:8265` - Set up your media libraries and transcoding settings - Configure plugins and workflows as needed diff --git a/zzz_archived_bitwarden/rootfs/etc/services.d/bitwarden/run b/zzz_archived_bitwarden/rootfs/etc/services.d/bitwarden/run old mode 100644 new mode 100755 diff --git a/zzz_archived_bitwarden/rootfs/etc/services.d/nginx/run b/zzz_archived_bitwarden/rootfs/etc/services.d/nginx/run old mode 100644 new mode 100755