From c4374e2c90210e2e6e1e34d5b6c137d4bb91db8e Mon Sep 17 00:00:00 2001
From: Pierre
Date: Thu, 5 Mar 2026 15:59:21 +0100
Subject: [PATCH 1/5] Add Maintainerr addon
---
maintainerr/CHANGELOG.md | 8 ++
maintainerr/Dockerfile | 135 +++++++++++++++++++++++++++++++
maintainerr/README.md | 43 ++++++++++
maintainerr/apparmor.txt | 66 +++++++++++++++
maintainerr/build.json | 6 ++
maintainerr/config.yaml | 91 +++++++++++++++++++++
maintainerr/icon.png | Bin 0 -> 6055 bytes
maintainerr/logo.png | Bin 0 -> 6055 bytes
maintainerr/rootfs/entrypoint.sh | 37 +++++++++
maintainerr/updater.json | 8 ++
10 files changed, 394 insertions(+)
create mode 100644 maintainerr/CHANGELOG.md
create mode 100644 maintainerr/Dockerfile
create mode 100644 maintainerr/README.md
create mode 100644 maintainerr/apparmor.txt
create mode 100644 maintainerr/build.json
create mode 100644 maintainerr/config.yaml
create mode 100644 maintainerr/icon.png
create mode 100644 maintainerr/logo.png
create mode 100644 maintainerr/rootfs/entrypoint.sh
create mode 100644 maintainerr/updater.json
diff --git a/maintainerr/CHANGELOG.md b/maintainerr/CHANGELOG.md
new file mode 100644
index 000000000..4e7782de4
--- /dev/null
+++ b/maintainerr/CHANGELOG.md
@@ -0,0 +1,8 @@
+# Changelog
+
+## 3.0.1
+
+- Initial release of Maintainerr addon
+- Based on upstream image `ghcr.io/maintainerr/maintainerr:3.0.1`
+- Persistent data stored in HA addon config directory
+- Supports amd64 and aarch64 architectures
diff --git a/maintainerr/Dockerfile b/maintainerr/Dockerfile
new file mode 100644
index 000000000..26ccdb606
--- /dev/null
+++ b/maintainerr/Dockerfile
@@ -0,0 +1,135 @@
+#============================#
+# ALEXBELGIUM'S DOCKERFILE #
+#============================#
+# _.------.
+# _.-` ('>.-`"""-.
+# '.--'` _'` _ .--.)
+# -' '-.-';` `
+# ' - _.' ``'--.
+# '---` .-'""`
+# /`
+#=== Home Assistant Addon ===#
+
+# ARGs used in FROM must be declared before any FROM instruction
+ARG BUILD_UPSTREAM="3.0.1"
+
+############################
+# 0) Tools stage #
+############################
+# Build a small payload with gosu (for privilege dropping) and its shared libs
+FROM alpine:3.22 AS ha_tools
+
+RUN apk add --no-cache \
+ gosu \
+ pax-utils
+
+RUN set -eux; \
+ mkdir -p /out; \
+ for bin in /usr/bin/gosu; do \
+ mkdir -p "/out$(dirname "$bin")"; \
+ cp -a "$bin" "/out$bin"; \
+ lddtree -l "$bin" | while read -r dep; do \
+ case "$dep" in \
+ /lib/ld-musl-*.so.1) \
+ continue ;; \
+ /*) \
+ mkdir -p "/out$(dirname "$dep")"; \
+ cp -a "$dep" "/out$(dirname "$dep")/"; \
+ ;; \
+ esac; \
+ done; \
+ done
+
+#################
+# 1 Build Image #
+#################
+
+ARG BUILD_FROM
+ARG BUILD_VERSION
+FROM ghcr.io/maintainerr/maintainerr:${BUILD_UPSTREAM}
+
+##################
+# 2 Modify Image #
+##################
+
+USER root
+
+# Bring in gosu from tools stage
+COPY --from=ha_tools /out/ /
+
+##################
+# 3 Install apps #
+##################
+
+# Add rootfs
+COPY rootfs/ /
+RUN find /. -type f \( -name "*.sh" \) -print -exec chmod +x {} \;
+
+# Install bashio standalone
+RUN BASHIO_VERSION="0.14.3" && \
+ mkdir -p /tmp/bashio && \
+ curl -f -L -s -S "https://github.com/hassio-addons/bashio/archive/v${BASHIO_VERSION}.tar.gz" | tar -xzf - --strip 1 -C /tmp/bashio && \
+ mv /tmp/bashio/lib /usr/lib/bashio && \
+ ln -s /usr/lib/bashio/bashio /usr/bin/bashio && \
+ rm -rf /tmp/bashio
+
+# Modules
+ARG MODULES="00-banner.sh 01-custom_script.sh"
+
+# Automatic modules download
+ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/ha_automodules.sh" "/ha_automodules.sh"
+RUN chmod 744 /ha_automodules.sh && /ha_automodules.sh "$MODULES" && rm /ha_automodules.sh
+
+################
+# 4 Entrypoint #
+################
+
+ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templates/bashio-standalone.sh" "/usr/local/lib/bashio-standalone.sh"
+RUN chmod 0755 /usr/local/lib/bashio-standalone.sh
+
+# Use our wrapper as entrypoint (replaces original /opt/app/start.sh)
+ENTRYPOINT ["/entrypoint.sh"]
+
+############
+# 5 Labels #
+############
+
+ARG BUILD_ARCH
+ARG BUILD_DATE
+ARG BUILD_DESCRIPTION
+ARG BUILD_NAME
+ARG BUILD_REF
+ARG BUILD_REPOSITORY
+ARG BUILD_VERSION
+ENV BUILD_VERSION="${BUILD_VERSION}"
+LABEL \
+ io.hass.name="${BUILD_NAME}" \
+ io.hass.description="${BUILD_DESCRIPTION}" \
+ io.hass.arch="${BUILD_ARCH}" \
+ io.hass.type="addon" \
+ io.hass.version=${BUILD_VERSION} \
+ maintainer="alexbelgium (https://github.com/alexbelgium)" \
+ org.opencontainers.image.title="${BUILD_NAME}" \
+ org.opencontainers.image.description="${BUILD_DESCRIPTION}" \
+ org.opencontainers.image.vendor="Home Assistant Add-ons" \
+ org.opencontainers.image.authors="alexbelgium (https://github.com/alexbelgium)" \
+ org.opencontainers.image.licenses="MIT" \
+ org.opencontainers.image.url="https://github.com/alexbelgium" \
+ org.opencontainers.image.source="https://github.com/${BUILD_REPOSITORY}" \
+ org.opencontainers.image.documentation="https://github.com/${BUILD_REPOSITORY}/blob/main/README.md" \
+ org.opencontainers.image.created=${BUILD_DATE} \
+ org.opencontainers.image.revision=${BUILD_REF} \
+ org.opencontainers.image.version=${BUILD_VERSION}
+
+#################
+# 6 Healthcheck #
+#################
+
+ENV HEALTH_PORT="6246" \
+ HEALTH_URL=""
+HEALTHCHECK \
+ --interval=5s \
+ --retries=5 \
+ --start-period=60s \
+ --timeout=25s \
+ CMD curl -A "HealthCheck: Docker/1.0" -s -f "http://127.0.0.1:${HEALTH_PORT}${HEALTH_URL}" &>/dev/null || exit 1
diff --git a/maintainerr/README.md b/maintainerr/README.md
new file mode 100644
index 000000000..8654b452a
--- /dev/null
+++ b/maintainerr/README.md
@@ -0,0 +1,43 @@
+# Home Assistant Add-on: Maintainerr
+
+_"Looks and smells like Overseerr, does the opposite."_
+
+Maintainerr is a rule-based media management tool for your Plex, Jellyfin, or Emby ecosystem. It creates smart collections based on configurable rules (watched status, age, ratings, ...) and can optionally delete unwatched content to keep your library clean.
+
+## About
+
+Maintainerr integrates with:
+- **Plex / Jellyfin / Emby** — media server
+- **Sonarr / Radarr** — to remove media files
+- **Overseerr / Jellyseerr** — to reset requests
+- **Tautulli** — for advanced watch statistics
+
+## Installation
+
+1. Add the repository to Home Assistant.
+2. Install the **Maintainerr** add-on.
+3. Start the add-on.
+4. Open the Web UI on port `6246`.
+
+## Configuration
+
+| Option | Description |
+|--------|-------------|
+| `TZ` | Timezone (e.g. `Europe/Paris`). Defaults to `Europe/London`. |
+| `env_vars` | Extra environment variables passed to the container. |
+
+### Available extra env vars
+
+| Variable | Default | Description |
+|----------|---------|-------------|
+| `UI_PORT` | `6246` | Change the listening port |
+| `BASE_PATH` | _(empty)_ | Serve under a URL subpath |
+
+## Data
+
+Persistent data (database, configuration) is stored in the HA addon config directory and survives add-on updates and reinstalls.
+
+## Support
+
+- [Maintainerr upstream project](https://github.com/maintainerr/maintainerr)
+- [Addon repository issues](https://github.com/alexbelgium/hassio-addons/issues)
diff --git a/maintainerr/apparmor.txt b/maintainerr/apparmor.txt
new file mode 100644
index 000000000..cebe37e41
--- /dev/null
+++ b/maintainerr/apparmor.txt
@@ -0,0 +1,66 @@
+#include
+
+profile maintainerr_addon flags=(attach_disconnected,mediate_deleted) {
+ #include
+
+ capability,
+ file,
+ signal,
+ mount,
+ umount,
+ remount,
+ network udp,
+ network tcp,
+ network dgram,
+ network stream,
+ network inet,
+ network inet6,
+ network netlink raw,
+ network unix dgram,
+
+ capability setgid,
+ capability setuid,
+ capability sys_admin,
+ capability dac_read_search,
+ # capability dac_override,
+ # capability sys_rawio,
+
+# S6-Overlay
+ /init ix,
+ /run/{s6,s6-rc*,service}/** ix,
+ /package/** ix,
+ /command/** ix,
+ /run/{,**} rwk,
+ /dev/tty rw,
+ /bin/** ix,
+ /usr/bin/** ix,
+ /usr/lib/bashio/** ix,
+ /etc/s6/** rix,
+ /run/s6/** rix,
+ /etc/services.d/** rwix,
+ /etc/cont-init.d/** rwix,
+ /etc/cont-finish.d/** rwix,
+ /init rix,
+ /var/run/** mrwkl,
+ /var/run/ mrwkl,
+ /dev/i2c-1 mrwkl,
+ # Files required
+ /dev/fuse mrwkl,
+ /dev/sda1 mrwkl,
+ /dev/sdb1 mrwkl,
+ /dev/nvme0 mrwkl,
+ /dev/nvme1 mrwkl,
+ /dev/mmcblk0p1 mrwkl,
+ /dev/* mrwkl,
+ /tmp/** mrkwl,
+
+ # Data access
+ /data/** rw,
+
+ # suppress ptrace denials when using 'docker ps' or using 'ps' inside a container
+ ptrace (trace,read) peer=docker-default,
+
+ # docker daemon confinement requires explict allow rule for signal
+ signal (receive) set=(kill,term) peer=/usr/bin/docker,
+
+}
diff --git a/maintainerr/build.json b/maintainerr/build.json
new file mode 100644
index 000000000..51daa2cdf
--- /dev/null
+++ b/maintainerr/build.json
@@ -0,0 +1,6 @@
+{
+ "build_from": {
+ "aarch64": "ghcr.io/maintainerr/maintainerr:latest",
+ "amd64": "ghcr.io/maintainerr/maintainerr:latest"
+ }
+}
diff --git a/maintainerr/config.yaml b/maintainerr/config.yaml
new file mode 100644
index 000000000..2d7a8c31f
--- /dev/null
+++ b/maintainerr/config.yaml
@@ -0,0 +1,91 @@
+arch:
+ - aarch64
+ - amd64
+description:
+ Rule-based media cleanup tool for Plex, Jellyfin and Emby. Creates collections and optionally deletes unwatched content.
+devices:
+ - /dev/dri
+ - /dev/dri/card0
+ - /dev/dri/card1
+ - /dev/dri/renderD128
+ - /dev/vchiq
+ - /dev/video10
+ - /dev/video11
+ - /dev/video12
+ - /dev/video13
+ - /dev/video14
+ - /dev/video15
+ - /dev/video16
+ - /dev/ttyUSB0
+ - /dev/sda
+ - /dev/sdb
+ - /dev/sdc
+ - /dev/sdd
+ - /dev/sde
+ - /dev/sdf
+ - /dev/sdg
+ - /dev/nvme
+ - /dev/nvme0
+ - /dev/nvme0n1
+ - /dev/nvme0n1p1
+ - /dev/nvme0n1p2
+ - /dev/nvme0n1p3
+ - /dev/nvme1n1
+ - /dev/nvme1n1p1
+ - /dev/nvme1n1p2
+ - /dev/nvme1n1p3
+ - /dev/nvme2n1
+ - /dev/nvme2n1p1
+ - /dev/nvme2n1p2
+ - /dev/nvme2n3p3
+ - /dev/mmcblk
+ - /dev/fuse
+ - /dev/sda1
+ - /dev/sdb1
+ - /dev/sdc1
+ - /dev/sdd1
+ - /dev/sde1
+ - /dev/sdf1
+ - /dev/sdg1
+ - /dev/sda2
+ - /dev/sdb2
+ - /dev/sdc2
+ - /dev/sdd2
+ - /dev/sde2
+ - /dev/sdf2
+ - /dev/sdg2
+ - /dev/sda3
+ - /dev/sdb3
+ - /dev/sda4
+ - /dev/sdb4
+ - /dev/sda5
+ - /dev/sda6
+ - /dev/sda7
+ - /dev/sda8
+ - /dev/nvme0
+ - /dev/nvme1
+ - /dev/nvme2
+image: ghcr.io/alexbelgium/maintainerr-{arch}
+ingress: true
+ingress_stream: true
+init: false
+panel_icon: mdi:movie-search
+map:
+ - addon_config:rw
+name: Maintainerr
+options:
+ env_vars: []
+ TZ: Europe/London
+ports:
+ 6246/tcp: 6246
+ports_description:
+ 6246/tcp: Web interface
+schema:
+ env_vars:
+ - name: match(^[A-Za-z0-9_]+$)
+ value: str?
+ TZ: str?
+slug: maintainerr
+url: https://github.com/alexbelgium/hassio-addons/tree/master/maintainerr
+version: "3.0.1"
+webui: "[PROTO:ssl]://[HOST]:[PORT:6246]"
diff --git a/maintainerr/icon.png b/maintainerr/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..087a0caeab4f22a31e0b278b61ced63d74306a3a
GIT binary patch
literal 6055
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
Date: Fri, 6 Mar 2026 09:31:32 +0100
Subject: [PATCH 2/5] Fix review feedback: use /config, scope chmod, gate chown
- Use DATA_DIR=/config (config:rw map) per maintainer request
- Scope chmod to /entrypoint.sh and cont-init.d instead of whole FS
- Gate chown -R behind .initialized marker to avoid slow restarts
---
maintainerr/Dockerfile | 3 ++-
maintainerr/config.yaml | 2 +-
maintainerr/rootfs/entrypoint.sh | 8 ++++++--
3 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/maintainerr/Dockerfile b/maintainerr/Dockerfile
index 26ccdb606..8e43f7451 100644
--- a/maintainerr/Dockerfile
+++ b/maintainerr/Dockerfile
@@ -63,7 +63,8 @@ COPY --from=ha_tools /out/ /
# Add rootfs
COPY rootfs/ /
-RUN find /. -type f \( -name "*.sh" \) -print -exec chmod +x {} \;
+RUN chmod +x /entrypoint.sh \
+ && find /etc/cont-init.d /etc/cont-finish.d -type f -name "*.sh" -exec chmod +x {} \; 2>/dev/null || true
# Install bashio standalone
RUN BASHIO_VERSION="0.14.3" && \
diff --git a/maintainerr/config.yaml b/maintainerr/config.yaml
index 2d7a8c31f..1b5ee9802 100644
--- a/maintainerr/config.yaml
+++ b/maintainerr/config.yaml
@@ -71,7 +71,7 @@ ingress_stream: true
init: false
panel_icon: mdi:movie-search
map:
- - addon_config:rw
+ - config:rw
name: Maintainerr
options:
env_vars: []
diff --git a/maintainerr/rootfs/entrypoint.sh b/maintainerr/rootfs/entrypoint.sh
index 17cfa1d19..ba0dbe693 100644
--- a/maintainerr/rootfs/entrypoint.sh
+++ b/maintainerr/rootfs/entrypoint.sh
@@ -26,10 +26,14 @@ fi
# ─── Setup persistent data directory ─────────────────────────────────────────
# /opt/data is a Docker VOLUME in the upstream image and cannot be removed.
# Maintainerr supports the DATA_DIR env var to redirect data storage.
-DATA_DIR="/addon_configs/maintainerr"
+DATA_DIR="/config"
echo "[Maintainerr] Setting up data directory: $DATA_DIR"
mkdir -p "$DATA_DIR"
-chown -R node:node "$DATA_DIR"
+# Only chown on first run to avoid slow startup on large directories
+if [ ! -f "$DATA_DIR/.initialized" ]; then
+ chown -R node:node "$DATA_DIR"
+ touch "$DATA_DIR/.initialized"
+fi
export DATA_DIR
# ─── Start Maintainerr as unprivileged node user ─────────────────────────────
From 2c0c0089a358653f4599ef17f0b525775172b9f3 Mon Sep 17 00:00:00 2001
From: Alexandre <44178713+alexbelgium@users.noreply.github.com>
Date: Fri, 6 Mar 2026 10:38:55 +0100
Subject: [PATCH 3/5] Update config.yaml
---
maintainerr/config.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/maintainerr/config.yaml b/maintainerr/config.yaml
index 1b5ee9802..2d7a8c31f 100644
--- a/maintainerr/config.yaml
+++ b/maintainerr/config.yaml
@@ -71,7 +71,7 @@ ingress_stream: true
init: false
panel_icon: mdi:movie-search
map:
- - config:rw
+ - addon_config:rw
name: Maintainerr
options:
env_vars: []
From 82418264a82c7977e66c071410b94289192d1bc8 Mon Sep 17 00:00:00 2001
From: Alexandre <44178713+alexbelgium@users.noreply.github.com>
Date: Fri, 6 Mar 2026 10:40:18 +0100
Subject: [PATCH 4/5] Add 99-run.sh to cont-init.d directory
---
maintainerr/rootfs/{entrypoint.sh => etc/cont-init.d/99-run.sh} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename maintainerr/rootfs/{entrypoint.sh => etc/cont-init.d/99-run.sh} (100%)
diff --git a/maintainerr/rootfs/entrypoint.sh b/maintainerr/rootfs/etc/cont-init.d/99-run.sh
similarity index 100%
rename from maintainerr/rootfs/entrypoint.sh
rename to maintainerr/rootfs/etc/cont-init.d/99-run.sh
From f555f14dc7ec594829304a6fcedfdafa32e6152b Mon Sep 17 00:00:00 2001
From: Alexandre <44178713+alexbelgium@users.noreply.github.com>
Date: Fri, 6 Mar 2026 10:41:01 +0100
Subject: [PATCH 5/5] Update Dockerfile
---
maintainerr/Dockerfile | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/maintainerr/Dockerfile b/maintainerr/Dockerfile
index 8e43f7451..7be52aa33 100644
--- a/maintainerr/Dockerfile
+++ b/maintainerr/Dockerfile
@@ -89,7 +89,8 @@ ADD "https://raw.githubusercontent.com/alexbelgium/hassio-addons/master/.templat
RUN chmod 0755 /usr/local/lib/bashio-standalone.sh
# Use our wrapper as entrypoint (replaces original /opt/app/start.sh)
-ENTRYPOINT ["/entrypoint.sh"]
+ENTRYPOINT [ "/usr/bin/env" ]
+CMD [ "/ha_entrypoint.sh" ]
############
# 5 Labels #