Merge pull request #2408 from alexbelgium/codex/refactor-birdnet-pipy-ha-add-on-for-s6-supervision

Add configurable `data_location` option and symlink `/app/data` to chosen path
This commit is contained in:
Alexandre
2026-01-28 20:03:40 +01:00
committed by GitHub
11 changed files with 123 additions and 38 deletions

View File

@@ -50,7 +50,7 @@ USER root
# Copy local files
COPY rootfs/ /
RUN find . -type f \( -name "*.sh" -o -name "run" \) -print -exec chmod +x {} \;
RUN find /etc -type f \( -name "*.sh" -o -path "*/services.d/*/run" \) -exec chmod +x {} \;
# Uses /bin for compatibility purposes
# hadolint ignore=DL4005

View File

@@ -11,8 +11,10 @@ ingress_entry: /
ingress_stream: true
panel_icon: mdi:bird
init: false
share: true
map:
- addon_config:rw
- data:rw
ports:
8099/tcp: 8099
ports_description:
@@ -21,11 +23,17 @@ options:
TZ: Etc/UTC
ICECAST_PASSWORD: ""
STREAM_BITRATE: 320k
RECORDING_MODE: "rtsp"
RTSP_URL: ""
data_location: /config/data
env_vars: []
schema:
TZ: str?
ICECAST_PASSWORD: str?
STREAM_BITRATE: str?
RECORDING_MODE: list(pulseaudio|http_stream|rtsp)
RTSP_URL: str?
data_location: str
env_vars:
- name: match(^[A-Za-z0-9_]+$)
value: str?

View File

@@ -1,24 +1,37 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
set -euo pipefail
DATA_ROOT="/config/birdnet-pipy"
DATA_DIR="${DATA_ROOT}/data"
DEFAULT_LOCATION="/config/data"
DATA_LOCATION="$(bashio::config 'data_location' || true)"
DATA_LOCATION="${DATA_LOCATION:-$DEFAULT_LOCATION}"
mkdir -p "${DATA_DIR}"
case "${DATA_LOCATION}" in
/config/*|/share/*|/data/*) ;;
*)
bashio::log.warning "Invalid data_location '${DATA_LOCATION}', falling back to ${DEFAULT_LOCATION}"
DATA_LOCATION="${DEFAULT_LOCATION}"
;;
esac
if [ -e /app/data ] && [ ! -L /app/data ]; then
rm -rf /app/data
LEGACY1="/config/birdnet-pipy/data"
LEGACY2="/data"
mkdir -p "${DATA_LOCATION}"
if [ -z "$(ls -A "${DATA_LOCATION}" 2>/dev/null || true)" ]; then
if [ -d "${LEGACY1}" ] && [ -n "$(ls -A "${LEGACY1}" 2>/dev/null || true)" ]; then
bashio::log.notice "Migrating legacy data from ${LEGACY1} to ${DATA_LOCATION}"
cp -a "${LEGACY1}/." "${DATA_LOCATION}/" || true
elif [ -d "${LEGACY2}" ] && [ "${LEGACY2}" != "${DATA_LOCATION}" ] && [ -n "$(ls -A "${LEGACY2}" 2>/dev/null || true)" ]; then
bashio::log.notice "Migrating legacy data from ${LEGACY2} to ${DATA_LOCATION}"
cp -a "${LEGACY2}/." "${DATA_LOCATION}/" || true
fi
fi
if [ ! -L /app/data ]; then
ln -s "${DATA_DIR}" /app/data
fi
mkdir -p "${DATA_LOCATION}/config" "${DATA_LOCATION}/clips" "${DATA_LOCATION}/logs" "${DATA_LOCATION}/cache" || true
mkdir -p \
/app/data/config \
/app/data/db \
/app/data/audio/recordings \
/app/data/audio/extracted_songs \
/app/data/spectrograms \
/app/data/flags
rm -rf /app/data
ln -s "${DATA_LOCATION}" /app/data
bashio::log.notice "Data location set to: ${DATA_LOCATION}"

View File

@@ -0,0 +1,34 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -euo pipefail
DATA_DIR="/app/data"
CFG_DIR="${DATA_DIR}/config"
SETTINGS="${CFG_DIR}/user_settings.json"
mkdir -p "${CFG_DIR}"
if [ ! -f "${SETTINGS}" ]; then
if [ -f /app/config/user_settings.example.json ]; then
cp /app/config/user_settings.example.json "${SETTINGS}"
else
printf '%s\n' '{}' > "${SETTINGS}"
fi
fi
RECORDING_MODE="$(bashio::config 'RECORDING_MODE' || true)"
RTSP_URL="$(bashio::config 'RTSP_URL' || true)"
PATCH='{}'
if [ -n "${RECORDING_MODE}" ]; then
PATCH="$(printf '%s' "${PATCH}" | jq --arg v "${RECORDING_MODE}" '.audio.recording_mode=$v')"
fi
if [ -n "${RTSP_URL}" ]; then
PATCH="$(printf '%s' "${PATCH}" | jq --arg v "${RTSP_URL}" '.audio.rtsp_url=$v')"
fi
tmp="$(mktemp)"
jq -s '.[0] * .[1]' "${SETTINGS}" <(printf '%s\n' "${PATCH}") > "${tmp}"
mv "${tmp}" "${SETTINGS}"
chmod 0644 "${SETTINGS}" || true

View File

@@ -0,0 +1,21 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -euo pipefail
SND_GID=""
if [ -e /dev/snd ] && command -v stat >/dev/null 2>&1; then
SND_GID="$(stat -c '%g' /dev/snd 2>/dev/null || true)"
fi
if [ -n "${SND_GID}" ] && getent group audio >/dev/null 2>&1; then
current_gid="$(getent group audio | cut -d: -f3 || true)"
if [ -n "${current_gid}" ] && [ "${current_gid}" != "${SND_GID}" ]; then
groupmod -g "${SND_GID}" audio 2>/dev/null || true
fi
fi
for u in root nginx www-data; do
if id "${u}" >/dev/null 2>&1; then
usermod -aG audio "${u}" 2>/dev/null || true
fi
done

View File

@@ -1,21 +0,0 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -e
export PYTHONPATH=/app
export PULSE_SERVER=unix:/run/pulse/native
cd /app
bashio::log.info "Starting BirdNET-PiPy services"
python3 -m model_service.inference_server &
python3 -m core.api &
python3 -m core.main &
/usr/local/bin/start-icecast.sh &
bashio::net.wait_for 5002 localhost 300
bashio::log.info "BirdNET-PiPy API is available"
exec nginx

View File

@@ -0,0 +1,7 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -euo pipefail
export PYTHONPATH=/app
bashio::net.wait_for 5001 127.0.0.1 300
cd /app
exec python3 -m core.api

View File

@@ -0,0 +1,5 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -euo pipefail
export PULSE_SERVER=unix:/run/pulse/native
exec /usr/local/bin/start-icecast.sh

View File

@@ -0,0 +1,8 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -euo pipefail
export PYTHONPATH=/app
export PULSE_SERVER=unix:/run/pulse/native
bashio::net.wait_for 5002 127.0.0.1 300
cd /app
exec python3 -m core.main

View File

@@ -0,0 +1,6 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -euo pipefail
export PYTHONPATH=/app
cd /app
exec python3 -m model_service.inference_server

View File

@@ -0,0 +1,4 @@
#!/usr/bin/with-contenv bashio
# shellcheck shell=bash
set -euo pipefail
exec nginx -g "daemon off;"