mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-09-18 23:57:37 +02:00
Compare commits
18 Commits
create-pul
...
d31ccfa21c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d31ccfa21c | ||
|
|
9c277876ff | ||
|
|
7e59aa8803 | ||
|
|
360fd669fa | ||
|
|
7bf77c8558 | ||
|
|
a195d3ac39 | ||
|
|
14834d4063 | ||
|
|
f5caafd62c | ||
|
|
fd61631ccd | ||
|
|
578a7f8368 | ||
|
|
5115dcb93a | ||
|
|
fa5e890c4c | ||
|
|
addb0ca66f | ||
|
|
16e112b21f | ||
|
|
040a4e0f2f | ||
|
|
f72f7bef0f | ||
|
|
c18f45d822 | ||
|
|
abf3d76873 |
@@ -30,14 +30,8 @@ VAR="${1:?usage: env_trace.sh <VAR> [process-name-or-pid]}"
|
|||||||
TARGET="${2:-}"
|
TARGET="${2:-}"
|
||||||
# VAR is interpolated into grep/sed patterns below — restrict it to a valid env var name
|
# VAR is interpolated into grep/sed patterns below — restrict it to a valid env var name
|
||||||
case "$VAR" in
|
case "$VAR" in
|
||||||
[A-Za-z_]*) [ -z "${VAR//[A-Za-z0-9_]/}" ] || {
|
[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
|
*) echo "invalid env var name: $VAR" >&2; exit 1 ;;
|
||||||
exit 1
|
|
||||||
} ;;
|
|
||||||
*)
|
|
||||||
echo "invalid env var name: $VAR" >&2
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
echo "== tracing ${VAR} =="
|
echo "== tracing ${VAR} =="
|
||||||
@@ -86,8 +80,7 @@ echo "3. s6 container_environment (only read by services using #!/usr/bin/with-c
|
|||||||
seen3=0
|
seen3=0
|
||||||
for d in /var/run/s6/container_environment /run/s6/container_environment; do
|
for d in /var/run/s6/container_environment /run/s6/container_environment; do
|
||||||
if [ -f "$d/$VAR" ]; then
|
if [ -f "$d/$VAR" ]; then
|
||||||
echo " $d/$VAR = [$(cat "$d/$VAR")]"
|
echo " $d/$VAR = [$(cat "$d/$VAR")]"; seen3=1
|
||||||
seen3=1
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
[ "$seen3" -eq 0 ] && echo " not present in either envdir"
|
[ "$seen3" -eq 0 ] && echo " not present in either envdir"
|
||||||
@@ -129,8 +122,8 @@ else
|
|||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
# What it was actually launched with beats any theory about its environment.
|
# What it was actually launched with beats any theory about its environment.
|
||||||
tr '\0' '\n' < "/proc/$pid/cmdline" 2> /dev/null | tail -n +2 \
|
tr '\0' '\n' < "/proc/$pid/cmdline" 2> /dev/null | tail -n +2 |
|
||||||
| grep -iE "res|screen|${VAR}" | head -3 | sed 's/^/ argv: /'
|
grep -iE "res|screen|${VAR}" | head -3 | sed 's/^/ argv: /'
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -47,10 +47,7 @@ if [ -n "${BUILD_VERSION:-}" ]; then
|
|||||||
if [ -z "$SLUG" ] && [ -n "${HOSTNAME:-}" ]; then
|
if [ -z "$SLUG" ] && [ -n "${HOSTNAME:-}" ]; then
|
||||||
base=$(printf '%s' "$HOSTNAME" | sed 's/^[0-9a-f]\{8\}-//')
|
base=$(printf '%s' "$HOSTNAME" | sed 's/^[0-9a-f]\{8\}-//')
|
||||||
for cand in "$(printf '%s' "$base" | tr '-' '_')" "$base"; do
|
for cand in "$(printf '%s' "$base" | tr '-' '_')" "$base"; do
|
||||||
[ -f "$REPO/$cand/config.yaml" ] && {
|
[ -f "$REPO/$cand/config.yaml" ] && { SLUG="$cand"; break; }
|
||||||
SLUG="$cand"
|
|
||||||
break
|
|
||||||
}
|
|
||||||
done
|
done
|
||||||
[ -z "$SLUG" ] && SLUG="$base"
|
[ -z "$SLUG" ] && SLUG="$base"
|
||||||
fi
|
fi
|
||||||
@@ -72,8 +69,8 @@ if [ -n "${BUILD_VERSION:-}" ]; then
|
|||||||
else
|
else
|
||||||
echo " MISMATCH — this branch is NOT what is running."
|
echo " MISMATCH — this branch is NOT what is running."
|
||||||
git fetch origin master --quiet 2> /dev/null
|
git fetch origin master --quiet 2> /dev/null
|
||||||
master=$(git show origin/master:"$SLUG/config.yaml" 2> /dev/null \
|
master=$(git show origin/master:"$SLUG/config.yaml" 2> /dev/null |
|
||||||
| grep -E '^version:' | head -1 | tr -d "\"'" | awk '{print $2}')
|
grep -E '^version:' | head -1 | tr -d "\"'" | awk '{print $2}')
|
||||||
echo " origin/master version = ${master:-unknown}"
|
echo " origin/master version = ${master:-unknown}"
|
||||||
echo " -> work from origin/master; analysing this branch will mislead you."
|
echo " -> work from origin/master; analysing this branch will mislead you."
|
||||||
echo
|
echo
|
||||||
|
|||||||
@@ -13,31 +13,22 @@ set -uo pipefail
|
|||||||
if root=$(git rev-parse --show-toplevel 2> /dev/null); then cd "$root" || exit 1; fi
|
if root=$(git rev-parse --show-toplevel 2> /dev/null); then cd "$root" || exit 1; fi
|
||||||
|
|
||||||
ADDON="${1:-}"
|
ADDON="${1:-}"
|
||||||
[ "${ADDON:-}" = "--vs-master" ] && {
|
[ "${ADDON:-}" = "--vs-master" ] && { ADDON=""; set -- --vs-master; }
|
||||||
ADDON=""
|
|
||||||
set -- --vs-master
|
|
||||||
}
|
|
||||||
VS_MASTER=false
|
VS_MASTER=false
|
||||||
for a in "$@"; do [ "$a" = "--vs-master" ] && VS_MASTER=true; done
|
for a in "$@"; do [ "$a" = "--vs-master" ] && VS_MASTER=true; done
|
||||||
|
|
||||||
if [ -z "$ADDON" ]; then
|
if [ -z "$ADDON" ]; then
|
||||||
mapfile -t _dirs < <(git diff --name-only origin/master...HEAD 2> /dev/null \
|
mapfile -t _dirs < <(git diff --name-only origin/master...HEAD 2> /dev/null |
|
||||||
| cut -d/ -f1 | sort -u | grep -vE '^\.')
|
cut -d/ -f1 | sort -u | grep -vE '^\.' )
|
||||||
if [ "${#_dirs[@]}" -gt 1 ]; then
|
if [ "${#_dirs[@]}" -gt 1 ]; then
|
||||||
echo "several changed dirs: ${_dirs[*]}"
|
echo "several changed dirs: ${_dirs[*]}"
|
||||||
echo "pass one explicitly: validate.sh <addon-dir>"
|
echo "pass one explicitly: validate.sh <addon-dir>"; exit 1
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
ADDON="${_dirs[0]:-}"
|
ADDON="${_dirs[0]:-}"
|
||||||
fi
|
fi
|
||||||
[ -z "$ADDON" ] && {
|
[ -z "$ADDON" ] && { echo "usage: validate.sh <addon-dir> [--vs-master]"; exit 1; }
|
||||||
echo "usage: validate.sh <addon-dir> [--vs-master]"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
git rev-parse --verify origin/master > /dev/null 2>&1 || {
|
git rev-parse --verify origin/master > /dev/null 2>&1 || {
|
||||||
echo "origin/master missing — run: git fetch origin master"
|
echo "origin/master missing — run: git fetch origin master"; exit 1; }
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
export PYTHONDONTWRITEBYTECODE=1
|
export PYTHONDONTWRITEBYTECODE=1
|
||||||
echo "== validating $ADDON =="
|
echo "== validating $ADDON =="
|
||||||
|
|
||||||
@@ -45,22 +36,14 @@ fail=0
|
|||||||
note() { printf ' %-13s %s\n' "$1" "$2"; }
|
note() { printf ' %-13s %s\n' "$1" "$2"; }
|
||||||
# execline `run`/`finish` files are not shell (25 of them here, across 21 add-ons). Neither
|
# 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.
|
# linter below can read one, so anything either says about it is noise.
|
||||||
is_execline() {
|
is_execline() { local l; IFS= read -r l < "$1" 2> /dev/null; [[ $l == '#!'*execlineb* ]]; }
|
||||||
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.
|
# Shell: bash -n then shellcheck -x (follows sourced files, as CI does). One list for both.
|
||||||
files=()
|
files=()
|
||||||
while IFS= read -r f; do is_execline "$f" || files+=("$f"); done \
|
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)
|
< <(find "$ADDON" -type f \( -name '*.sh' -o -name 'run' -o -name 'finish' -o -name 'autostart' \) 2> /dev/null)
|
||||||
for f in "${files[@]}"; do
|
for f in "${files[@]}"; do
|
||||||
if ! out=$(bash -n "$f" 2>&1); then
|
if ! out=$(bash -n "$f" 2>&1); then note "bash -n" "FAIL $f"; echo "$out" | sed 's/^/ /'; fail=1; fi
|
||||||
note "bash -n" "FAIL $f"
|
|
||||||
echo "$out" | sed 's/^/ /'
|
|
||||||
fail=1
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
[ "$fail" -eq 0 ] && note "bash -n" "${#files[@]} file(s) checked"
|
[ "$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
|
if [ -f "$ADDON/config.yaml" ]; then
|
||||||
# path passed as argv, never interpolated into Python source
|
# 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
|
import yaml,sys
|
||||||
d=yaml.safe_load(open(sys.argv[1]))
|
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 {})))
|
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 {})]
|
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)
|
if missing: print(' %-13s options with no schema entry: %s' % ('WARN', missing)); sys.exit(0)
|
||||||
PY
|
PY
|
||||||
note "config.yaml" "FAIL parse"
|
|
||||||
fail=1
|
|
||||||
}
|
|
||||||
command -v yamllint > /dev/null 2>&1 && {
|
command -v yamllint > /dev/null 2>&1 && {
|
||||||
yl=$(yamllint -f parsable "$ADDON/config.yaml" 2>&1 | grep -c .)
|
yl=$(yamllint -f parsable "$ADDON/config.yaml" 2>&1 | grep -c .)
|
||||||
note "yamllint" "$yl finding(s) (compare with --vs-master)"
|
note "yamllint" "$yl finding(s) (compare with --vs-master)"
|
||||||
@@ -99,10 +79,7 @@ PY
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
while IFS= read -r f; do
|
while IFS= read -r f; do
|
||||||
python3 -m py_compile "$f" 2> /dev/null || {
|
python3 -m py_compile "$f" 2> /dev/null || { note "py_compile" "FAIL $f"; fail=1; }
|
||||||
note "py_compile" "FAIL $f"
|
|
||||||
fail=1
|
|
||||||
}
|
|
||||||
done < <(find "$ADDON" -type f -name '*.py' 2> /dev/null)
|
done < <(find "$ADDON" -type f -name '*.py' 2> /dev/null)
|
||||||
|
|
||||||
$VS_MASTER && command -v npx > /dev/null 2>&1 && [ -f "$ADDON/CHANGELOG.md" ] && {
|
$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"
|
note "CHANGELOG" "updated"
|
||||||
else
|
else
|
||||||
# This one IS gated: onpr_check-pr.yaml exits 1 without it.
|
# This one IS gated: onpr_check-pr.yaml exits 1 without it.
|
||||||
note "CHANGELOG" "NOT UPDATED for $ADDON — CI hard-gates this"
|
note "CHANGELOG" "NOT UPDATED for $ADDON — CI hard-gates this"; fail=1
|
||||||
fail=1
|
|
||||||
fi
|
fi
|
||||||
if git diff origin/master...HEAD -- "$ADDON/config.yaml" 2> /dev/null | grep -q '^+version:'; then
|
if git diff origin/master...HEAD -- "$ADDON/config.yaml" 2> /dev/null | grep -q '^+version:'; then
|
||||||
note "version" "bumped"
|
note "version" "bumped"
|
||||||
@@ -134,8 +110,7 @@ note "docker build" "NOT tested locally (dockerd unavailable) — CI is the only
|
|||||||
if $VS_MASTER; then
|
if $VS_MASTER; then
|
||||||
echo
|
echo
|
||||||
echo "== findings ADDED by this diff (pre-existing ones filtered out) =="
|
echo "== findings ADDED by this diff (pre-existing ones filtered out) =="
|
||||||
tmp=$(mktemp -d)
|
tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT
|
||||||
trap 'rm -rf "$tmp"' EXIT
|
|
||||||
added=0
|
added=0
|
||||||
# Fed by process substitution, not a pipe: a pipeline runs this in a subshell, where the
|
# 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.
|
# 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.
|
# cancel it out and report a false clean.
|
||||||
case "$f" in
|
case "$f" in
|
||||||
*.sh | *autostart | */run | */finish)
|
*.sh | *autostart | */run | */finish)
|
||||||
command -v shellcheck > /dev/null 2>&1 || {
|
command -v shellcheck > /dev/null 2>&1 || { echo " $f: SKIPPED (shellcheck not installed)"; continue; }
|
||||||
echo " $f: SKIPPED (shellcheck not installed)"
|
cmd() { shellcheck -x -f gcc "$1" 2>&1 | sed 's/^[^:]*:[0-9]*:[0-9]*://'; } ;;
|
||||||
continue
|
|
||||||
}
|
|
||||||
cmd() { shellcheck -x -f gcc "$1" 2>&1 | sed 's/^[^:]*:[0-9]*:[0-9]*://'; }
|
|
||||||
;;
|
|
||||||
*.yaml | *.yml)
|
*.yaml | *.yml)
|
||||||
command -v yamllint > /dev/null 2>&1 || {
|
command -v yamllint > /dev/null 2>&1 || { echo " $f: SKIPPED (yamllint not installed)"; continue; }
|
||||||
echo " $f: SKIPPED (yamllint not installed)"
|
cmd() { yamllint -f parsable "$1" 2>&1 | sed 's/^[^:]*//; s/^:[0-9]*:[0-9]*//'; } ;;
|
||||||
continue
|
|
||||||
}
|
|
||||||
cmd() { yamllint -f parsable "$1" 2>&1 | sed 's/^[^:]*//; s/^:[0-9]*:[0-9]*//'; }
|
|
||||||
;;
|
|
||||||
*Dockerfile)
|
*Dockerfile)
|
||||||
command -v hadolint > /dev/null 2>&1 || {
|
command -v hadolint > /dev/null 2>&1 || { echo " $f: SKIPPED (hadolint not installed)"; continue; }
|
||||||
echo " $f: SKIPPED (hadolint not installed)"
|
cmd() { hadolint "$1" 2>&1 | sed 's/^[^:]*//; s/^:[0-9]*//'; } ;;
|
||||||
continue
|
|
||||||
}
|
|
||||||
cmd() { hadolint "$1" 2>&1 | sed 's/^[^:]*//; s/^:[0-9]*//'; }
|
|
||||||
;;
|
|
||||||
*) continue ;;
|
*) continue ;;
|
||||||
esac
|
esac
|
||||||
b=$(cmd "$tmp/base" | sort)
|
b=$(cmd "$tmp/base" | sort)
|
||||||
@@ -178,8 +141,7 @@ if $VS_MASTER; then
|
|||||||
[ -n "$new" ] && {
|
[ -n "$new" ] && {
|
||||||
echo " $f: $(printf '%s\n' "$new" | grep -c .) NEW finding(s)"
|
echo " $f: $(printf '%s\n' "$new" | grep -c .) NEW finding(s)"
|
||||||
printf '%s\n' "$new" | sed 's/^/ /' | head -5
|
printf '%s\n' "$new" | sed 's/^/ /' | head -5
|
||||||
added=1
|
added=1; fail=1
|
||||||
fail=1
|
|
||||||
}
|
}
|
||||||
done < <(git diff --name-only origin/master...HEAD -- "$ADDON" 2> /dev/null)
|
done < <(git diff --name-only origin/master...HEAD -- "$ADDON" 2> /dev/null)
|
||||||
[ "$added" -eq 0 ] && echo " (none — this diff introduced no new lint findings)"
|
[ "$added" -eq 0 ] && echo " (none — this diff introduced no new lint findings)"
|
||||||
|
|||||||
10
.github/scripts/ai_triage_context.sh
vendored
10
.github/scripts/ai_triage_context.sh
vendored
@@ -28,10 +28,7 @@ if [ -n "$RAW" ]; then
|
|||||||
# Directory list without checking out any of them.
|
# Directory list without checking out any of them.
|
||||||
git ls-tree -d --name-only HEAD > "$OUT/dirs.txt"
|
git ls-tree -d --name-only HEAD > "$OUT/dirs.txt"
|
||||||
for guess in "$CAND" "${CAND//_/-}" "${CAND//_/.}"; do
|
for guess in "$CAND" "${CAND//_/-}" "${CAND//_/.}"; do
|
||||||
if grep -qxF "$guess" "$OUT/dirs.txt"; then
|
if grep -qxF "$guess" "$OUT/dirs.txt"; then ADDON="$guess"; break; fi
|
||||||
ADDON="$guess"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
# Separator-insensitive exact match: a title like "[Calibre-web]" (hyphen)
|
# Separator-insensitive exact match: a title like "[Calibre-web]" (hyphen)
|
||||||
# against a directory named calibre_web (underscore) matches neither exact
|
# against a directory named calibre_web (underscore) matches neither exact
|
||||||
@@ -41,10 +38,7 @@ if [ -n "$RAW" ]; then
|
|||||||
if [ -z "$ADDON" ]; then
|
if [ -z "$ADDON" ]; then
|
||||||
CAND_STRIPPED=$(tr -d '_.-' <<<"$CAND")
|
CAND_STRIPPED=$(tr -d '_.-' <<<"$CAND")
|
||||||
while IFS= read -r dir; do
|
while IFS= read -r dir; do
|
||||||
if [ "$(tr -d '_.-' <<< "$dir")" = "$CAND_STRIPPED" ]; then
|
if [ "$(tr -d '_.-' <<<"$dir")" = "$CAND_STRIPPED" ]; then ADDON="$dir"; break; fi
|
||||||
ADDON="$dir"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done < "$OUT/dirs.txt"
|
done < "$OUT/dirs.txt"
|
||||||
fi
|
fi
|
||||||
# Last resort: longest directory name contained in the candidate.
|
# Last resort: longest directory name contained in the candidate.
|
||||||
|
|||||||
2
.github/workflows/daily_ai_fix.yaml
vendored
2
.github/workflows/daily_ai_fix.yaml
vendored
@@ -125,7 +125,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Analyse and fix
|
- name: Analyse and fix
|
||||||
if: steps.batch.outputs.count != '0'
|
if: steps.batch.outputs.count != '0'
|
||||||
uses: anthropics/claude-code-action@a874e9ecd7bb36efdad65429c6b35815f5a08f10 # v1
|
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1
|
||||||
with:
|
with:
|
||||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
# Skip the OIDC -> Claude App token exchange. The scheduled path
|
# Skip the OIDC -> Claude App token exchange. The scheduled path
|
||||||
|
|||||||
2
.github/workflows/on_claude_mention.yml
vendored
2
.github/workflows/on_claude_mention.yml
vendored
@@ -64,7 +64,7 @@ jobs:
|
|||||||
fetch-depth: 1
|
fetch-depth: 1
|
||||||
|
|
||||||
- name: Run Claude Code
|
- name: Run Claude Code
|
||||||
uses: anthropics/claude-code-action@a874e9ecd7bb36efdad65429c6b35815f5a08f10 # v1
|
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1
|
||||||
with:
|
with:
|
||||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
# AI_PR_TOKEN, not GITHUB_TOKEN, so a PR Claude opens triggers CI.
|
# AI_PR_TOKEN, not GITHUB_TOKEN, so a PR Claude opens triggers CI.
|
||||||
|
|||||||
2
.github/workflows/on_issue_approved.yaml
vendored
2
.github/workflows/on_issue_approved.yaml
vendored
@@ -135,7 +135,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Execute the plan
|
- name: Execute the plan
|
||||||
if: steps.bundle.outputs.has_plan == 'true'
|
if: steps.bundle.outputs.has_plan == 'true'
|
||||||
uses: anthropics/claude-code-action@a874e9ecd7bb36efdad65429c6b35815f5a08f10 # v1
|
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1
|
||||||
with:
|
with:
|
||||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
# Skip the OIDC -> Claude App token exchange, which 401s whenever
|
# Skip the OIDC -> Claude App token exchange, which 401s whenever
|
||||||
|
|||||||
2
.github/workflows/on_issues_ai_triage.yaml
vendored
2
.github/workflows/on_issues_ai_triage.yaml
vendored
@@ -166,7 +166,7 @@ jobs:
|
|||||||
id: classify
|
id: classify
|
||||||
if: github.event_name != 'issue_comment' || steps.claim.outputs.go == 'true'
|
if: github.event_name != 'issue_comment' || steps.claim.outputs.go == 'true'
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
uses: anthropics/claude-code-action@a874e9ecd7bb36efdad65429c6b35815f5a08f10 # v1
|
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1
|
||||||
with:
|
with:
|
||||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
# Without this the action falls back to the OIDC -> Claude App token
|
# Without this the action falls back to the OIDC -> Claude App token
|
||||||
|
|||||||
2
.github/workflows/on_pr_coderabbit.yml
vendored
2
.github/workflows/on_pr_coderabbit.yml
vendored
@@ -79,7 +79,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Address CodeRabbit comments
|
- name: Address CodeRabbit comments
|
||||||
if: steps.claim.outputs.go == 'true'
|
if: steps.claim.outputs.go == 'true'
|
||||||
uses: anthropics/claude-code-action@a874e9ecd7bb36efdad65429c6b35815f5a08f10 # v1
|
uses: anthropics/claude-code-action@d75b94d5ad426cb8546e6628b6f5f19b84e5cce1 # v1
|
||||||
with:
|
with:
|
||||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
# Skip the OIDC -> Claude App token exchange, which 401s whenever
|
# Skip the OIDC -> Claude App token exchange, which 401s whenever
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ if ! bashio::supervisor.ping 2> /dev/null; then
|
|||||||
if [ ! -f /usr/bin/bashio ]; then
|
if [ ! -f /usr/bin/bashio ]; then
|
||||||
cp -rf /usr/local/lib/bashio-standalone.sh /usr/bin/bashio
|
cp -rf /usr/local/lib/bashio-standalone.sh /usr/bin/bashio
|
||||||
fi
|
fi
|
||||||
grep -rl "^#!.*bashio" /etc \
|
grep -rl "^#!.*bashio" /etc |
|
||||||
| while IFS= read -r f; do
|
while IFS= read -r f; do
|
||||||
grep -qF "source /usr/local/lib/bashio-standalone.sh" "$f" && continue
|
grep -qF "source /usr/local/lib/bashio-standalone.sh" "$f" && continue
|
||||||
sed -i '1a source /usr/local/lib/bashio-standalone.sh' "$f"
|
sed -i '1a source /usr/local/lib/bashio-standalone.sh' "$f"
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -152,8 +152,8 @@ if [[ "${1:-}" == "--self-test" ]]; then
|
|||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[[ "$self_test_rc" -eq 0 ]] \
|
[[ "$self_test_rc" -eq 0 ]] &&
|
||||||
&& echo "${#self_test_values[@]} values round-tripped unchanged (export block + dotenv)"
|
echo "${#self_test_values[@]} values round-tripped unchanged (export block + dotenv)"
|
||||||
exit "$self_test_rc"
|
exit "$self_test_rc"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -193,10 +193,7 @@ SECRETSOURCE=""
|
|||||||
|
|
||||||
resolve_secret() {
|
resolve_secret() {
|
||||||
local v="$1" name line
|
local v="$1" name line
|
||||||
[[ "$v" =~ ^[[:space:]]*\!secret[[:space:]]+(.+)$ ]] || {
|
[[ "$v" =~ ^[[:space:]]*\!secret[[:space:]]+(.+)$ ]] || { printf '%s' "$v"; return; }
|
||||||
printf '%s' "$v"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
name="${BASH_REMATCH[1]}"
|
name="${BASH_REMATCH[1]}"
|
||||||
[[ -n "$SECRETSOURCE" ]] || bashio::exit.nok "Secrets not mounted"
|
[[ -n "$SECRETSOURCE" ]] || bashio::exit.nok "Secrets not mounted"
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,8 @@ pick_exec_dir() {
|
|||||||
for d in /dev/shm /run /var/run /mnt /root /; do
|
for d in /dev/shm /run /var/run /mnt /root /; do
|
||||||
if [ -d "$d" ] && [ -w "$d" ]; then
|
if [ -d "$d" ] && [ -w "$d" ]; then
|
||||||
local t="${d%/}/.exec_test_$$"
|
local t="${d%/}/.exec_test_$$"
|
||||||
printf '#!/bin/sh\necho ok\n' > "$t" 2> /dev/null || {
|
printf '#!/bin/sh\necho ok\n' >"$t" 2>/dev/null || { rm -f "$t" 2>/dev/null || true; continue; }
|
||||||
rm -f "$t" 2> /dev/null || true
|
chmod 700 "$t" 2>/dev/null || { rm -f "$t" 2>/dev/null || true; continue; }
|
||||||
continue
|
|
||||||
}
|
|
||||||
chmod 700 "$t" 2> /dev/null || {
|
|
||||||
rm -f "$t" 2> /dev/null || true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if "$t" >/dev/null 2>&1; then
|
if "$t" >/dev/null 2>&1; then
|
||||||
rm -f "$t" 2>/dev/null || true
|
rm -f "$t" 2>/dev/null || true
|
||||||
echo "$d"
|
echo "$d"
|
||||||
|
|||||||
@@ -46,8 +46,7 @@ _bashio_color() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_bashio_log() {
|
_bashio_log() {
|
||||||
local c="${1:-}"
|
local c="${1:-}"; shift || true
|
||||||
shift || true
|
|
||||||
printf '%s%s%s\n' "$(_bashio_color "$c")" "$*" "$(_bashio_color reset)"
|
printf '%s%s%s\n' "$(_bashio_color "$c")" "$*" "$(_bashio_color reset)"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,10 +246,7 @@ bashio::info.supervisor() { printf '%s' "standalone"; }
|
|||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
bashio::config() {
|
bashio::config() {
|
||||||
local key="${1:-}"
|
local key="${1:-}"
|
||||||
[ -n "$key" ] || {
|
[ -n "$key" ] || { printf '%s' ""; return 0; }
|
||||||
printf '%s' ""
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
local v=""
|
local v=""
|
||||||
if _bashio_env_get "$key" >/dev/null 2>&1; then
|
if _bashio_env_get "$key" >/dev/null 2>&1; then
|
||||||
@@ -360,10 +356,7 @@ bashio::host.hostname() {
|
|||||||
# bashio::services.available "mqtt"
|
# bashio::services.available "mqtt"
|
||||||
bashio::services() {
|
bashio::services() {
|
||||||
local svc="${1:-}" key="${2:-}"
|
local svc="${1:-}" key="${2:-}"
|
||||||
[ -n "$svc" ] && [ -n "$key" ] || {
|
[ -n "$svc" ] && [ -n "$key" ] || { printf '%s' ""; return 0; }
|
||||||
printf '%s' ""
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
local upper svc_upper var v=""
|
local upper svc_upper var v=""
|
||||||
upper="$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')"
|
upper="$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')"
|
||||||
@@ -426,11 +419,7 @@ bashio::homeassistant.token() {
|
|||||||
# Exit helpers
|
# Exit helpers
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
bashio::exit.ok() { exit 0; }
|
bashio::exit.ok() { exit 0; }
|
||||||
bashio::exit.nok() {
|
bashio::exit.nok() { local m="${1:-}"; [ -n "$m" ] && bashio::log.red "$m"; exit 1; }
|
||||||
local m="${1:-}"
|
|
||||||
[ -n "$m" ] && bashio::log.red "$m"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Core config check shim
|
# Core config check shim
|
||||||
|
|||||||
@@ -28,14 +28,8 @@ pick_exec_dir() {
|
|||||||
if [ -d "$d" ] && [ -w "$d" ]; then
|
if [ -d "$d" ] && [ -w "$d" ]; then
|
||||||
# Create a tiny test executable to confirm "exec" works
|
# Create a tiny test executable to confirm "exec" works
|
||||||
local t="${d%/}/.exec_test_$$"
|
local t="${d%/}/.exec_test_$$"
|
||||||
printf '#!/bin/sh\necho ok\n' > "$t" 2> /dev/null || {
|
printf '#!/bin/sh\necho ok\n' >"$t" 2>/dev/null || { rm -f "$t" 2>/dev/null || true; continue; }
|
||||||
rm -f "$t" 2> /dev/null || true
|
chmod 700 "$t" 2>/dev/null || { rm -f "$t" 2>/dev/null || true; continue; }
|
||||||
continue
|
|
||||||
}
|
|
||||||
chmod 700 "$t" 2> /dev/null || {
|
|
||||||
rm -f "$t" 2> /dev/null || true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if "$t" >/dev/null 2>&1; then
|
if "$t" >/dev/null 2>&1; then
|
||||||
rm -f "$t" 2>/dev/null || true
|
rm -f "$t" 2>/dev/null || true
|
||||||
echo "$d"
|
echo "$d"
|
||||||
@@ -215,8 +209,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
|
# 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
|
# 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.
|
# 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" \
|
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
|
s6-dumpenv -- "$S6_CONTAINER_ENV.tmp" && mv "$S6_CONTAINER_ENV.tmp" "$S6_CONTAINER_ENV"; then
|
||||||
echo "Populated $S6_CONTAINER_ENV for with-contenv"
|
echo "Populated $S6_CONTAINER_ENV for with-contenv"
|
||||||
else
|
else
|
||||||
# Leaves the directory absent, which is exactly how this fails today -- so the failure mode is
|
# Leaves the directory absent, which is exactly how this fails today -- so the failure mode is
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ You can add the following tags in the file :
|
|||||||
|
|
||||||
### Addon version numbering
|
### 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:
|
The addon version is therefore derived from the upstream tag:
|
||||||
|
|
||||||
|
|||||||
0
bazarr/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
bazarr/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
bentopdf/rootfs/etc/s6-overlay/s6-rc.d/bentopdf/run
Executable file → Normal file
0
bentopdf/rootfs/etc/s6-overlay/s6-rc.d/bentopdf/run
Executable file → Normal file
@@ -1,3 +1,21 @@
|
|||||||
|
## 20260909.5 (09-09-2026)
|
||||||
|
- Minor bugs fixed
|
||||||
|
## 20260909.4 (09-09-2026)
|
||||||
|
- Minor bugs fixed
|
||||||
|
## 20260909.3 (09-09-2026)
|
||||||
|
- Minor bugs fixed
|
||||||
|
## 20260909.2 (09-09-2026)
|
||||||
|
- Minor bugs fixed
|
||||||
|
## 20260909 (09-09-2026)
|
||||||
|
- Minor bugs fixed
|
||||||
|
## 20260908.2 (08-09-2026)
|
||||||
|
- Minor bugs fixed
|
||||||
|
## 20260908.1 (08-09-2026)
|
||||||
|
- Synced with upstream birdnet-go (4 commits); re-merges the open fork PRs, adding fork PR #62 (reanalyze a clip with every loaded model + one-click correction)
|
||||||
|
## 20260908 (08-09-2026)
|
||||||
|
- Synced with upstream birdnet-go (7 commits); re-merges the open fork PRs
|
||||||
|
## 20260907 (07-09-2026)
|
||||||
|
- Rebuild: re-merges the open fork PRs, picking up the updated fork PR #57
|
||||||
## 20260901.4 (01-09-2026)
|
## 20260901.4 (01-09-2026)
|
||||||
- Minor bugs fixed
|
- Minor bugs fixed
|
||||||
## 20260901.3 (01-09-2026)
|
## 20260901.3 (01-09-2026)
|
||||||
|
|||||||
@@ -127,5 +127,5 @@ slug: birdnet-go-dev
|
|||||||
udev: true
|
udev: true
|
||||||
url: https://github.com/alexbelgium/hassio-addons
|
url: https://github.com/alexbelgium/hassio-addons
|
||||||
usb: true
|
usb: true
|
||||||
version: "20260901.4"
|
version: "20260909.5"
|
||||||
video: true
|
video: true
|
||||||
|
|||||||
@@ -11,6 +11,15 @@
|
|||||||
# stamping) is written to the directory given as $1 so the Docker build can
|
# stamping) is written to the directory given as $1 so the Docker build can
|
||||||
# compile it.
|
# compile it.
|
||||||
#
|
#
|
||||||
|
# With --check the script does not build anything: it performs the exact same
|
||||||
|
# merge sequence, skips (instead of failing on) every conflicting PR, and prints
|
||||||
|
# one "!!! CONFLICT pr=#N conflicts-with=... files=... " line per offender before
|
||||||
|
# exiting 2. Use it to find conflicts *before* a build burns on them. This is a
|
||||||
|
# different question from GitHub's `mergeable` field, which compares a PR against
|
||||||
|
# its own base ref - for a stacked PR that base is another feature branch (often
|
||||||
|
# stale, sometimes belonging to a closed PR), so GitHub can report CLEAN for a PR
|
||||||
|
# that does not merge onto main at all.
|
||||||
|
#
|
||||||
# Environment:
|
# Environment:
|
||||||
# BIRDNET_FORK owner/repo of the fork (default alexbelgium/birdnet-go)
|
# BIRDNET_FORK owner/repo of the fork (default alexbelgium/birdnet-go)
|
||||||
# BIRDNET_UPSTREAM owner/repo of the upstream (default tphakala/birdnet-go)
|
# BIRDNET_UPSTREAM owner/repo of the upstream (default tphakala/birdnet-go)
|
||||||
@@ -19,7 +28,26 @@
|
|||||||
#
|
#
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
TARGET_DIR="${1:?usage: merge-prs.sh <target-dir>}"
|
CHECK_ONLY="${MERGE_PRS_CHECK:-0}"
|
||||||
|
TARGET_DIR=""
|
||||||
|
while [ "$#" -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--check) CHECK_ONLY=1 ;;
|
||||||
|
-*) 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
|
||||||
|
# quietly change which operand counts.
|
||||||
|
if [ -n "${TARGET_DIR}" ]; then
|
||||||
|
echo "usage: merge-prs.sh [--check] <target-dir>" >&2
|
||||||
|
exit 64
|
||||||
|
fi
|
||||||
|
TARGET_DIR="$1"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
: "${TARGET_DIR:?usage: merge-prs.sh [--check] <target-dir>}"
|
||||||
|
|
||||||
FORK="${BIRDNET_FORK:-alexbelgium/birdnet-go}"
|
FORK="${BIRDNET_FORK:-alexbelgium/birdnet-go}"
|
||||||
UPSTREAM="${BIRDNET_UPSTREAM:-tphakala/birdnet-go}"
|
UPSTREAM="${BIRDNET_UPSTREAM:-tphakala/birdnet-go}"
|
||||||
@@ -33,6 +61,52 @@ GH_TOKEN="${GH_TOKEN:-${GITHUB_TOKEN:-}}"
|
|||||||
|
|
||||||
log() { echo ">>> $*"; }
|
log() { echo ">>> $*"; }
|
||||||
|
|
||||||
|
# Conflicting PRs collected in --check mode: "number|scope|files|title".
|
||||||
|
conflicting=()
|
||||||
|
|
||||||
|
LOCKFILE="frontend/package-lock.json"
|
||||||
|
|
||||||
|
# The single place that decides whether a conflicted merge is still acceptable.
|
||||||
|
# package-lock.json is generated content and stacked PRs can carry an older copy even when
|
||||||
|
# their source changes merge cleanly, so keep the lockfile already assembled on the base side
|
||||||
|
# — but only when it is the sole conflict. Any source conflict stays fatal.
|
||||||
|
# Returns 0 when it resolved and committed such a merge, 1 when the conflict is real.
|
||||||
|
# BOTH the real merge and the --check probe must go through here: when only the real merge
|
||||||
|
# applied the policy, the probe called a PR "conflicts-with=main" that the build would have
|
||||||
|
# merged fine, and printed the opposite remediation to the true one.
|
||||||
|
resolve_sole_lockfile() {
|
||||||
|
local dir="$1"
|
||||||
|
local -a conflicted
|
||||||
|
mapfile -t conflicted < <(git -C "${dir}" diff --name-only --diff-filter=U)
|
||||||
|
if [ "${#conflicted[@]}" -ne 1 ] || [ "${conflicted[0]}" != "${LOCKFILE}" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
log "Resolving generated ${LOCKFILE} conflict using the base tree"
|
||||||
|
git -C "${dir}" checkout --ours -- "${LOCKFILE}" || return 1
|
||||||
|
git -C "${dir}" add "${LOCKFILE}" || return 1
|
||||||
|
git -C "${dir}" commit --no-edit > /dev/null || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Does ${1} merge cleanly onto the pristine upstream-synced main? Probed in a
|
||||||
|
# throwaway worktree so the accumulated tree is left untouched. Tells apart a PR
|
||||||
|
# that is simply stale against main (fixable inside that PR's own branch) from
|
||||||
|
# one that only clashes with another open PR (needs a cross-PR decision).
|
||||||
|
merges_onto_main() {
|
||||||
|
local sha="$1" tmpdir probe rc=0
|
||||||
|
tmpdir="$(mktemp -d)"
|
||||||
|
probe="${tmpdir}/probe"
|
||||||
|
git worktree add --quiet --detach "${probe}" "${MAIN_SYNCED}"
|
||||||
|
if ! git -C "${probe}" merge --no-edit --no-ff -m probe "${sha}" > /dev/null 2>&1; then
|
||||||
|
# Same policy as the real merge, or this misclassifies a lockfile-only clash.
|
||||||
|
resolve_sole_lockfile "${probe}" > /dev/null 2>&1 || rc=1
|
||||||
|
fi
|
||||||
|
git worktree remove --force "${probe}" > /dev/null 2>&1 || true
|
||||||
|
# worktree remove only takes the child back; without this the mktemp parent is left behind
|
||||||
|
# on every checked conflict.
|
||||||
|
rmdir "${tmpdir}" > /dev/null 2>&1 || true
|
||||||
|
return "${rc}"
|
||||||
|
}
|
||||||
|
|
||||||
git config --global user.email "addon-builder@users.noreply.github.com"
|
git config --global user.email "addon-builder@users.noreply.github.com"
|
||||||
git config --global user.name "BirdNET-Go Addon Builder"
|
git config --global user.name "BirdNET-Go Addon Builder"
|
||||||
git config --global advice.detachedHead false
|
git config --global advice.detachedHead false
|
||||||
@@ -47,6 +121,7 @@ git remote add upstream "${UPSTREAM_URL}"
|
|||||||
git fetch --no-tags upstream main
|
git fetch --no-tags upstream main
|
||||||
# --no-ff keeps an explicit sync commit; a no-op when main is already current.
|
# --no-ff keeps an explicit sync commit; a no-op when main is already current.
|
||||||
git merge --no-edit --no-ff upstream/main
|
git merge --no-edit --no-ff upstream/main
|
||||||
|
MAIN_SYNCED="$(git rev-parse HEAD)"
|
||||||
|
|
||||||
log "Querying open non-draft PRs from ${FORK}"
|
log "Querying open non-draft PRs from ${FORK}"
|
||||||
auth_header=()
|
auth_header=()
|
||||||
@@ -79,27 +154,43 @@ for entry in "${prs[@]}"; do
|
|||||||
if ! git merge --no-edit --no-ff -m "Merge PR #${number}: ${title}" "${sha}"; then
|
if ! git merge --no-edit --no-ff -m "Merge PR #${number}: ${title}" "${sha}"; then
|
||||||
mapfile -t conflicted_files < <(git diff --name-only --diff-filter=U)
|
mapfile -t conflicted_files < <(git diff --name-only --diff-filter=U)
|
||||||
|
|
||||||
# package-lock.json is generated content and stacked PRs can carry an
|
if resolve_sole_lockfile .; then
|
||||||
# older copy even when their source changes merge cleanly. Keep the
|
: # generated lockfile only - the merge is committed and the build continues
|
||||||
# lockfile already assembled from upstream and earlier PRs, but only
|
|
||||||
# when it is the sole conflict. Any source conflict remains fatal.
|
|
||||||
if [ "${#conflicted_files[@]}" -eq 1 ] \
|
|
||||||
&& [ "${conflicted_files[0]}" = "frontend/package-lock.json" ]; then
|
|
||||||
log "Resolving generated frontend/package-lock.json conflict using the accumulated tree"
|
|
||||||
git checkout --ours -- frontend/package-lock.json
|
|
||||||
git add frontend/package-lock.json
|
|
||||||
git commit --no-edit
|
|
||||||
else
|
else
|
||||||
echo "!!! Merge conflict while merging PR #${number} (${title})." >&2
|
echo "!!! Merge conflict while merging PR #${number} (${title})." >&2
|
||||||
if [ "${#conflicted_files[@]}" -gt 0 ]; then
|
if [ "${#conflicted_files[@]}" -gt 0 ]; then
|
||||||
printf '!!! Conflicting file: %s\n' "${conflicted_files[@]}" >&2
|
printf '!!! Conflicting file: %s\n' "${conflicted_files[@]}" >&2
|
||||||
fi
|
fi
|
||||||
echo "!!! Resolve the conflict in the fork or pause this PR, then rebuild." >&2
|
|
||||||
git merge --abort || true
|
git merge --abort || true
|
||||||
|
|
||||||
|
if [ "${CHECK_ONLY}" = "1" ]; then
|
||||||
|
scope="accumulated"
|
||||||
|
merges_onto_main "${sha}" || scope="main"
|
||||||
|
conflicting+=("${number}|${scope}|${conflicted_files[*]:-}|${title}")
|
||||||
|
log "check mode: skipping PR #${number}, continuing with the rest"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "!!! Resolve the conflict in the fork or pause this PR, then rebuild." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if [ "${CHECK_ONLY}" = "1" ]; then
|
||||||
|
if [ "${#conflicting[@]}" -eq 0 ]; then
|
||||||
|
log "CHECK OK: every open non-draft PR merges into the combined build tree"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "!!! CHECK FAILED: ${#conflicting[@]} PR(s) would break the add-on build" >&2
|
||||||
|
for entry in "${conflicting[@]}"; do
|
||||||
|
IFS='|' read -r number scope files title <<<"${entry}"
|
||||||
|
echo "!!! CONFLICT pr=#${number} conflicts-with=${scope} files=${files} title=${title}" >&2
|
||||||
|
done
|
||||||
|
echo "!!! conflicts-with=main -> the PR is stale against main; merge main into its branch and resolve there." >&2
|
||||||
|
echo "!!! conflicts-with=accumulated -> the PR only clashes with another open PR; decide which one owns the hunk." >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
log "Merged HEAD: $(git rev-parse --short HEAD)"
|
log "Merged HEAD: $(git rev-parse --short HEAD)"
|
||||||
log "Source tree ready at ${TARGET_DIR}"
|
log "Source tree ready at ${TARGET_DIR}"
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ Here are some example tests I did (the whole threads are really interesting also
|
|||||||
|
|
||||||
**My recommendation:**
|
**My recommendation:**
|
||||||
|
|
||||||
- **Best entry system (< 50 €):** Boya By-lm40 (30 €) + deadcat (10 €)
|
- **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 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 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:**
|
**Sources for high end microphones in Europe:**
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,6 @@ def automatic_mqtt_publish(file, detection, path):
|
|||||||
mqttc.publish(mqtt_topic, json_bird, 1)
|
mqttc.publish(mqtt_topic, json_bird, 1)
|
||||||
log.info("Posted to MQTT: ok")
|
log.info("Posted to MQTT: ok")
|
||||||
|
|
||||||
|
|
||||||
# Create MQTT client using legacy callback API when available for
|
# Create MQTT client using legacy callback API when available for
|
||||||
# compatibility with paho-mqtt >= 2.0
|
# compatibility with paho-mqtt >= 2.0
|
||||||
callback_api = getattr(mqtt, "CallbackAPIVersion", None)
|
callback_api = getattr(mqtt, "CallbackAPIVersion", None)
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ Here are some example tests I did (the whole threads are really interesting also
|
|||||||
|
|
||||||
**My recommendation:**
|
**My recommendation:**
|
||||||
|
|
||||||
- **Best entry system (< 50 €):** Boya By-lm40 (30 €) + deadcat (10 €)
|
- **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 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 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:**
|
**Sources for high end microphones in Europe:**
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,6 @@ def automatic_mqtt_publish(file, detection, path):
|
|||||||
mqttc.publish(mqtt_topic, json_bird, 1)
|
mqttc.publish(mqtt_topic, json_bird, 1)
|
||||||
log.info("Posted to MQTT: ok")
|
log.info("Posted to MQTT: ok")
|
||||||
|
|
||||||
|
|
||||||
# Create MQTT client using legacy callback API when available for
|
# Create MQTT client using legacy callback API when available for
|
||||||
# compatibility with paho-mqtt >= 2.0
|
# compatibility with paho-mqtt >= 2.0
|
||||||
callback_api = getattr(mqtt, "CallbackAPIVersion", None)
|
callback_api = getattr(mqtt, "CallbackAPIVersion", None)
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ map:
|
|||||||
name: BirdNET-PiPy
|
name: BirdNET-PiPy
|
||||||
options:
|
options:
|
||||||
env_vars: []
|
env_vars: []
|
||||||
ICECAST_PASSWORD: ""
|
ICECAST_PASSWORD: ''
|
||||||
data_location: /config/data
|
data_location: /config/data
|
||||||
panel_icon: mdi:bird
|
panel_icon: mdi:bird
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
0
birdnet-pipy/rootfs/etc/services.d/api/run
Executable file → Normal file
0
birdnet-pipy/rootfs/etc/services.d/api/run
Executable file → Normal file
0
birdnet-pipy/rootfs/etc/services.d/icecast/run
Executable file → Normal file
0
birdnet-pipy/rootfs/etc/services.d/icecast/run
Executable file → Normal file
0
birdnet-pipy/rootfs/etc/services.d/main/run
Executable file → Normal file
0
birdnet-pipy/rootfs/etc/services.d/main/run
Executable file → Normal file
0
birdnet-pipy/rootfs/etc/services.d/model/run
Executable file → Normal file
0
birdnet-pipy/rootfs/etc/services.d/model/run
Executable file → Normal file
0
birdnet-pipy/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
birdnet-pipy/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
bitwarden/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/run
Executable file → Normal file
0
bitwarden/rootfs/etc/s6-overlay/s6-rc.d/init-nginx/run
Executable file → Normal file
0
bitwarden/rootfs/etc/s6-overlay/s6-rc.d/nginx/run
Executable file → Normal file
0
bitwarden/rootfs/etc/s6-overlay/s6-rc.d/nginx/run
Executable file → Normal file
0
bitwarden/rootfs/etc/s6-overlay/s6-rc.d/vaultwarden/run
Executable file → Normal file
0
bitwarden/rootfs/etc/s6-overlay/s6-rc.d/vaultwarden/run
Executable file → Normal file
1
browser_chromium/rootfs/etc/cont-init.d/20-folders.sh
Normal file → Executable file
1
browser_chromium/rootfs/etc/cont-init.d/20-folders.sh
Normal file → Executable file
@@ -7,6 +7,7 @@ set -e
|
|||||||
PUID=$(bashio::config "PUID")
|
PUID=$(bashio::config "PUID")
|
||||||
PGID=$(bashio::config "PGID")
|
PGID=$(bashio::config "PGID")
|
||||||
|
|
||||||
|
|
||||||
# Create cache
|
# Create cache
|
||||||
#mkdir -p /.cache
|
#mkdir -p /.cache
|
||||||
#chmod 755 /.cache
|
#chmod 755 /.cache
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ This addon supports mounting both local drives and remote SMB shares:
|
|||||||
|
|
||||||
### Optional Calibre-Web features
|
### 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`).
|
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`).
|
||||||
|
|
||||||
|
|||||||
@@ -30,16 +30,16 @@ else
|
|||||||
# duplicates it can leave behind are entries calibre-web skips or already trusts.
|
# 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
|
# 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.
|
# 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) \
|
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})"
|
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
|
# 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
|
# 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
|
# 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.
|
# 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.
|
# 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) \
|
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})"
|
bashio::log.warning "Could not reset the kepubify path, it will be applied at next start (${kepubify_error})"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
bashio::log.info "Default username:password is admin:admin123"
|
bashio::log.info "Default username:password is admin:admin123"
|
||||||
|
|||||||
0
changedetection.io/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
changedetection.io/rootfs/etc/services.d/nginx/run
Executable file → Normal file
@@ -338,7 +338,8 @@ ln -sfn "$CODEX_BIN" "$CODEX_LINK"
|
|||||||
CODEX_SANDBOX_MODE="$(bashio::config 'codex_sandbox_mode' 'danger-full-access')"
|
CODEX_SANDBOX_MODE="$(bashio::config 'codex_sandbox_mode' 'danger-full-access')"
|
||||||
run_as_runtime_user mkdir -p "$RUNTIME_HOME/.codex"
|
run_as_runtime_user mkdir -p "$RUNTIME_HOME/.codex"
|
||||||
CODEX_SANDBOX_MODE="$CODEX_SANDBOX_MODE" RUNTIME_HOME="$RUNTIME_HOME" \
|
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 os
|
||||||
import re
|
import re
|
||||||
import tomllib
|
import tomllib
|
||||||
|
|||||||
0
claude_desktop/rootfs/usr/local/bin/codex-login
Normal file → Executable file
0
claude_desktop/rootfs/usr/local/bin/codex-login
Normal file → Executable file
12
claude_desktop/rootfs/usr/local/bin/ha-cli
Normal file → Executable file
12
claude_desktop/rootfs/usr/local/bin/ha-cli
Normal file → Executable file
@@ -133,9 +133,7 @@ def rest(method, base, token, path, body=None):
|
|||||||
if body is not None:
|
if body is not None:
|
||||||
data = json.dumps(body).encode("utf-8")
|
data = json.dumps(body).encode("utf-8")
|
||||||
headers["Content-Type"] = "application/json"
|
headers["Content-Type"] = "application/json"
|
||||||
req = urllib.request.Request(
|
req = urllib.request.Request(_url(base, path), data=data, method=method, headers=headers)
|
||||||
_url(base, path), data=data, method=method, headers=headers
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
with urllib.request.urlopen(req, timeout=30) as resp:
|
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||||
text = resp.read().decode("utf-8")
|
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()
|
detail = exc.read().decode("utf-8", "replace").strip()
|
||||||
sys.exit(f"ha-cli: HTTP {exc.code} {exc.reason} on {method} {path}\n{detail}")
|
sys.exit(f"ha-cli: HTTP {exc.code} {exc.reason} on {method} {path}\n{detail}")
|
||||||
except urllib.error.URLError as exc:
|
except urllib.error.URLError as exc:
|
||||||
sys.exit(
|
sys.exit(f"ha-cli: cannot reach Home Assistant ({exc.reason}) on {method} {path}")
|
||||||
f"ha-cli: cannot reach Home Assistant ({exc.reason}) on {method} {path}"
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
return json.loads(text) if text.strip() else None
|
return json.loads(text) if text.strip() else None
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@@ -218,9 +214,7 @@ def main(argv):
|
|||||||
sys.exit("usage: ha-cli call <domain.service> [BODY]")
|
sys.exit("usage: ha-cli call <domain.service> [BODY]")
|
||||||
domain, service = args[0].split(".", 1)
|
domain, service = args[0].split(".", 1)
|
||||||
body = _read_body(args[1]) if len(args) > 1 else None
|
body = _read_body(args[1]) if len(args) > 1 else None
|
||||||
_print(
|
_print(rest("POST", rest_base, token, f"services/{domain}/{service}", body or {}))
|
||||||
rest("POST", rest_base, token, f"services/{domain}/{service}", body or {})
|
|
||||||
)
|
|
||||||
elif cmd == "states":
|
elif cmd == "states":
|
||||||
path = f"states/{args[0]}" if args else "states"
|
path = f"states/{args[0]}" if args else "states"
|
||||||
_print(rest("GET", rest_base, token, path))
|
_print(rest("GET", rest_base, token, path))
|
||||||
|
|||||||
14
claude_desktop/rootfs/usr/local/bin/headroom-posttooluse-compress.py
Normal file → Executable file
14
claude_desktop/rootfs/usr/local/bin/headroom-posttooluse-compress.py
Normal file → Executable file
@@ -76,11 +76,7 @@ def main() -> int:
|
|||||||
|
|
||||||
# Find big string/array fields before paying the headroom import cost.
|
# Find big string/array fields before paying the headroom import cost.
|
||||||
def is_string_array(value):
|
def is_string_array(value):
|
||||||
return (
|
return isinstance(value, list) and len(value) > ARRAY_KEEP and all(isinstance(v, str) for v in value)
|
||||||
isinstance(value, list)
|
|
||||||
and len(value) > ARRAY_KEEP
|
|
||||||
and all(isinstance(v, str) for v in value)
|
|
||||||
)
|
|
||||||
|
|
||||||
if isinstance(response, str):
|
if isinstance(response, str):
|
||||||
string_candidates = ["__whole__"] if len(response) >= MIN_CHARS else []
|
string_candidates = ["__whole__"] if len(response) >= MIN_CHARS else []
|
||||||
@@ -89,14 +85,10 @@ def main() -> int:
|
|||||||
string_candidates = [
|
string_candidates = [
|
||||||
key
|
key
|
||||||
for key, value in response.items()
|
for key, value in response.items()
|
||||||
if key not in SKIP_KEYS
|
if key not in SKIP_KEYS and isinstance(value, str) and len(value) >= MIN_CHARS
|
||||||
and isinstance(value, str)
|
|
||||||
and len(value) >= MIN_CHARS
|
|
||||||
]
|
]
|
||||||
array_candidates = [
|
array_candidates = [
|
||||||
key
|
key for key, value in response.items() if key not in SKIP_KEYS and is_string_array(value)
|
||||||
for key, value in response.items()
|
|
||||||
if key not in SKIP_KEYS and is_string_array(value)
|
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
string_candidates = []
|
string_candidates = []
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
arch:
|
arch:
|
||||||
- aarch64
|
- aarch64
|
||||||
- amd64
|
- 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:
|
devices:
|
||||||
- /dev/dri
|
- /dev/dri
|
||||||
- /dev/dri/card0
|
- /dev/dri/card0
|
||||||
|
|||||||
0
comicarr/rootfs/etc/services.d/comicarr/run
Executable file → Normal file
0
comicarr/rootfs/etc/services.d/comicarr/run
Executable file → Normal file
0
comicarr/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
comicarr/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
emby/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
emby/rootfs/etc/services.d/nginx/run
Executable file → Normal file
@@ -4,17 +4,9 @@ set -e
|
|||||||
|
|
||||||
# Source environment variables for cron context
|
# Source environment variables for cron context
|
||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
if [ -f /etc/environment ]; then
|
if [ -f /etc/environment ]; then set -a; . /etc/environment; set +a; fi
|
||||||
set -a
|
|
||||||
. /etc/environment
|
|
||||||
set +a
|
|
||||||
fi
|
|
||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
if [ -f /.env ]; then
|
if [ -f /.env ]; then set -a; . /.env; set +a; fi
|
||||||
set -a
|
|
||||||
. /.env
|
|
||||||
set +a
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Use persisted value instead of calling bashio::config (www-data may lack API access)
|
# Use persisted value instead of calling bashio::config (www-data may lack API access)
|
||||||
CONFIGSOURCE="${CONFIG_LOCATION}"
|
CONFIGSOURCE="${CONFIG_LOCATION}"
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
# Complete option reference:
|
# Complete option reference:
|
||||||
# https://github.com/P-Adamiec/Free-Games-Claimer-Remaster#configuration
|
# https://github.com/P-Adamiec/Free-Games-Claimer-Remaster#configuration
|
||||||
|
|
||||||
HEIGHT=720
|
|
||||||
LOGIN_TIMEOUT=180
|
|
||||||
NOVNC_PORT=6080
|
|
||||||
# Browser and noVNC
|
# Browser and noVNC
|
||||||
SHOW=1
|
SHOW=1
|
||||||
TIMEOUT=60
|
|
||||||
VNC_LOGIN_TIMEOUT=180
|
|
||||||
WIDTH=1280
|
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.
|
# Public address used in notification links when behind a reverse proxy.
|
||||||
# VNC_URL=https://fgc.example.tld
|
# VNC_URL=https://fgc.example.tld
|
||||||
|
|
||||||
|
|||||||
@@ -47,10 +47,8 @@ def normalize_timestamp(value: Any) -> str:
|
|||||||
return parsed.isoformat(sep=" ", timespec="seconds")
|
return parsed.isoformat(sep=" ", timespec="seconds")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
return (
|
return datetime.now(timezone.utc).replace(tzinfo=None).isoformat(
|
||||||
datetime.now(timezone.utc)
|
sep=" ", timespec="seconds"
|
||||||
.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:
|
def ensure_schema(connection: sqlite3.Connection) -> None:
|
||||||
connection.executescript("""
|
connection.executescript(
|
||||||
|
"""
|
||||||
CREATE TABLE IF NOT EXISTS claimed_games (
|
CREATE TABLE IF NOT EXISTS claimed_games (
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
store VARCHAR(32) NOT NULL,
|
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_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_user ON claimed_games (user);
|
||||||
CREATE INDEX IF NOT EXISTS ix_claimed_games_game_id ON claimed_games (game_id);
|
CREATE INDEX IF NOT EXISTS ix_claimed_games_game_id ON claimed_games (game_id);
|
||||||
""")
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def migrate() -> int:
|
def migrate() -> int:
|
||||||
@@ -209,12 +209,7 @@ def migrate() -> int:
|
|||||||
|
|
||||||
connection.commit()
|
connection.commit()
|
||||||
log(f"Imported {source_imported} record(s) from {source}")
|
log(f"Imported {source_imported} record(s) from {source}")
|
||||||
except (
|
except (OSError, ValueError, json.JSONDecodeError, sqlite3.Error) as err:
|
||||||
OSError,
|
|
||||||
ValueError,
|
|
||||||
json.JSONDecodeError,
|
|
||||||
sqlite3.Error,
|
|
||||||
) as err:
|
|
||||||
connection.rollback()
|
connection.rollback()
|
||||||
message = f"Failed to import {source}: {err}"
|
message = f"Failed to import {source}: {err}"
|
||||||
errors.append(message)
|
errors.append(message)
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ arch:
|
|||||||
- amd64
|
- amd64
|
||||||
backup_exclude:
|
backup_exclude:
|
||||||
- "**/machine-learning/*"
|
- "**/machine-learning/*"
|
||||||
description: Self-hosted photo and video backup solution directly from your mobile phone
|
description:
|
||||||
|
Self-hosted photo and video backup solution directly from your mobile phone
|
||||||
devices:
|
devices:
|
||||||
- /dev/dri
|
- /dev/dri
|
||||||
- /dev/dxg
|
- /dev/dxg
|
||||||
|
|||||||
@@ -121,10 +121,7 @@ ACCOUNT_SCHEMA_OPTS="Albums ExcludedAlbums People Tags ShowFavorites ShowMemorie
|
|||||||
|
|
||||||
for opt in $GENERAL_SCHEMA_OPTS; do
|
for opt in $GENERAL_SCHEMA_OPTS; do
|
||||||
if config_has ".$opt"; then
|
if config_has ".$opt"; then
|
||||||
$GENERAL_STARTED || {
|
$GENERAL_STARTED || { echo "General:"; GENERAL_STARTED=true; }
|
||||||
echo "General:"
|
|
||||||
GENERAL_STARTED=true
|
|
||||||
}
|
|
||||||
yaml_kv " " "$opt" "$(config_val ".$opt")"
|
yaml_kv " " "$opt" "$(config_val ".$opt")"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -132,10 +129,7 @@ ACCOUNT_SCHEMA_OPTS="Albums ExcludedAlbums People Tags ShowFavorites ShowMemorie
|
|||||||
# Add general env_vars (skip if already set via schema option)
|
# Add general env_vars (skip if already set via schema option)
|
||||||
for key in "${!GENERAL_ENVS[@]}"; do
|
for key in "${!GENERAL_ENVS[@]}"; do
|
||||||
if ! config_has ".$key"; then
|
if ! config_has ".$key"; then
|
||||||
$GENERAL_STARTED || {
|
$GENERAL_STARTED || { echo "General:"; GENERAL_STARTED=true; }
|
||||||
echo "General:"
|
|
||||||
GENERAL_STARTED=true
|
|
||||||
}
|
|
||||||
yaml_kv " " "$key" "${GENERAL_ENVS[$key]}"
|
yaml_kv " " "$key" "${GENERAL_ENVS[$key]}"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ arch:
|
|||||||
- amd64
|
- amd64
|
||||||
backup_exclude:
|
backup_exclude:
|
||||||
- "**/machine-learning/*"
|
- "**/machine-learning/*"
|
||||||
description: Self-hosted photo and video backup solution directly from your mobile phone
|
description:
|
||||||
|
Self-hosted photo and video backup solution directly from your mobile phone
|
||||||
devices:
|
devices:
|
||||||
- /dev/dri
|
- /dev/dri
|
||||||
- /dev/dxg
|
- /dev/dxg
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ devices:
|
|||||||
- /dev/nvme1
|
- /dev/nvme1
|
||||||
- /dev/nvme2
|
- /dev/nvme2
|
||||||
environment:
|
environment:
|
||||||
ATTACHED_DEVICES_PERMS: "/dev/dri /dev/dvb /dev/vchiq /dev/vc-mem /dev/video1? -type c -o -type f"
|
ATTACHED_DEVICES_PERMS: '/dev/dri /dev/dvb /dev/vchiq /dev/vc-mem /dev/video1? -type c -o -type f'
|
||||||
host_dbus: true
|
host_dbus: true
|
||||||
host_network: true
|
host_network: true
|
||||||
image: ghcr.io/alexbelgium/jellyfin-{arch}
|
image: ghcr.io/alexbelgium/jellyfin-{arch}
|
||||||
|
|||||||
0
jellyfin/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
jellyfin/rootfs/etc/services.d/nginx/run
Executable file → Normal file
@@ -60,10 +60,7 @@ unlock_postgres_migrations() {
|
|||||||
local has_table
|
local has_table
|
||||||
has_table="$(psql -h "$POSTGRES_HOST" -p "$pg_port" -U "$POSTGRES_USER" -d "$POSTGRES_DATABASE" -Atqc \
|
has_table="$(psql -h "$POSTGRES_HOST" -p "$pg_port" -U "$POSTGRES_USER" -d "$POSTGRES_DATABASE" -Atqc \
|
||||||
"SELECT 1 FROM information_schema.tables WHERE table_name='knex_migrations_lock' LIMIT 1;" 2>/dev/null || true)"
|
"SELECT 1 FROM information_schema.tables WHERE table_name='knex_migrations_lock' LIMIT 1;" 2>/dev/null || true)"
|
||||||
[[ "$has_table" == "1" ]] || {
|
[[ "$has_table" == "1" ]] || { unset PGPASSWORD; return 0; }
|
||||||
unset PGPASSWORD
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# Ensure row exists
|
# Ensure row exists
|
||||||
psql -h "$POSTGRES_HOST" -p "$pg_port" -U "$POSTGRES_USER" -d "$POSTGRES_DATABASE" -Atqc \
|
psql -h "$POSTGRES_HOST" -p "$pg_port" -U "$POSTGRES_USER" -d "$POSTGRES_DATABASE" -Atqc \
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
arch:
|
arch:
|
||||||
- aarch64
|
- aarch64
|
||||||
- amd64
|
- amd64
|
||||||
description: Rule-based media cleanup tool for Plex, Jellyfin and Emby. Creates collections and optionally deletes unwatched content.
|
description:
|
||||||
|
Rule-based media cleanup tool for Plex, Jellyfin and Emby. Creates collections and optionally deletes unwatched content.
|
||||||
devices:
|
devices:
|
||||||
- /dev/dri
|
- /dev/dri
|
||||||
- /dev/dri/card0
|
- /dev/dri/card0
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ chmod 600 /addon_configs/<new_slug>/secret_key_base
|
|||||||
|
|
||||||
Replace `<old_slug>` and `<new_slug>` with the actual directory names (e.g. `db21ed7f_manyfold` and `088d77ac_manyfold_solo`). List them with `ls /addon_configs/`.
|
Replace `<old_slug>` and `<new_slug>` with the actual directory names (e.g. `db21ed7f_manyfold` and `088d77ac_manyfold_solo`). List them with `ls /addon_configs/`.
|
||||||
|
|
||||||
1. Start the new addon — it will pick up the existing database and secret automatically.
|
3. Start the new addon — it will pick up the existing database and secret automatically.
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|||||||
0
manyfold/rootfs/etc/s6-overlay/s6-rc.d/manyfold/finish
Normal file → Executable file
0
manyfold/rootfs/etc/s6-overlay/s6-rc.d/manyfold/finish
Normal file → Executable file
@@ -194,7 +194,8 @@ start_manyfold() {
|
|||||||
/usr/local/bin/docker-entrypoint.sh \
|
/usr/local/bin/docker-entrypoint.sh \
|
||||||
/usr/local/bin/docker-entrypoint \
|
/usr/local/bin/docker-entrypoint \
|
||||||
/docker-entrypoint.sh \
|
/docker-entrypoint.sh \
|
||||||
/entrypoint.sh; do
|
/entrypoint.sh
|
||||||
|
do
|
||||||
if [[ -x "$candidate" ]]; then
|
if [[ -x "$candidate" ]]; then
|
||||||
log "Starting Manyfold via ${candidate}"
|
log "Starting Manyfold via ${candidate}"
|
||||||
if [[ "$candidate" == *docker-entrypoint* ]]; then
|
if [[ "$candidate" == *docker-entrypoint* ]]; then
|
||||||
@@ -227,34 +228,20 @@ start_manyfold() {
|
|||||||
|
|
||||||
[[ -f "$OPTIONS_JSON" ]] || die "Missing options file at ${OPTIONS_JSON}"
|
[[ -f "$OPTIONS_JSON" ]] || die "Missing options file at ${OPTIONS_JSON}"
|
||||||
|
|
||||||
PUID="$(read_opt puid)"
|
PUID="$(read_opt puid)"; PUID="${PUID:-1000}"
|
||||||
PUID="${PUID:-1000}"
|
PGID="$(read_opt pgid)"; PGID="${PGID:-1000}"
|
||||||
PGID="$(read_opt pgid)"
|
MULTIUSER="$(read_opt multiuser)"; MULTIUSER="${MULTIUSER:-true}"
|
||||||
PGID="${PGID:-1000}"
|
LIBRARY_PATH_RAW="$(read_opt library_path)"; LIBRARY_PATH_RAW="${LIBRARY_PATH_RAW:-$DEFAULT_LIBRARY_PATH}"
|
||||||
MULTIUSER="$(read_opt multiuser)"
|
THUMBNAILS_PATH_RAW="$(read_opt thumbnails_path)"; THUMBNAILS_PATH_RAW="${THUMBNAILS_PATH_RAW:-$DEFAULT_THUMBNAILS_PATH}"
|
||||||
MULTIUSER="${MULTIUSER:-true}"
|
LOG_LEVEL="$(read_opt log_level)"; LOG_LEVEL="${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}"
|
||||||
LIBRARY_PATH_RAW="$(read_opt library_path)"
|
WEB_CONCURRENCY="$(read_opt web_concurrency)"; WEB_CONCURRENCY="${WEB_CONCURRENCY:-$DEFAULT_WEB_CONCURRENCY}"
|
||||||
LIBRARY_PATH_RAW="${LIBRARY_PATH_RAW:-$DEFAULT_LIBRARY_PATH}"
|
RAILS_MAX_THREADS="$(read_opt rails_max_threads)"; RAILS_MAX_THREADS="${RAILS_MAX_THREADS:-$DEFAULT_RAILS_MAX_THREADS}"
|
||||||
THUMBNAILS_PATH_RAW="$(read_opt thumbnails_path)"
|
DEFAULT_WORKER_CONCURRENCY="$(read_opt default_worker_concurrency)"; DEFAULT_WORKER_CONCURRENCY="${DEFAULT_WORKER_CONCURRENCY:-$DEFAULT_DEFAULT_WORKER_CONCURRENCY}"
|
||||||
THUMBNAILS_PATH_RAW="${THUMBNAILS_PATH_RAW:-$DEFAULT_THUMBNAILS_PATH}"
|
PERFORMANCE_WORKER_CONCURRENCY="$(read_opt performance_worker_concurrency)"; PERFORMANCE_WORKER_CONCURRENCY="${PERFORMANCE_WORKER_CONCURRENCY:-$DEFAULT_PERFORMANCE_WORKER_CONCURRENCY}"
|
||||||
LOG_LEVEL="$(read_opt log_level)"
|
MAX_FILE_UPLOAD_SIZE="$(read_opt max_file_upload_size)"; MAX_FILE_UPLOAD_SIZE="${MAX_FILE_UPLOAD_SIZE:-$DEFAULT_MAX_FILE_UPLOAD_SIZE}"
|
||||||
LOG_LEVEL="${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}"
|
MAX_FILE_EXTRACT_SIZE="$(read_opt max_file_extract_size)"; MAX_FILE_EXTRACT_SIZE="${MAX_FILE_EXTRACT_SIZE:-$DEFAULT_MAX_FILE_EXTRACT_SIZE}"
|
||||||
WEB_CONCURRENCY="$(read_opt web_concurrency)"
|
SECRET_KEY_BASE="$(read_opt secret_key_base)"; SECRET_KEY_BASE="${SECRET_KEY_BASE:-}"
|
||||||
WEB_CONCURRENCY="${WEB_CONCURRENCY:-$DEFAULT_WEB_CONCURRENCY}"
|
PUBLIC_HOSTNAME_RAW="$(read_opt public_hostname)"; PUBLIC_HOSTNAME_RAW="${PUBLIC_HOSTNAME_RAW:-}"
|
||||||
RAILS_MAX_THREADS="$(read_opt rails_max_threads)"
|
|
||||||
RAILS_MAX_THREADS="${RAILS_MAX_THREADS:-$DEFAULT_RAILS_MAX_THREADS}"
|
|
||||||
DEFAULT_WORKER_CONCURRENCY="$(read_opt default_worker_concurrency)"
|
|
||||||
DEFAULT_WORKER_CONCURRENCY="${DEFAULT_WORKER_CONCURRENCY:-$DEFAULT_DEFAULT_WORKER_CONCURRENCY}"
|
|
||||||
PERFORMANCE_WORKER_CONCURRENCY="$(read_opt performance_worker_concurrency)"
|
|
||||||
PERFORMANCE_WORKER_CONCURRENCY="${PERFORMANCE_WORKER_CONCURRENCY:-$DEFAULT_PERFORMANCE_WORKER_CONCURRENCY}"
|
|
||||||
MAX_FILE_UPLOAD_SIZE="$(read_opt max_file_upload_size)"
|
|
||||||
MAX_FILE_UPLOAD_SIZE="${MAX_FILE_UPLOAD_SIZE:-$DEFAULT_MAX_FILE_UPLOAD_SIZE}"
|
|
||||||
MAX_FILE_EXTRACT_SIZE="$(read_opt max_file_extract_size)"
|
|
||||||
MAX_FILE_EXTRACT_SIZE="${MAX_FILE_EXTRACT_SIZE:-$DEFAULT_MAX_FILE_EXTRACT_SIZE}"
|
|
||||||
SECRET_KEY_BASE="$(read_opt secret_key_base)"
|
|
||||||
SECRET_KEY_BASE="${SECRET_KEY_BASE:-}"
|
|
||||||
PUBLIC_HOSTNAME_RAW="$(read_opt public_hostname)"
|
|
||||||
PUBLIC_HOSTNAME_RAW="${PUBLIC_HOSTNAME_RAW:-}"
|
|
||||||
|
|
||||||
[[ "$PUID" =~ ^[0-9]+$ ]] || die "puid must be a non-negative integer"
|
[[ "$PUID" =~ ^[0-9]+$ ]] || die "puid must be a non-negative integer"
|
||||||
[[ "$PGID" =~ ^[0-9]+$ ]] || die "pgid must be a non-negative integer"
|
[[ "$PGID" =~ ^[0-9]+$ ]] || die "pgid must be a non-negative integer"
|
||||||
|
|||||||
@@ -245,11 +245,11 @@ if [[ "${MEILISEARCH_LOCAL}" == true ]]; then
|
|||||||
}
|
}
|
||||||
|
|
||||||
MEILISEARCH_CMD=(
|
MEILISEARCH_CMD=(
|
||||||
env
|
env \
|
||||||
MEILI_ENV="${MEILISEARCH_ENVIRONMENT}"
|
MEILI_ENV="${MEILISEARCH_ENVIRONMENT}" \
|
||||||
MEILI_NO_ANALYTICS="${MEILISEARCH_NO_ANALYTICS}"
|
MEILI_NO_ANALYTICS="${MEILISEARCH_NO_ANALYTICS}" \
|
||||||
meilisearch
|
meilisearch \
|
||||||
--http-addr "${MEILISEARCH_ADDR}"
|
--http-addr "${MEILISEARCH_ADDR}" \
|
||||||
--db-path "${MEILISEARCH_DB_PATH}"
|
--db-path "${MEILISEARCH_DB_PATH}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
0
netbird-server/rootfs/etc/services.d/caddy/run
Executable file → Normal file
0
netbird-server/rootfs/etc/services.d/caddy/run
Executable file → Normal file
0
netbird-server/rootfs/etc/services.d/dashboard/run
Executable file → Normal file
0
netbird-server/rootfs/etc/services.d/dashboard/run
Executable file → Normal file
0
netbird-server/rootfs/etc/services.d/management/run
Executable file → Normal file
0
netbird-server/rootfs/etc/services.d/management/run
Executable file → Normal file
0
netbird-server/rootfs/etc/services.d/relay/run
Executable file → Normal file
0
netbird-server/rootfs/etc/services.d/relay/run
Executable file → Normal file
0
netbird-server/rootfs/etc/services.d/signal/run
Executable file → Normal file
0
netbird-server/rootfs/etc/services.d/signal/run
Executable file → Normal file
@@ -143,7 +143,7 @@ If you use clients for file syncing, the use of SQLite is highly discouraged.
|
|||||||
and you want to overcome this, follow the below steps:
|
and you want to overcome this, follow the below steps:
|
||||||
|
|
||||||
- 1. Install `mariadb` add-on, configure it with some random infos and start it. It is important to start it successfully in order to be seen by `nextcloud` in the network.
|
- 1. Install `mariadb` add-on, configure it with some random infos and start it. It is important to start it successfully in order to be seen by `nextcloud` in the network.
|
||||||
- 1. Install `nextcloud` add-on (or restart it if you have already installed), watch the logs until you will notice the following `warning`:
|
- 2. Install `nextcloud` add-on (or restart it if you have already installed), watch the logs until you will notice the following `warning`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
WARNING: MariaDB addon was found! It can't be configured automatically due to the way Nextcloud works, but you can configure it manually when running the web UI for the first time using those values :
|
WARNING: MariaDB addon was found! It can't be configured automatically due to the way Nextcloud works, but you can configure it manually when running the web UI for the first time using those values :
|
||||||
@@ -153,8 +153,8 @@ and you want to overcome this, follow the below steps:
|
|||||||
Host-name : core-mariadb:3306
|
Host-name : core-mariadb:3306
|
||||||
```
|
```
|
||||||
|
|
||||||
- 1. Go back at `mariadb` add-on, configure it with above credentials and restart it. Make sure the add-on is creating the `nextcloud` database.
|
- 3. Go back at `mariadb` add-on, configure it with above credentials and restart it. Make sure the add-on is creating the `nextcloud` database.
|
||||||
- 1. Go in the webui and fill all required info. Here you can view an example:
|
- 4. Go in the webui and fill all required info. Here you can view an example:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
0
nzbget/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
nzbget/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/addon-init/script
Normal file → Executable file
0
obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/addon-init/script
Normal file → Executable file
0
obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/addon-init/up
Normal file → Executable file
0
obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/addon-init/up
Normal file → Executable file
0
obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/couchdb/finish
Normal file → Executable file
0
obsidian_syncserver_npm/rootfs/etc/s6-overlay/s6-rc.d/couchdb/finish
Normal file → Executable file
@@ -108,7 +108,7 @@ wait_for_postgres() {
|
|||||||
while ! pg_isready -h "$DB_HOSTNAME" -p "$DB_PORT" -U "$DB_USERNAME" > /dev/null 2>&1; do
|
while ! pg_isready -h "$DB_HOSTNAME" -p "$DB_PORT" -U "$DB_USERNAME" > /dev/null 2>&1; do
|
||||||
tries=$((tries + 1))
|
tries=$((tries + 1))
|
||||||
[ "$tries" -ge 60 ] && {
|
[ "$tries" -ge 60 ] && {
|
||||||
bashio::log.error "Postgres did not start after 2 minutes, aborting."
|
bashio::log.error "Postgres did not start after 2 minutes, aborting."
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
echo "PostgreSQL is starting up... ($tries/60)"
|
echo "PostgreSQL is starting up... ($tries/60)"
|
||||||
|
|||||||
0
qbittorrent/rootfs/etc/s6-overlay/s6-rc.d/svc-qbittorrent/run
Executable file → Normal file
0
qbittorrent/rootfs/etc/s6-overlay/s6-rc.d/svc-qbittorrent/run
Executable file → Normal file
0
qbittorrent/rootfs/etc/services.d/timer/run
Executable file → Normal file
0
qbittorrent/rootfs/etc/services.d/timer/run
Executable file → Normal file
@@ -178,8 +178,7 @@ read -r VPN_IP VPN_COUNTRY <<< "${VPN_INFO_OUT}"
|
|||||||
bashio::log.info "VPN external IP: ${VPN_IP} (${VPN_COUNTRY})"
|
bashio::log.info "VPN external IP: ${VPN_IP} (${VPN_COUNTRY})"
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
sleep "${VPN_CHECK_INTERVAL}" &
|
sleep "${VPN_CHECK_INTERVAL}" & wait $!
|
||||||
wait $!
|
|
||||||
|
|
||||||
if ! current_out="$(get_ip_info)"; then
|
if ! current_out="$(get_ip_info)"; then
|
||||||
bashio::log.warning "Failed to refresh external IP; keeping previous assumptions."
|
bashio::log.warning "Failed to refresh external IP; keeping previous assumptions."
|
||||||
|
|||||||
6
qbittorrent/rootfs/etc/services.d/vpn-upnp/run
Executable file → Normal file
6
qbittorrent/rootfs/etc/services.d/vpn-upnp/run
Executable file → Normal file
@@ -253,9 +253,9 @@ config["Interval"]=$((${VPN_UPNP_INTERVAL} + (${VPN_UPNP_INTERVAL} / 2)))
|
|||||||
|
|
||||||
bashio::log.info "VPN UPnP enabled, starting NAT-PMP/UPnP monitor with an interval of ${VPN_UPNP_INTERVAL} seconds (UPnP lease interval: ${config["Interval"]} seconds)."
|
bashio::log.info "VPN UPnP enabled, starting NAT-PMP/UPnP monitor with an interval of ${VPN_UPNP_INTERVAL} seconds (UPnP lease interval: ${config["Interval"]} seconds)."
|
||||||
|
|
||||||
while true; do
|
while true;
|
||||||
sleep ${VPN_UPNP_INTERVAL} &
|
do
|
||||||
wait $!
|
sleep ${VPN_UPNP_INTERVAL} & wait $!
|
||||||
|
|
||||||
if pnat_set; then
|
if pnat_set; then
|
||||||
bashio::log.info "NAT-PMP/UPnP Ok!"
|
bashio::log.info "NAT-PMP/UPnP Ok!"
|
||||||
|
|||||||
0
qbittorrent/rootfs/usr/local/sbin/vpn
Normal file → Executable file
0
qbittorrent/rootfs/usr/local/sbin/vpn
Normal file → Executable file
0
readarr/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
readarr/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
sabnzbd/rootfs/etc/services.d/nginx/finish
Normal file → Executable file
0
sabnzbd/rootfs/etc/services.d/nginx/finish
Normal file → Executable file
@@ -73,8 +73,8 @@ validate_backup_against_source() {
|
|||||||
find . -mindepth 1 -print | sed -e 's#^\./##' -e 's#/$##' | LC_ALL=C sort
|
find . -mindepth 1 -print | sed -e 's#^\./##' -e 's#/$##' | LC_ALL=C sort
|
||||||
) > "$source_manifest"
|
) > "$source_manifest"
|
||||||
|
|
||||||
tar -tzf "$archive" |
|
tar -tzf "$archive" | \
|
||||||
sed -e "s#^${archive_root}/##" -e '/^$/d' -e 's#/$##' |
|
sed -e "s#^${archive_root}/##" -e '/^$/d' -e 's#/$##' | \
|
||||||
LC_ALL=C sort > "$archive_manifest"
|
LC_ALL=C sort > "$archive_manifest"
|
||||||
|
|
||||||
if ! cmp -s "$source_manifest" "$archive_manifest"; then
|
if ! cmp -s "$source_manifest" "$archive_manifest"; then
|
||||||
|
|||||||
0
scrutiny_fa/rootfs_overlay/etc/services.d/nginx/finish
Normal file → Executable file
0
scrutiny_fa/rootfs_overlay/etc/services.d/nginx/finish
Normal file → Executable file
@@ -73,8 +73,8 @@ validate_backup_against_source() {
|
|||||||
find . -mindepth 1 -print | sed -e 's#^\./##' -e 's#/$##' | LC_ALL=C sort
|
find . -mindepth 1 -print | sed -e 's#^\./##' -e 's#/$##' | LC_ALL=C sort
|
||||||
) > "$source_manifest"
|
) > "$source_manifest"
|
||||||
|
|
||||||
tar -tzf "$archive" |
|
tar -tzf "$archive" | \
|
||||||
sed -e "s#^${archive_root}/##" -e '/^$/d' -e 's#/$##' |
|
sed -e "s#^${archive_root}/##" -e '/^$/d' -e 's#/$##' | \
|
||||||
LC_ALL=C sort > "$archive_manifest"
|
LC_ALL=C sort > "$archive_manifest"
|
||||||
|
|
||||||
if ! cmp -s "$source_manifest" "$archive_manifest"; then
|
if ! cmp -s "$source_manifest" "$archive_manifest"; then
|
||||||
|
|||||||
@@ -108,8 +108,8 @@ sed -i "s|/shared|$DATA_LOCATION|g" /home/seafile/*.sh
|
|||||||
ADMIN_EMAIL_VAL="$(bashio::config 'SEAFILE_ADMIN_EMAIL')"
|
ADMIN_EMAIL_VAL="$(bashio::config 'SEAFILE_ADMIN_EMAIL')"
|
||||||
ADMIN_PASSWORD_VAL="$(bashio::config 'SEAFILE_ADMIN_PASSWORD')"
|
ADMIN_PASSWORD_VAL="$(bashio::config 'SEAFILE_ADMIN_PASSWORD')"
|
||||||
|
|
||||||
if [[ -n "${ADMIN_EMAIL_VAL}" && "${ADMIN_EMAIL_VAL}" != "null" &&
|
if [[ -n "${ADMIN_EMAIL_VAL}" && "${ADMIN_EMAIL_VAL}" != "null" \
|
||||||
-n "${ADMIN_PASSWORD_VAL}" && "${ADMIN_PASSWORD_VAL}" != "null" ]]; then
|
&& -n "${ADMIN_PASSWORD_VAL}" && "${ADMIN_PASSWORD_VAL}" != "null" ]]; then
|
||||||
bashio::log.info "Seeding admin credentials"
|
bashio::log.info "Seeding admin credentials"
|
||||||
|
|
||||||
mkdir -p "${DATA_LOCATION}/conf"
|
mkdir -p "${DATA_LOCATION}/conf"
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
arch:
|
arch:
|
||||||
- aarch64
|
- aarch64
|
||||||
- amd64
|
- amd64
|
||||||
description: Open-source media request and discovery manager for Jellyfin, Plex, and Emby
|
description:
|
||||||
|
Open-source media request and discovery manager for Jellyfin, Plex, and Emby
|
||||||
devices:
|
devices:
|
||||||
- /dev/dri
|
- /dev/dri
|
||||||
- /dev/dri/card0
|
- /dev/dri/card0
|
||||||
|
|||||||
0
seerr/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
seerr/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
seerr/rootfs/etc/services.d/seerr/finish
Normal file → Executable file
0
seerr/rootfs/etc/services.d/seerr/finish
Normal file → Executable file
@@ -42,5 +42,6 @@ if [[ ! -f /data/version || "$current_version" != "$(cat /data/version)" ]]; the
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
bashio::log.info "Starting application"
|
bashio::log.info "Starting application"
|
||||||
sudo -u "$USER" -s /bin/sh -c "/home/node/signalk/startup.sh"
|
sudo -u "$USER" -s /bin/sh -c "/home/node/signalk/startup.sh"
|
||||||
|
|||||||
0
transmission_openvpn/rootfs/etc/openvpn/update-resolv-conf
Normal file → Executable file
0
transmission_openvpn/rootfs/etc/openvpn/update-resolv-conf
Normal file → Executable file
@@ -167,8 +167,8 @@ case "$(bashio::config "DB_CONNECTION")" in
|
|||||||
-u "${ZM_DB_USER}" -p"${ZM_DB_PASS}" \
|
-u "${ZM_DB_USER}" -p"${ZM_DB_PASS}" \
|
||||||
-h "${ZM_DB_HOST}" -P "${ZM_DB_PORT}" \
|
-h "${ZM_DB_HOST}" -P "${ZM_DB_PORT}" \
|
||||||
--routines --events --triggers \
|
--routines --events --triggers \
|
||||||
"${LEGACY_DB_NAME}" \
|
"${LEGACY_DB_NAME}" | \
|
||||||
| mysql \
|
mysql \
|
||||||
-u "${ZM_DB_USER}" -p"${ZM_DB_PASS}" \
|
-u "${ZM_DB_USER}" -p"${ZM_DB_PASS}" \
|
||||||
-h "${ZM_DB_HOST}" -P "${ZM_DB_PORT}" \
|
-h "${ZM_DB_HOST}" -P "${ZM_DB_PORT}" \
|
||||||
"${ZM_DB_NAME}"; then
|
"${ZM_DB_NAME}"; then
|
||||||
|
|||||||
0
zoraxy/rootfs/etc/services.d/zoraxy/run
Executable file → Normal file
0
zoraxy/rootfs/etc/services.d/zoraxy/run
Executable file → Normal file
@@ -1,7 +1,8 @@
|
|||||||
arch:
|
arch:
|
||||||
- aarch64
|
- aarch64
|
||||||
- amd64
|
- amd64
|
||||||
description: Fork of overseerr for jellyfin support (deprecated, migrate to Seerr add-on)
|
description:
|
||||||
|
Fork of overseerr for jellyfin support (deprecated, migrate to Seerr add-on)
|
||||||
devices:
|
devices:
|
||||||
- /dev/dri
|
- /dev/dri
|
||||||
- /dev/dri/card0
|
- /dev/dri/card0
|
||||||
|
|||||||
0
zzz_archived_kapowarr/rootfs/etc/services.d/kapowarr/run
Executable file → Normal file
0
zzz_archived_kapowarr/rootfs/etc/services.d/kapowarr/run
Executable file → Normal file
0
zzz_archived_kapowarr/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
zzz_archived_kapowarr/rootfs/etc/services.d/nginx/run
Executable file → Normal file
0
zzz_archived_omada/rootfs/etc/cont-init.d/99-run.sh
Executable file → Normal file
0
zzz_archived_omada/rootfs/etc/cont-init.d/99-run.sh
Executable file → Normal file
0
zzz_archived_overseerr/rootfs/etc/cont-init.d/00-config_location.sh
Executable file → Normal file
0
zzz_archived_overseerr/rootfs/etc/cont-init.d/00-config_location.sh
Executable file → Normal file
0
zzz_archived_overseerr/rootfs/etc/cont-init.d/20-folders.sh
Executable file → Normal file
0
zzz_archived_overseerr/rootfs/etc/cont-init.d/20-folders.sh
Executable file → Normal file
@@ -90,10 +90,7 @@ set +u
|
|||||||
# container_environment, which is read by `with-contenv` when each service starts.
|
# container_environment, which is read by `with-contenv` when each service starts.
|
||||||
S6_ENV_DIR=""
|
S6_ENV_DIR=""
|
||||||
for candidate in /var/run/s6/container_environment /run/s6/container_environment; do
|
for candidate in /var/run/s6/container_environment /run/s6/container_environment; do
|
||||||
if [ -d "$candidate" ]; then
|
if [ -d "$candidate" ]; then S6_ENV_DIR="$candidate"; break; fi
|
||||||
S6_ENV_DIR="$candidate"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
|
|
||||||
# For all relevant variables
|
# For all relevant variables
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ fi
|
|||||||
# Checks if client names where configured when using stealth mode
|
# Checks if client names where configured when using stealth mode
|
||||||
if bashio::config.true 'hidden_services' \
|
if bashio::config.true 'hidden_services' \
|
||||||
&& bashio::config.true 'stealth' \
|
&& bashio::config.true 'stealth' \
|
||||||
&& ! bashio::config.has_value 'client_names'; then
|
&& ! bashio::config.has_value 'client_names';
|
||||||
|
then
|
||||||
bashio::log.fatal
|
bashio::log.fatal
|
||||||
bashio::log.fatal 'Add-on configuration is incomplete.'
|
bashio::log.fatal 'Add-on configuration is incomplete.'
|
||||||
bashio::log.fatal
|
bashio::log.fatal
|
||||||
@@ -131,7 +132,8 @@ fi
|
|||||||
|
|
||||||
# Configure bridges
|
# Configure bridges
|
||||||
if bashio::config.exists 'bridges' \
|
if bashio::config.exists 'bridges' \
|
||||||
&& ! bashio::config.is_empty 'bridges'; then
|
&& ! bashio::config.is_empty 'bridges';
|
||||||
|
then
|
||||||
bashio::log.info 'Use bridges:'
|
bashio::log.info 'Use bridges:'
|
||||||
echo "UseBridges 1" >> "${torrc}"
|
echo "UseBridges 1" >> "${torrc}"
|
||||||
|
|
||||||
@@ -174,12 +176,14 @@ if bashio::config.true 'hidden_services'; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Configure stealth mode
|
# Configure stealth mode
|
||||||
if bashio::config.true 'hidden_services' && bashio::config.true 'stealth'; then
|
if bashio::config.true 'hidden_services' && bashio::config.true 'stealth';
|
||||||
|
then
|
||||||
# Following the documentation at:
|
# Following the documentation at:
|
||||||
# https://community.torproject.org/onion-services/advanced/client-auth/
|
# https://community.torproject.org/onion-services/advanced/client-auth/
|
||||||
while read -r clientname; do
|
while read -r clientname; do
|
||||||
# Generate key is they do not exist yet
|
# Generate key is they do not exist yet
|
||||||
if ! bashio::fs.file_exists "${authorized_clients_dir}/${clientname}.auth"; then
|
if ! bashio::fs.file_exists "${authorized_clients_dir}/${clientname}.auth"
|
||||||
|
then
|
||||||
key=$(openssl genpkey -algorithm x25519)
|
key=$(openssl genpkey -algorithm x25519)
|
||||||
|
|
||||||
private_key=$(
|
private_key=$(
|
||||||
|
|||||||
0
zzz_archived_tor/rootfs/etc/s6-overlay/s6-rc.d/tor/run
Executable file → Normal file
0
zzz_archived_tor/rootfs/etc/s6-overlay/s6-rc.d/tor/run
Executable file → Normal file
Reference in New Issue
Block a user