Compare commits

..

24 Commits

Author SHA1 Message Date
github-actions
dacc4abef9 GitHub bot: changelog [nobuild] 2026-09-17 13:51:31 +00:00
Alexandre
c0bb781e6b Update config.yaml 2026-09-17 15:45:18 +02:00
github-actions
dcc21988e3 GitHub bot: changelog [nobuild] 2026-09-17 10:23:46 +00:00
Alexandre
47363725ea Update config.yaml 2026-09-17 12:17:36 +02:00
github-actions
b42a6ac3aa GitHub bot: changelog [nobuild] 2026-09-17 05:55:48 +00:00
Alexandre
f61b3b95d3 Update config.yaml 2026-09-17 07:49:33 +02:00
github-actions
15a2abe451 GitHub bot: changelog [nobuild] 2026-09-16 15:54:51 +00:00
Alexandre
4c1038916d Update config.yaml 2026-09-16 17:49:36 +02:00
github-actions
71bbdb0929 GitHub bot: changelog [nobuild] 2026-09-16 14:04:48 +00:00
Alexandre
41f0863702 Update config.yaml 2026-09-16 15:58:39 +02:00
github-actions
8fec8556e8 GitHub bot: changelog [nobuild] 2026-09-16 11:35:30 +00:00
Alexandre
3ec897fa38 Update config.yaml 2026-09-16 13:29:08 +02:00
GitHub Actions
5a4d7b2f8c Revert "Update config.yaml"
This reverts commit b519002cea.
2026-09-16 09:01:55 +00:00
Alexandre
b519002cea Update config.yaml 2026-09-16 10:58:36 +02:00
github-actions
bad72b9451 GitHub bot: changelog [nobuild] 2026-09-15 10:03:57 +00:00
Alexandre
4028564991 Update config.yaml 2026-09-15 11:57:02 +02:00
GitHub Actions
096db771fc Revert "birdnet-go-dev: bump to 20260915 (upstream sync, PR updates)"
This reverts commit 58e98fb63c.
2026-09-15 07:11:59 +00:00
BirdNET-Go Addon Builder
58e98fb63c birdnet-go-dev: bump to 20260915 (upstream sync, PR updates) 2026-09-15 09:05:40 +02:00
dependabot[bot]
40d0401ccd build(deps): bump home-assistant/builder from 2026.06.0 to 2026.09.0 (#3065)
Bumps [home-assistant/builder](https://github.com/home-assistant/builder) from 2026.06.0 to 2026.09.0.
- [Release notes](https://github.com/home-assistant/builder/releases)
- [Commits](https://github.com/home-assistant/builder/compare/2026.06.0...2026.09.0)

---
updated-dependencies:
- dependency-name: home-assistant/builder
  dependency-version: 2026.09.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-15 07:23:11 +02:00
dependabot[bot]
883b38cacc build(deps): bump anthropics/claude-code-action from 1.0.216 to 1.0.222 (#3066)
Bumps [anthropics/claude-code-action](https://github.com/anthropics/claude-code-action) from 1.0.216 to 1.0.222.
- [Release notes](https://github.com/anthropics/claude-code-action/releases)
- [Commits](d75b94d5ad...56cf60fde4)

---
updated-dependencies:
- dependency-name: anthropics/claude-code-action
  dependency-version: 1.0.222
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-15 07:22:17 +02:00
github-actions
80821a7d9a Github bot : image compressed 2026-09-13 23:13:02 +00:00
Alexandre
e7f8c37695 Remove scheduled linting from lint.yml
Removed scheduled linting from the workflow.
2026-09-13 07:13:33 +02:00
Alexandre
88faf503fb fix(transmission): let incomplete-dir stay off across restarts (#3063)
* fix(transmission): let incomplete-dir stay off across restarts

01-config.sh rewrites Transmission's settings.json on every restart,
deriving "incomplete-dir-enabled" purely from whether incomplete_dir is
non-empty. Since incomplete_dir defaults to a non-empty path, any toggle
made in Transmission's own Web UI was silently overwritten back to enabled
on the next restart (#3059).

Add incomplete_dir_enabled (bool, default true): setting it to false writes
the disabled state on every restart instead of forcing it back on. The
default of true preserves normal existing configurations unchanged; the two
edge cases it also touches were already latent bugs, see below.

While touching this line: bashio::config's own default-value argument
cannot be an empty string (bash's ${2:-null} treats "" as unset), so an
install whose incomplete_dir key was entirely absent, or literally the four
characters "null", returned bashio's own "null" fallback and would have
created a directory named "null". Normalized that explicitly; both now
disable instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(transmission): keep incomplete-dir enabled on upgrade in standalone mode

The previous commit relied on bashio::config's default argument to treat
an absent incomplete_dir_enabled as true. The standalone shim
(.templates/bashio-standalone.sh), injected by 00-banner.sh when the image
runs without Supervisor, ignores that argument and returns "" for a
missing key, so an upgraded standalone install would have silently
disabled its incomplete directory.

Treat anything but an explicit "false" as enabled instead. That covers
real bashio ("null") and the shim ("") alike, and drops the default
argument altogether.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 07:10:57 +02:00
github-actions[bot]
b88c5c5826 Update stargazer map & cache 2026-09-13 00:55:02 +00:00
449 changed files with 2782 additions and 2900 deletions

View File

@@ -30,14 +30,8 @@ VAR="${1:?usage: env_trace.sh <VAR> [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} =="
@@ -86,8 +80,7 @@ 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"
@@ -129,8 +122,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

View File

@@ -22,17 +22,10 @@ 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,20p' "$0" | sed 's/^# \?//'
exit 1
}
CMD="${1:-}"; PR="${2:-}"
[ -z "$CMD" ] || [ -z "$PR" ] && { sed -n '2,20p' "$0" | sed 's/^# \?//'; exit 1; }
case "$CMD" in
list)
@@ -50,8 +43,7 @@ case "$CMD" in
--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}"
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=$?
@@ -77,12 +69,8 @@ case "$CMD" in
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
}
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 <PR> <THREAD_ID...> (or --all, with confirmation)" >&2
@@ -93,10 +81,7 @@ case "$CMD" in
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
}
[ -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}}}" \
@@ -116,9 +101,7 @@ case "$CMD" in
# CI later counts as blocking until someone puts it here on purpose.
ADVISORY_CHECKS="Codacy Static Code Analysis" # one per line if more are ever added
wfail=2 # not 0: running out of minutes with checks still pending is not a pass
c=""
bstates=""
adv=""
c=""; bstates=""; adv=""
for i in $(seq 1 "$MINS"); do
# gh pr checks emits TAB-separated columns with no header when its output is not a TTY,
# which inside this $(... | awk) it never is. (Attached to a terminal it prints a wholly
@@ -138,8 +121,7 @@ case "$CMD" in
# 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
sleep 60; continue
fi
c=$(printf '%s\n' "$rows" | cut -f2 | tr '\n' ' ')
echo "[$i] $c"
@@ -149,14 +131,12 @@ case "$CMD" in
adv=$(printf '%s\n' "$rows" | awk -F'\t' '$1 == "A" { print $2 }' | tr '\n' ' ')
if [ -z "$bstates" ]; then
echo " only advisory checks have reported — no blocking check has run yet"
sleep 60
continue
sleep 60; continue
fi
# Allowlist the good states rather than denylisting the bad ones: an unrecognised state
# must land in the failure branch, because falling through to "passing" is this command's
# worst outcome.
nbad=0
npend=0
nbad=0; npend=0
for s in $bstates; do
case "$s" in
pass | skipping) ;;
@@ -166,17 +146,13 @@ case "$CMD" in
done
if [ "$nbad" -gt 0 ]; then
echo "settled — blocking checks FAILED:"
printf '%s\n' "$rows" \
| awk -F'\t' '$1 == "B" && $3 != "pass" && $3 != "skipping" && $3 != "pending" { print " " $2 }'
wfail=1
break
printf '%s\n' "$rows" |
awk -F'\t' '$1 == "B" && $3 != "pass" && $3 != "skipping" && $3 != "pending" { print " " $2 }'
wfail=1; break
elif [ "$npend" -gt 0 ]; then
sleep 60
continue
sleep 60; continue
else
echo "settled — blocking checks passing"
wfail=0
break
echo "settled — blocking checks passing"; wfail=0; break
fi
done
[ "$wfail" -eq 2 ] && echo "gave up after ${MINS}m, checks still unsettled — NOT a pass"
@@ -187,8 +163,5 @@ case "$CMD" in
echo "note: long queues here are usually account runner contention, not your diff."
exit "$wfail"
;;
*)
echo "unknown: $CMD"
exit 1
;;
*) echo "unknown: $CMD"; exit 1 ;;
esac

View File

@@ -59,10 +59,7 @@ 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
@@ -84,8 +81,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

View File

@@ -12,10 +12,7 @@
set -uo pipefail
TRAPS="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/references/traps.md"
[ -f "$TRAPS" ] || {
echo "not found: $TRAPS" >&2
exit 1
}
[ -f "$TRAPS" ] || { echo "not found: $TRAPS" >&2; exit 1; }
# The Contents list duplicates the headings; grep the headings themselves so the list cannot drift.
list() {
@@ -23,16 +20,13 @@ list() {
grep '^## ' "$TRAPS" | grep -v '^## Contents' | sed 's/^## / /'
}
[ $# -eq 0 ] && {
list
exit 0
}
[ $# -eq 0 ] && { list; exit 0; }
# awk over exact heading text: section names contain '/' and other characters that would need
# escaping in a sed address, and a keyword matching several headings should be an error, not a
# silent pick of the first.
mapfile -t matches < <(grep '^## ' "$TRAPS" | grep -v '^## Contents' \
| grep -iF -- "$1" | sed 's/^## //')
mapfile -t matches < <(grep '^## ' "$TRAPS" | grep -v '^## Contents' |
grep -iF -- "$1" | sed 's/^## //')
case "${#matches[@]}" in
0)

View File

@@ -13,31 +13,22 @@ 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 <addon-dir>"
exit 1
echo "pass one explicitly: validate.sh <addon-dir>"; exit 1
fi
ADDON="${_dirs[0]:-}"
fi
[ -z "$ADDON" ] && {
echo "usage: validate.sh <addon-dir> [--vs-master]"
exit 1
}
[ -z "$ADDON" ] && { echo "usage: validate.sh <addon-dir> [--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 =="
@@ -45,22 +36,14 @@ 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"
@@ -82,16 +65,13 @@ 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' || {
python3 - "$ADDON/config.yaml" <<'PY' || { note "config.yaml" "FAIL parse"; fail=1; }
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)"
@@ -99,10 +79,7 @@ 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" ] && {
@@ -119,8 +96,7 @@ 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"
@@ -134,8 +110,7 @@ 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.
@@ -150,26 +125,14 @@ 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)
@@ -178,8 +141,7 @@ 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)"

View File

@@ -28,10 +28,7 @@ if [ -n "$RAW" ]; then
# 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
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
@@ -41,10 +38,7 @@ if [ -n "$RAW" ]; then
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
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.

View File

@@ -250,6 +250,7 @@ F4bsi,Germany,
Fabaderheld,Austria,
Fabeuss,France,
Fabian-Eigenherd,Germany,
Fabiot9,,2026-09-13
Faithfinder,Canada,
FallsSteven,,2026-08-10
Felitendo,Germany,
@@ -471,6 +472,7 @@ MNDani,,2026-08-10
MTHarden,United States,
MYLE-01,New Zealand,
MaBeniu,,2026-08-10
Maboroshi0327,,2026-09-13
MachinaDev,,2026-08-10
Madelena,United States,
MagicMau,,2026-08-10
@@ -515,6 +517,7 @@ Mofx-01,,2026-08-10
Mokdeze,,2026-08-10
MondoGao,United States,
Moosh-be,Belgium,
Moozzuzz,,2026-09-13
MrAct1on,United States,
MrCraigen,,2026-08-10
MrHacky,,2026-08-10
@@ -952,6 +955,7 @@ austinmccalley,,2026-08-10
autodeck,United Kingdom,
aviadlevy,,2026-08-10
aviv926,,2026-08-10
axelburks,United States,2026-09-13
axute,Germany,
azerioxal,United States,
azure1922,,2026-08-10
@@ -1043,6 +1047,7 @@ brettmiller,United States,
brewston,,2026-08-10
brianalexander,,2026-08-10
brianm71,,2026-08-10
brietman,,2026-09-13
brittek,Australia,
brokec,,2026-08-10
brunerm99,,2026-08-10
@@ -1451,6 +1456,7 @@ gh-residante,,2026-08-10
ghisch,,2026-08-10
gieljnssns,Belgium,
gigatexel,,2026-08-10
gilberth,Peru,2026-09-13
gileswells,United States,
giotec,,2026-08-10
git-mdumont,,
@@ -1771,6 +1777,7 @@ ldec,,2026-08-10
ldkdev,Viet Nam,
le-pet,,2026-08-10
lead0r,,2026-08-10
leaskovski,,2026-09-13
legovaer,Belgium,
legusha,,2026-08-10
lehnerpat,,2026-08-10
@@ -2001,6 +2008,8 @@ najdias,Portugal,
nalditopr,,2026-08-10
nana4rider,Japan,
naor1,Israel,
narmod,,2026-09-13
nascentt,,2026-09-13
natbrood,,2026-08-10
nate-marshall,,2026-08-10
nduest,Germany,
@@ -2583,6 +2592,7 @@ w10devheh,,2026-08-10
waako,,2026-08-10
walduino,,2026-08-10
wangjiezhe,China,
wannes-wagemans,Belgium,2026-09-13
warbringer,,2026-08-10
wardbeyens,Belgium,
warkurre86,,2026-08-10
1 username country last_checked
250 Fabaderheld Austria
251 Fabeuss France
252 Fabian-Eigenherd Germany
253 Fabiot9 2026-09-13
254 Faithfinder Canada
255 FallsSteven 2026-08-10
256 Felitendo Germany
472 MTHarden United States
473 MYLE-01 New Zealand
474 MaBeniu 2026-08-10
475 Maboroshi0327 2026-09-13
476 MachinaDev 2026-08-10
477 Madelena United States
478 MagicMau 2026-08-10
517 Mokdeze 2026-08-10
518 MondoGao United States
519 Moosh-be Belgium
520 Moozzuzz 2026-09-13
521 MrAct1on United States
522 MrCraigen 2026-08-10
523 MrHacky 2026-08-10
955 autodeck United Kingdom
956 aviadlevy 2026-08-10
957 aviv926 2026-08-10
958 axelburks United States 2026-09-13
959 axute Germany
960 azerioxal United States
961 azure1922 2026-08-10
1047 brewston 2026-08-10
1048 brianalexander 2026-08-10
1049 brianm71 2026-08-10
1050 brietman 2026-09-13
1051 brittek Australia
1052 brokec 2026-08-10
1053 brunerm99 2026-08-10
1456 ghisch 2026-08-10
1457 gieljnssns Belgium
1458 gigatexel 2026-08-10
1459 gilberth Peru 2026-09-13
1460 gileswells United States
1461 giotec 2026-08-10
1462 git-mdumont
1777 ldkdev Viet Nam
1778 le-pet 2026-08-10
1779 lead0r 2026-08-10
1780 leaskovski 2026-09-13
1781 legovaer Belgium
1782 legusha 2026-08-10
1783 lehnerpat 2026-08-10
2008 nalditopr 2026-08-10
2009 nana4rider Japan
2010 naor1 Israel
2011 narmod 2026-09-13
2012 nascentt 2026-09-13
2013 natbrood 2026-08-10
2014 nate-marshall 2026-08-10
2015 nduest Germany
2592 waako 2026-08-10
2593 walduino 2026-08-10
2594 wangjiezhe China
2595 wannes-wagemans Belgium 2026-09-13
2596 warbringer 2026-08-10
2597 wardbeyens Belgium
2598 warkurre86 2026-08-10

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 67 KiB

BIN
.github/stats.png vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -125,7 +125,7 @@ jobs:
- name: Analyse and fix
if: steps.batch.outputs.count != '0'
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1
uses: anthropics/claude-code-action@56cf60fde42f7b19c3abfd5c9c48b69a1288461f # v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# Skip the OIDC -> Claude App token exchange. The scheduled path

View File

@@ -7,8 +7,6 @@ on:
- "**/config.*"
pull_request:
branches: [ master ]
schedule:
- cron: "0 0 * * 0"
workflow_dispatch:
permissions:

View File

@@ -64,7 +64,7 @@ jobs:
fetch-depth: 1
- name: Run Claude Code
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1
uses: anthropics/claude-code-action@56cf60fde42f7b19c3abfd5c9c48b69a1288461f # v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# AI_PR_TOKEN, not GITHUB_TOKEN, so a PR Claude opens triggers CI.

View File

@@ -135,7 +135,7 @@ jobs:
- name: Execute the plan
if: steps.bundle.outputs.has_plan == 'true'
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1
uses: anthropics/claude-code-action@56cf60fde42f7b19c3abfd5c9c48b69a1288461f # v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# Skip the OIDC -> Claude App token exchange, which 401s whenever

View File

@@ -166,7 +166,7 @@ jobs:
id: classify
if: github.event_name != 'issue_comment' || steps.claim.outputs.go == 'true'
continue-on-error: true
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1
uses: anthropics/claude-code-action@56cf60fde42f7b19c3abfd5c9c48b69a1288461f # v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# Without this the action falls back to the OIDC -> Claude App token

View File

@@ -79,7 +79,7 @@ jobs:
- name: Address CodeRabbit comments
if: steps.claim.outputs.go == 'true'
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1
uses: anthropics/claude-code-action@56cf60fde42f7b19c3abfd5c9c48b69a1288461f # v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# Skip the OIDC -> Claude App token exchange, which 401s whenever

View File

@@ -306,7 +306,7 @@ jobs:
id: build
if: steps.info.outputs.build_arch == 'true' && steps.info.outputs.has_dockerfile == 'true'
continue-on-error: true
uses: home-assistant/builder/actions/build-image@2026.06.0
uses: home-assistant/builder/actions/build-image@2026.09.0
with:
arch: ${{ matrix.arch }}
cache-gha: "false"
@@ -331,7 +331,7 @@ jobs:
# else for the retry to be skipped from.
- name: Build ${{ matrix.addon }} add-on (retry after failed attempt)
if: steps.build.outcome == 'failure'
uses: home-assistant/builder/actions/build-image@2026.06.0
uses: home-assistant/builder/actions/build-image@2026.09.0
with:
arch: ${{ matrix.arch }}
cache-gha: "false"

View File

@@ -19,8 +19,8 @@ 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 -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

View File

@@ -152,8 +152,8 @@ 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
@@ -193,10 +193,7 @@ 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"

View File

@@ -11,14 +11,8 @@ pick_exec_dir() {
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
}
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"

View File

@@ -46,8 +46,7 @@ _bashio_color() {
}
_bashio_log() {
local c="${1:-}"
shift || true
local c="${1:-}"; shift || true
printf '%s%s%s\n' "$(_bashio_color "$c")" "$*" "$(_bashio_color reset)"
}
@@ -247,10 +246,7 @@ bashio::info.supervisor() { printf '%s' "standalone"; }
# -----------------------------------------------------------------------------
bashio::config() {
local key="${1:-}"
[ -n "$key" ] || {
printf '%s' ""
return 0
}
[ -n "$key" ] || { printf '%s' ""; return 0; }
local v=""
if _bashio_env_get "$key" >/dev/null 2>&1; then
@@ -360,10 +356,7 @@ bashio::host.hostname() {
# bashio::services.available "mqtt"
bashio::services() {
local svc="${1:-}" key="${2:-}"
[ -n "$svc" ] && [ -n "$key" ] || {
printf '%s' ""
return 0
}
[ -n "$svc" ] && [ -n "$key" ] || { printf '%s' ""; return 0; }
local upper svc_upper var v=""
upper="$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')"
@@ -426,11 +419,7 @@ bashio::homeassistant.token() {
# Exit helpers
# -----------------------------------------------------------------------------
bashio::exit.ok() { exit 0; }
bashio::exit.nok() {
local m="${1:-}"
[ -n "$m" ] && bashio::log.red "$m"
exit 1
}
bashio::exit.nok() { local m="${1:-}"; [ -n "$m" ] && bashio::log.red "$m"; exit 1; }
# -----------------------------------------------------------------------------
# Core config check shim

View File

@@ -76,14 +76,8 @@ pick_exec_dir() {
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
}
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"
@@ -263,8 +257,8 @@ if $PID1 && { [ -x /command/with-contenv ] || [ -x /usr/bin/with-contenv ]; }; t
# 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
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

View File

@@ -109,7 +109,7 @@ never a default.
### 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:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

0
bazarr/rootfs/etc/services.d/nginx/run Executable file → Normal file
View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

0
bentopdf/rootfs/etc/s6-overlay/s6-rc.d/bentopdf/run Executable file → Normal file
View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,3 +1,17 @@
## 20260917.2 (17-09-2026)
- Minor bugs fixed
## 20260917.1 (17-09-2026)
- Minor bugs fixed
## 20260917 (17-09-2026)
- Minor bugs fixed
## 20260916.2 (16-09-2026)
- Minor bugs fixed
## 20260916.1 (16-09-2026)
- Minor bugs fixed
## 20260916 (16-09-2026)
- Minor bugs fixed
## 20260915 (15-09-2026)
- Minor bugs fixed
## 20260912.2 (12-09-2026)
- Minor bugs fixed
## 20260912 (12-09-2026)

View File

@@ -75,7 +75,7 @@ Requires a second model to confirm the **first** detection of each bird species
The first detection of a species in a day is the weakest evidence the pipeline produces, and it is the one that creates a "new species today" entry. Asking two models to agree on just that one detection removes most spurious new-species entries without slowing anything else down.
**Off by default.** Turn it on in the web UI under _Settings → Filters → First Daily Detection Consensus_, or in `config.yaml`:
**Off by default.** Turn it on in the web UI under *Settings → Filters → First Daily Detection Consensus*, or in `config.yaml`:
```yaml
realtime:
@@ -89,7 +89,7 @@ It deliberately does **nothing** in these cases, all of which keep today's singl
- you run only one bird model (the default) — a second opinion does not exist, so the rule can never trigger
- the species is not a bird — bats and the non-bird sound classes Perch reports (insects, amphibians, mammals, `power_tool`, and so on)
- the species is not known to _every_ active bird model analyzing that audio source — a species only one of them can name could never reach two confirmations. With several sources running different model combinations, this is decided per source, not add-on-wide
- the species is not known to *every* active bird model analyzing that audio source — a species only one of them can name could never reach two confirmations. With several sources running different model combinations, this is decided per source, not add-on-wide
- a dynamic threshold has actually lowered the bar for that species, meaning you asked for a more permissive gate
- the taxonomy or the database cannot be consulted — it fails open and accepts the detection

View File

@@ -127,5 +127,5 @@ slug: birdnet-go-dev
udev: true
url: https://github.com/alexbelgium/hassio-addons
usb: true
version: "20260912.3"
version: "20260917.2"
video: true

View File

@@ -33,10 +33,7 @@ TARGET_DIR=""
while [ "$#" -gt 0 ]; do
case "$1" in
--check) CHECK_ONLY=1 ;;
-*)
echo "unknown option: $1" >&2
exit 64
;;
-*) echo "unknown option: $1" >&2; exit 64 ;;
*)
# Last-one-wins would silently clone into the wrong directory if a caller ever
# appended an argument; the pre-flag script used "${1}", so refuse rather than

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -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:**

View File

@@ -112,7 +112,6 @@ 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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -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:**

View File

@@ -112,7 +112,6 @@ 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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -73,7 +73,7 @@ map:
name: BirdNET-PiPy
options:
env_vars: []
ICECAST_PASSWORD: ""
ICECAST_PASSWORD: ''
data_location: /config/data
panel_icon: mdi:bird
ports:

0
birdnet-pipy/rootfs/etc/services.d/api/run Executable file → Normal file
View File

0
birdnet-pipy/rootfs/etc/services.d/icecast/run Executable file → Normal file
View File

0
birdnet-pipy/rootfs/etc/services.d/main/run Executable file → Normal file
View File

0
birdnet-pipy/rootfs/etc/services.d/model/run Executable file → Normal file
View File

0
birdnet-pipy/rootfs/etc/services.d/nginx/run Executable file → Normal file
View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

0
bitwarden/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/run Executable file → Normal file
View File

0
bitwarden/rootfs/etc/s6-overlay/s6-rc.d/nginx/run Executable file → Normal file
View File

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

1
browser_chromium/rootfs/etc/cont-init.d/20-folders.sh Normal file → Executable file
View File

@@ -7,6 +7,7 @@ set -e
PUID=$(bashio::config "PUID")
PGID=$(bashio::config "PGID")
# Create cache
#mkdir -p /.cache
#chmod 755 /.cache

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -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`).

View File

@@ -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"

0
changedetection.io/rootfs/etc/services.d/nginx/run Executable file → Normal file
View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -338,7 +338,8 @@ 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

0
claude_desktop/rootfs/usr/local/bin/codex-login Normal file → Executable file
View File

12
claude_desktop/rootfs/usr/local/bin/ha-cli Normal file → Executable file
View File

@@ -133,9 +133,7 @@ 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")
@@ -143,9 +141,7 @@ 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:
@@ -218,9 +214,7 @@ def main(argv):
sys.exit("usage: ha-cli call <domain.service> [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))

View File

@@ -76,11 +76,7 @@ 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 []
@@ -89,14 +85,10 @@ 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 = []

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,7 +1,8 @@
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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

0
comicarr/rootfs/etc/services.d/comicarr/run Executable file → Normal file
View File

0
comicarr/rootfs/etc/services.d/nginx/run Executable file → Normal file
View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

0
emby/rootfs/etc/services.d/nginx/run Executable file → Normal file
View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -4,17 +4,9 @@ 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}"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -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
TIMEOUT=60
VNC_LOGIN_TIMEOUT=180
WIDTH=1280
HEIGHT=720
TIMEOUT=60
LOGIN_TIMEOUT=180
VNC_LOGIN_TIMEOUT=180
NOVNC_PORT=6080
# Public address used in notification links when behind a reverse proxy.
# VNC_URL=https://fgc.example.tld

View File

@@ -47,10 +47,8 @@ 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"
)
@@ -101,7 +99,8 @@ 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,
@@ -118,7 +117,8 @@ 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,12 +209,7 @@ 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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Some files were not shown because too many files have changed in this diff Show More