mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-09-27 11:53:59 +02:00
feat(kapowarr): new add-on with Home Assistant ingress support (#2999)
* feat(kapowarr): new add-on with Home Assistant ingress support Kapowarr is a comic book library manager in the *arr family. The add-on is built on the upstream image (mrcas/kapowarr), with the repository's standard nginx ingress scaffolding on top. Ingress uses the pattern komga and bazarr already use here: Kapowarr renders absolute urls from its url base, Home Assistant strips its own ingress prefix before forwarding, so Kapowarr is started with --UrlBase /kapowarr and nginx rewrites that fixed prefix back onto the ingress entry. Database and logs go to the add-on configuration directory. Temporary downloads are symlinked there rather than passed with --TempDownloadFolder, which upstream re-applies on its own restarts and would keep overwriting a folder chosen in Settings > Download. * fix(kapowarr): review fixes from the codex pass - repair a /app/temp_downloads symlink pointing at the wrong target instead of accepting any symlink - exclude logs and temporary downloads from Home Assistant backups: the temp folder now lives in the add-on config directory and can hold gigabytes - fix the /dev/nvme2n3p3 typo inherited from the copied device list (the partition is nvme2n1p3); the same typo is present in the other add-ons - document that the url base must not be changed, and that a non-zero PUID only reaches folders that user can already access - drop three dead Dockerfile lines (BASHIO_VERSION is overridden inside ha_automatic_packages.sh, USER root is a no-op on this image) * fix(kapowarr): pin host and port too, not just the url base Found by a Codex review that could read the upstream source. Kapowarr stores host, port and url base in its database and reads the stored value whenever the matching flag is absent. Only --UrlBase was passed, so a host or port changed in Settings > General survived every restart and upgrade while nginx and the healthcheck stayed pointed at 127.0.0.1:5656 -- a permanent 502 with no way back except editing the database by hand. All three flags are startup-only upstream, so passing them re-applies the add-on's values once per container start without fighting the self-restarts Kapowarr performs after a settings change.
This commit is contained in:
10
kapowarr/CHANGELOG.md
Normal file
10
kapowarr/CHANGELOG.md
Normal file
@@ -0,0 +1,10 @@
|
||||
## 1.3.1 (19-08-2026)
|
||||
|
||||
- Initial release, based on upstream Kapowarr 1.3.1
|
||||
- Home Assistant ingress support: Kapowarr is started with `--UrlBase /kapowarr` and nginx rewrites
|
||||
that prefix onto the ingress path, so the sidebar panel works without any user configuration
|
||||
- The host, port and URL base are re-applied on every start, so a hosting setting changed by hand
|
||||
in the web interface is repaired by restarting the add-on rather than breaking it permanently
|
||||
- Database and logs stored in the add-on configuration directory, so they survive updates
|
||||
- Temporary downloads redirected to persistent storage (`/config/temp_downloads`)
|
||||
- `PUID`/`PGID`, `TZ`, `env_vars`, local disk and SMB share mounting supported
|
||||
112
kapowarr/Dockerfile
Normal file
112
kapowarr/Dockerfile
Normal file
@@ -0,0 +1,112 @@
|
||||
#============================#
|
||||
# ALEXBELGIUM'S DOCKERFILE #
|
||||
#============================#
|
||||
# _.------.
|
||||
# _.-` ('>.-`"""-.
|
||||
# '.--'` _'` _ .--.)
|
||||
# -' '-.-';` `
|
||||
# ' - _.' ``'--.
|
||||
# '---` .-'""`
|
||||
# /`
|
||||
#=== Home Assistant Addon ===#
|
||||
|
||||
#################
|
||||
# 1 Build Image #
|
||||
#################
|
||||
|
||||
ARG BUILD_FROM
|
||||
ARG BUILD_VERSION
|
||||
ARG BUILD_UPSTREAM="1.3.1"
|
||||
FROM ${BUILD_FROM}
|
||||
|
||||
##################
|
||||
# 2 Modify Image #
|
||||
##################
|
||||
|
||||
# No S6_* tuning here : the upstream image is a plain python:slim image with no
|
||||
# s6-overlay, so the vars the other addons set would be read by nobody
|
||||
|
||||
##################
|
||||
# 3 Install apps #
|
||||
##################
|
||||
|
||||
# Add rootfs
|
||||
# Absolute paths on purpose : the upstream image sets WORKDIR /app, so the
|
||||
# relative "find ." used by the other addons would miss /etc entirely
|
||||
COPY rootfs/ /
|
||||
RUN find /etc/cont-init.d /etc/services.d -type f \( -name "*.sh" -o -name "run" \) -print -exec chmod +x {} \;
|
||||
|
||||
# Modules
|
||||
ARG MODULES="00-banner.sh 00-global_var.sh 01-custom_script.sh 00-local_mounts.sh 00-smb_mounts.sh"
|
||||
|
||||
# Automatic modules download
|
||||
COPY ha_automodules.sh /ha_automodules.sh
|
||||
RUN chmod 744 /ha_automodules.sh && /ha_automodules.sh "$MODULES" && rm /ha_automodules.sh
|
||||
|
||||
# Manual apps
|
||||
ENV PACKAGES="nginx"
|
||||
|
||||
# Automatic apps & bashio
|
||||
COPY ha_autoapps.sh /ha_autoapps.sh
|
||||
RUN chmod 744 /ha_autoapps.sh && /ha_autoapps.sh "$PACKAGES" && rm /ha_autoapps.sh
|
||||
|
||||
################
|
||||
# 4 Entrypoint #
|
||||
################
|
||||
|
||||
# The upstream image has no s6-overlay, so ha_entrypoint runs as pid 1 : it
|
||||
# executes /etc/cont-init.d, then supervises /etc/services.d. This replaces the
|
||||
# upstream ENTRYPOINT (/app/entrypoint.sh), which is called again from
|
||||
# rootfs/etc/services.d/kapowarr/run so its PUID/PGID handling is kept
|
||||
COPY ha_entrypoint.sh /ha_entrypoint.sh
|
||||
RUN chmod 777 /ha_entrypoint.sh
|
||||
ENTRYPOINT ["/ha_entrypoint.sh"]
|
||||
|
||||
# Install bashio
|
||||
COPY bashio-standalone.sh /usr/local/lib/bashio-standalone.sh
|
||||
RUN chmod 0755 /usr/local/lib/bashio-standalone.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 #
|
||||
#################
|
||||
|
||||
# Kapowarr is hosted under the /kapowarr url base, see the addon documentation
|
||||
ENV HEALTH_PORT="5656" \
|
||||
HEALTH_URL="/kapowarr/"
|
||||
HEALTHCHECK \
|
||||
--interval=30s \
|
||||
--retries=5 \
|
||||
--start-period=120s \
|
||||
--timeout=25s \
|
||||
CMD curl -A "HealthCheck: Docker/1.0" -s -f "http://127.0.0.1:${HEALTH_PORT}${HEALTH_URL}" >/dev/null 2>&1 || exit 1
|
||||
81
kapowarr/README.md
Normal file
81
kapowarr/README.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Home Assistant Add-on: Kapowarr
|
||||
|
||||
Build and manage a comic book library, fitting in the \*arr suite of software.
|
||||
|
||||
[Kapowarr](https://casvt.github.io/Kapowarr/) tracks the volumes you own, finds the issues you are
|
||||
missing, downloads them through GetComics and your download clients, and keeps the files renamed
|
||||
and converted the way you want them.
|
||||
|
||||
## About
|
||||
|
||||
- Import an existing comic collection and match it against ComicVine metadata
|
||||
- Monitor volumes and automatically search for missing issues
|
||||
- Direct downloads and Mega links, plus torrent and Usenet clients
|
||||
- Automatic renaming, converting and file management
|
||||
|
||||
## Installation
|
||||
|
||||
1. Add this repository to Home Assistant.
|
||||
2. Install the **Kapowarr** add-on.
|
||||
3. Start the add-on and open it from the sidebar (ingress), or on port `5656` at
|
||||
`http://homeassistant:5656/kapowarr` — note the `/kapowarr` suffix, see *Ingress and URLs* below.
|
||||
4. Enter a ComicVine API key under *Settings > Metadata*; Kapowarr cannot search without one.
|
||||
5. Add a root folder under *Settings > Media Management*, for example `/media/comics` or
|
||||
`/share/comics`.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `PUID` / `PGID` | Ownership applied to the add-on configuration directory, and the user Kapowarr runs as. Defaults to `0` (root). |
|
||||
| `TZ` | Timezone, e.g. `Europe/Paris`. |
|
||||
| `localdisks` | Local disks to mount, e.g. `sda1` or a disk label. |
|
||||
| `networkdisks` | SMB shares to mount, e.g. `//192.168.1.2/comics`. Mounted under `/mnt`. |
|
||||
| `cifsusername` / `cifspassword` / `cifsdomain` | Credentials for the SMB shares. |
|
||||
| `smbv1` | Allow the legacy SMBv1 protocol. |
|
||||
| `env_vars` | Extra environment variables passed to Kapowarr. See the [wiki](https://github.com/alexbelgium/hassio-addons/wiki/Add-Environment-variables-to-your-Addon-2). |
|
||||
|
||||
Everything else — root folders, download clients, naming, the ComicVine key — is configured in
|
||||
Kapowarr's own web interface, not in the add-on options.
|
||||
|
||||
The *host*, *port* and *URL base* fields under *Settings > General* are reserved by the add-on and
|
||||
should not be changed. The add-on is built around Kapowarr listening on `0.0.0.0:5656` under the
|
||||
`/kapowarr` URL base, and it sets all three back to those values every time it starts. Changing any
|
||||
of them breaks the sidebar panel and the direct port until the next add-on restart, which repairs
|
||||
them.
|
||||
|
||||
When `PUID`/`PGID` are not `0`, Kapowarr runs as that user and can only read and write the root
|
||||
folders and download folders that user already has access to. The add-on only fixes ownership of
|
||||
its own configuration directory.
|
||||
|
||||
## Ingress and URLs
|
||||
|
||||
Kapowarr is served from the `/kapowarr` subpath so that it works behind Home Assistant ingress:
|
||||
|
||||
- from the Home Assistant sidebar: ingress, no extra setup
|
||||
- directly: `http://homeassistant:5656/kapowarr` — `http://homeassistant:5656/` on its own returns
|
||||
a 404, the subpath is not optional
|
||||
|
||||
External clients that talk to Kapowarr's API must use the direct
|
||||
`http://homeassistant:5656/kapowarr` url. Ingress is browser-session based, so they cannot
|
||||
authenticate through it.
|
||||
|
||||
## Data
|
||||
|
||||
Kapowarr's database (`Kapowarr.db`) and logs live in `/config` inside the add-on, which Home
|
||||
Assistant maps to this add-on's own configuration directory —
|
||||
`/addon_configs/<repository_id>_kapowarr`, browsable with the Filebrowser add-on. They survive
|
||||
add-on updates.
|
||||
|
||||
Temporary downloads go to `/config/temp_downloads` by default, so an interrupted download is not
|
||||
lost when the add-on restarts. That directory is on the Home Assistant data disk: if space there is
|
||||
tight, point *Settings > Download > Direct download temporary folder* at somewhere roomier such as
|
||||
`/share/kapowarr_downloads` or a disk mounted through `localdisks`.
|
||||
|
||||
Your comics themselves stay where you put them, under `/media`, `/share` or a mounted disk.
|
||||
|
||||
## Support
|
||||
|
||||
- [Kapowarr upstream project](https://github.com/Casvt/Kapowarr)
|
||||
- [Kapowarr documentation](https://casvt.github.io/Kapowarr/)
|
||||
- [Add-on repository issues](https://github.com/alexbelgium/hassio-addons/issues)
|
||||
68
kapowarr/apparmor.txt
Normal file
68
kapowarr/apparmor.txt
Normal file
@@ -0,0 +1,68 @@
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
profile kapowarr_addon flags=(attach_disconnected,mediate_deleted) {
|
||||
#include <abstractions/base>
|
||||
|
||||
capability chown,
|
||||
capability dac_override,
|
||||
capability dac_read_search,
|
||||
capability fowner,
|
||||
capability setgid,
|
||||
capability setuid,
|
||||
capability sys_chroot,
|
||||
capability sys_admin,
|
||||
file,
|
||||
signal,
|
||||
mount,
|
||||
umount,
|
||||
remount,
|
||||
network udp,
|
||||
network tcp,
|
||||
network dgram,
|
||||
network stream,
|
||||
network inet,
|
||||
network inet6,
|
||||
network netlink raw,
|
||||
network unix dgram,
|
||||
|
||||
|
||||
# Entrypoint stack
|
||||
/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 explicit allow rule for signal
|
||||
signal (receive) set=(kill,term) peer=/usr/bin/docker,
|
||||
|
||||
}
|
||||
6
kapowarr/build.json
Normal file
6
kapowarr/build.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"build_from": {
|
||||
"aarch64": "mrcas/kapowarr:v1.3.1",
|
||||
"amd64": "mrcas/kapowarr:v1.3.1"
|
||||
}
|
||||
}
|
||||
107
kapowarr/config.yaml
Normal file
107
kapowarr/config.yaml
Normal file
@@ -0,0 +1,107 @@
|
||||
arch:
|
||||
- aarch64
|
||||
- amd64
|
||||
backup_exclude:
|
||||
- "**/logs/*"
|
||||
- "**/temp_downloads/*"
|
||||
description: Comic book library manager, fitting in the *arr suite of software
|
||||
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/nvme2n1p3
|
||||
- /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/kapowarr-{arch}
|
||||
ingress: true
|
||||
ingress_entry: kapowarr
|
||||
init: false
|
||||
map:
|
||||
- addon_config:rw
|
||||
- media:rw
|
||||
- share:rw
|
||||
name: Kapowarr
|
||||
options:
|
||||
env_vars: []
|
||||
PGID: 0
|
||||
PUID: 0
|
||||
panel_icon: mdi:book-multiple
|
||||
ports:
|
||||
5656/tcp: 5656
|
||||
ports_description:
|
||||
5656/tcp: Web interface (path /kapowarr)
|
||||
privileged:
|
||||
- SYS_ADMIN
|
||||
- DAC_READ_SEARCH
|
||||
schema:
|
||||
env_vars:
|
||||
- name: match(^[A-Za-z0-9_]+$)
|
||||
value: str?
|
||||
PGID: int
|
||||
PUID: int
|
||||
TZ: str?
|
||||
cifsdomain: str?
|
||||
cifspassword: str?
|
||||
cifsusername: str?
|
||||
localdisks: str?
|
||||
networkdisks: str?
|
||||
smbv1: bool?
|
||||
slug: kapowarr
|
||||
udev: true
|
||||
url: https://github.com/alexbelgium/hassio-addons/tree/master/kapowarr
|
||||
version: "1.3.1"
|
||||
BIN
kapowarr/icon.png
Normal file
BIN
kapowarr/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
BIN
kapowarr/logo.png
Normal file
BIN
kapowarr/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
35
kapowarr/rootfs/etc/cont-init.d/20-config_location.sh
Executable file
35
kapowarr/rootfs/etc/cont-init.d/20-config_location.sh
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
# Kapowarr keeps its database, its logs and its temporary downloads outside the
|
||||
# image so that they survive the container being recreated.
|
||||
#
|
||||
# The database and log folders are passed on the command line (see
|
||||
# /etc/services.d/kapowarr/run). The temporary download folder is not: upstream
|
||||
# re-applies --TempDownloadFolder on every start Kapowarr makes, including the
|
||||
# self-restarts it performs after a hosting change, so passing it would keep
|
||||
# undoing a folder the user picked in Settings > Download. Symlinking upstream's
|
||||
# default onto persistent storage gives the same persistence and leaves the
|
||||
# setting itself entirely to the user.
|
||||
|
||||
CONFIG_LOCATION="/config"
|
||||
bashio::log.info "Config stored in $CONFIG_LOCATION"
|
||||
|
||||
mkdir -p "$CONFIG_LOCATION/logs" "$CONFIG_LOCATION/temp_downloads"
|
||||
|
||||
# Compared against the target rather than just testing for a symlink, so that a
|
||||
# link left pointing somewhere else -- by a future upstream image, or by hand --
|
||||
# is repaired instead of silently kept.
|
||||
if [ "$(readlink /app/temp_downloads)" != "$CONFIG_LOCATION/temp_downloads" ]; then
|
||||
rm -rf /app/temp_downloads
|
||||
ln -s "$CONFIG_LOCATION/temp_downloads" /app/temp_downloads
|
||||
fi
|
||||
|
||||
# Numbered 20- on purpose : it must sort after 00-global_var.sh, which is what
|
||||
# exports PUID/PGID from the addon options. The upstream image sets both to 0,
|
||||
# so the fallbacks only apply when the module is absent.
|
||||
# Recursive because a user raising PUID after the first run would otherwise
|
||||
# leave Kapowarr.db, its -wal/-shm sidecars and the logs owned by the previous
|
||||
# uid, which sqlite then cannot write.
|
||||
chown -R "${PUID:-0}:${PGID:-0}" "$CONFIG_LOCATION"
|
||||
17
kapowarr/rootfs/etc/cont-init.d/32-nginx_ingress.sh
Executable file
17
kapowarr/rootfs/etc/cont-init.d/32-nginx_ingress.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
#################
|
||||
# NGINX SETTING #
|
||||
#################
|
||||
declare ingress_interface
|
||||
declare ingress_port
|
||||
declare ingress_entry
|
||||
|
||||
ingress_port=$(bashio::addon.ingress_port)
|
||||
ingress_interface=$(bashio::addon.ip_address)
|
||||
ingress_entry=$(bashio::addon.ingress_entry)
|
||||
sed -i "s/%%port%%/${ingress_port}/g" /etc/nginx/servers/ingress.conf
|
||||
sed -i "s/%%interface%%/${ingress_interface}/g" /etc/nginx/servers/ingress.conf
|
||||
sed -i "s|%%ingress_entry%%|${ingress_entry}|g" /etc/nginx/servers/ingress.conf
|
||||
96
kapowarr/rootfs/etc/nginx/includes/mime.types
Normal file
96
kapowarr/rootfs/etc/nginx/includes/mime.types
Normal file
@@ -0,0 +1,96 @@
|
||||
types {
|
||||
text/html html htm shtml;
|
||||
text/css css;
|
||||
text/xml xml;
|
||||
image/gif gif;
|
||||
image/jpeg jpeg jpg;
|
||||
application/javascript js;
|
||||
application/atom+xml atom;
|
||||
application/rss+xml rss;
|
||||
|
||||
text/mathml mml;
|
||||
text/plain txt;
|
||||
text/vnd.sun.j2me.app-descriptor jad;
|
||||
text/vnd.wap.wml wml;
|
||||
text/x-component htc;
|
||||
|
||||
image/png png;
|
||||
image/svg+xml svg svgz;
|
||||
image/tiff tif tiff;
|
||||
image/vnd.wap.wbmp wbmp;
|
||||
image/webp webp;
|
||||
image/x-icon ico;
|
||||
image/x-jng jng;
|
||||
image/x-ms-bmp bmp;
|
||||
|
||||
font/woff woff;
|
||||
font/woff2 woff2;
|
||||
|
||||
application/java-archive jar war ear;
|
||||
application/json json;
|
||||
application/mac-binhex40 hqx;
|
||||
application/msword doc;
|
||||
application/pdf pdf;
|
||||
application/postscript ps eps ai;
|
||||
application/rtf rtf;
|
||||
application/vnd.apple.mpegurl m3u8;
|
||||
application/vnd.google-earth.kml+xml kml;
|
||||
application/vnd.google-earth.kmz kmz;
|
||||
application/vnd.ms-excel xls;
|
||||
application/vnd.ms-fontobject eot;
|
||||
application/vnd.ms-powerpoint ppt;
|
||||
application/vnd.oasis.opendocument.graphics odg;
|
||||
application/vnd.oasis.opendocument.presentation odp;
|
||||
application/vnd.oasis.opendocument.spreadsheet ods;
|
||||
application/vnd.oasis.opendocument.text odt;
|
||||
application/vnd.openxmlformats-officedocument.presentationml.presentation
|
||||
pptx;
|
||||
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||
xlsx;
|
||||
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||
docx;
|
||||
application/vnd.wap.wmlc wmlc;
|
||||
application/x-7z-compressed 7z;
|
||||
application/x-cocoa cco;
|
||||
application/x-java-archive-diff jardiff;
|
||||
application/x-java-jnlp-file jnlp;
|
||||
application/x-makeself run;
|
||||
application/x-perl pl pm;
|
||||
application/x-pilot prc pdb;
|
||||
application/x-rar-compressed rar;
|
||||
application/x-redhat-package-manager rpm;
|
||||
application/x-sea sea;
|
||||
application/x-shockwave-flash swf;
|
||||
application/x-stuffit sit;
|
||||
application/x-tcl tcl tk;
|
||||
application/x-x509-ca-cert der pem crt;
|
||||
application/x-xpinstall xpi;
|
||||
application/xhtml+xml xhtml;
|
||||
application/xspf+xml xspf;
|
||||
application/zip zip;
|
||||
|
||||
application/octet-stream bin exe dll;
|
||||
application/octet-stream deb;
|
||||
application/octet-stream dmg;
|
||||
application/octet-stream iso img;
|
||||
application/octet-stream msi msp msm;
|
||||
|
||||
audio/midi mid midi kar;
|
||||
audio/mpeg mp3;
|
||||
audio/ogg ogg;
|
||||
audio/x-m4a m4a;
|
||||
audio/x-realaudio ra;
|
||||
|
||||
video/3gpp 3gpp 3gp;
|
||||
video/mp2t ts;
|
||||
video/mp4 mp4;
|
||||
video/mpeg mpeg mpg;
|
||||
video/quicktime mov;
|
||||
video/webm webm;
|
||||
video/x-flv flv;
|
||||
video/x-m4v m4v;
|
||||
video/x-mng mng;
|
||||
video/x-ms-asf asx asf;
|
||||
video/x-ms-wmv wmv;
|
||||
video/x-msvideo avi;
|
||||
}
|
||||
1
kapowarr/rootfs/etc/nginx/includes/resolver.conf
Normal file
1
kapowarr/rootfs/etc/nginx/includes/resolver.conf
Normal file
@@ -0,0 +1 @@
|
||||
resolver 127.0.0.11 ipv6=off;
|
||||
56
kapowarr/rootfs/etc/nginx/nginx.conf
Normal file
56
kapowarr/rootfs/etc/nginx/nginx.conf
Normal file
@@ -0,0 +1,56 @@
|
||||
|
||||
# Run nginx in foreground.
|
||||
daemon off;
|
||||
|
||||
# This is run inside Docker.
|
||||
user root;
|
||||
|
||||
# Pid storage location.
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
# Set number of worker processes.
|
||||
worker_processes 1;
|
||||
|
||||
# Enables the use of JIT for regular expressions to speed-up their processing.
|
||||
pcre_jit on;
|
||||
|
||||
# Write error log to Hass.io add-on log.
|
||||
error_log /proc/1/fd/1 error;
|
||||
|
||||
# Load allowed environment vars
|
||||
env HASSIO_TOKEN;
|
||||
|
||||
# Load dynamic modules.
|
||||
include /etc/nginx/modules-enabled/*.conf;
|
||||
|
||||
# Max num of simultaneous connections by a worker process.
|
||||
events {
|
||||
worker_connections 512;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/includes/mime.types;
|
||||
|
||||
log_format hassio '[$time_local] $status '
|
||||
'$http_x_forwarded_for($remote_addr) '
|
||||
'$request ($http_user_agent)';
|
||||
|
||||
access_log /proc/1/fd/1 hassio;
|
||||
client_max_body_size 4G;
|
||||
default_type application/octet-stream;
|
||||
gzip on;
|
||||
keepalive_timeout 65;
|
||||
sendfile on;
|
||||
server_tokens off;
|
||||
tcp_nodelay on;
|
||||
tcp_nopush on;
|
||||
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
include /etc/nginx/includes/resolver.conf;
|
||||
|
||||
include /etc/nginx/servers/*.conf;
|
||||
}
|
||||
56
kapowarr/rootfs/etc/nginx/servers/ingress.conf
Normal file
56
kapowarr/rootfs/etc/nginx/servers/ingress.conf
Normal file
@@ -0,0 +1,56 @@
|
||||
server {
|
||||
listen %%interface%%:%%port%% default_server;
|
||||
|
||||
client_max_body_size 0;
|
||||
|
||||
# Kapowarr is mounted under the /kapowarr url base, so Werkzeug's
|
||||
# DispatcherMiddleware answers 404 at / . Home Assistant opens the ingress
|
||||
# panel at <ingress_entry>/ unless config.yaml's ingress_entry moves it, so
|
||||
# bounce / to the url base whichever way the panel was opened.
|
||||
# absolute_redirect off keeps the Location relative to the HA host instead
|
||||
# of nginx's own listen address.
|
||||
location = / {
|
||||
absolute_redirect off;
|
||||
return 302 %%ingress_entry%%/kapowarr/;
|
||||
}
|
||||
|
||||
location / {
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
proxy_connect_timeout 30m;
|
||||
proxy_send_timeout 30m;
|
||||
proxy_read_timeout 30m;
|
||||
proxy_pass http://127.0.0.1:5656;
|
||||
|
||||
# Kapowarr streams queue, task and download progress over socket.io at
|
||||
# <url_base>/api/socket.io, which must not be buffered or the UI stops
|
||||
# updating until the buffer fills
|
||||
proxy_buffering off;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
|
||||
# Werkzeug redirects /kapowarr to /kapowarr/ , and the Location it
|
||||
# produces is absolute against the upstream address nginx talks to.
|
||||
# proxy_redirect puts it back on the ingress path (the second rule
|
||||
# covers an already relative Location).
|
||||
absolute_redirect off;
|
||||
proxy_redirect http://127.0.0.1:5656/ %%ingress_entry%%/;
|
||||
proxy_redirect / %%ingress_entry%%/;
|
||||
|
||||
# Kapowarr renders every link and asset url as {{url_base}}/... and
|
||||
# general.js reads the same value back out of
|
||||
# <meta id="url_base" data-value="/kapowarr">, so rewriting the html
|
||||
# moves the whole SPA -- including its fetch() and socket.io urls --
|
||||
# onto the ingress prefix that Home Assistant strips before forwarding.
|
||||
# sub_filter cannot rewrite a compressed body, hence Accept-Encoding "".
|
||||
proxy_set_header Accept-Encoding "";
|
||||
sub_filter_once off;
|
||||
# text/html is always filtered ; the pwa manifest is added because
|
||||
# /manifest.json embeds the url base in start_url, scope, id and icons,
|
||||
# and it is served as application/manifest+json. Json is deliberately
|
||||
# not filtered : api payloads carry user file paths that must not be
|
||||
# rewritten.
|
||||
sub_filter_types application/manifest+json;
|
||||
sub_filter "/kapowarr" "%%ingress_entry%%/kapowarr";
|
||||
}
|
||||
}
|
||||
36
kapowarr/rootfs/etc/services.d/kapowarr/run
Executable file
36
kapowarr/rootfs/etc/services.d/kapowarr/run
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
# ==============================================================================
|
||||
|
||||
# Kapowarr is started through the upstream entrypoint, which is what implements
|
||||
# PUID/PGID (groupmod -o / usermod -o, then gosu). ha_entrypoint.sh replaced it
|
||||
# as the container entrypoint so that cont-init.d and nginx could run too, so it
|
||||
# is called again here rather than reimplemented. Both usermod and groupmod are
|
||||
# given -o upstream, so a PUID that collides with an existing account is not an
|
||||
# error.
|
||||
#
|
||||
# --UrlBase is what makes ingress work: Kapowarr renders absolute urls, Home
|
||||
# Assistant strips its own ingress prefix before forwarding, and nginx adds it
|
||||
# back by rewriting this fixed prefix. See rootfs/etc/nginx/servers/ingress.conf.
|
||||
#
|
||||
# --Host and --Port are passed for the same reason, even though they are already
|
||||
# the upstream defaults: all three are stored in the database, and Kapowarr reads
|
||||
# the stored value when the flag is absent. Without them, a host or port changed
|
||||
# in Settings > General would survive every restart and upgrade while nginx and
|
||||
# the healthcheck stayed pointed at 127.0.0.1:5656 -- a permanent 502 with no way
|
||||
# back except editing the database. Passing all three makes the whole hosting
|
||||
# section self repairing.
|
||||
#
|
||||
# Upstream applies these three only on a startup, never on the restarts Kapowarr
|
||||
# performs itself, so they are re-applied once per container start and do not
|
||||
# fight the user in between.
|
||||
|
||||
bashio::log.info "Starting Kapowarr (served on the /kapowarr path, see the addon documentation)"
|
||||
|
||||
exec /app/entrypoint.sh python3 /app/Kapowarr.py \
|
||||
--DatabaseFolder /config \
|
||||
--LogFolder /config/logs \
|
||||
--Host 0.0.0.0 \
|
||||
--Port 5656 \
|
||||
--UrlBase /kapowarr
|
||||
36
kapowarr/rootfs/etc/services.d/nginx/run
Executable file
36
kapowarr/rootfs/etc/services.d/nginx/run
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
# ==============================================================================
|
||||
|
||||
# Wait for Kapowarr to answer before nginx starts serving ingress. The first
|
||||
# boot creates the database and runs its migrations, so leave a wide margin, but
|
||||
# poll rather than call bashio::net.wait_for : bashio takes (port host timeout)
|
||||
# while the bundled bashio-standalone.sh takes (host port timeout), and picking
|
||||
# the wrong one would either fail instantly or block for the whole timeout.
|
||||
# The per probe timeouts keep the ceiling real : without them a half open
|
||||
# connection would hang a single probe, and the loop, forever.
|
||||
# A wall clock deadline, not an attempt count : a failed probe costs up to
|
||||
# max-time on top of the sleep, so counting attempts would stretch the wait to
|
||||
# roughly twice the advertised ceiling.
|
||||
# The probe asks for /kapowarr/ rather than / , because / is served by the empty
|
||||
# app that DispatcherMiddleware mounts beside the url base and always answers.
|
||||
kapowarr_ready=false
|
||||
deadline=$((SECONDS + 300))
|
||||
while [ "$SECONDS" -lt "$deadline" ]; do
|
||||
if curl -sf --connect-timeout 2 --max-time 5 -o /dev/null "http://127.0.0.1:5656/kapowarr/"; then
|
||||
kapowarr_ready=true
|
||||
break
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
|
||||
# Deliberately not fatal : nginx serving a 502 tells the user something is wrong
|
||||
# and starts working by itself once Kapowarr finally answers, while refusing to
|
||||
# start would take ingress down for good after ha_entrypoint gives up retrying.
|
||||
if [ "$kapowarr_ready" != true ]; then
|
||||
bashio::log.warning "Kapowarr did not answer within 5 minutes. Starting NGinx anyway : ingress will return 502 until it does."
|
||||
fi
|
||||
|
||||
bashio::log.info "Starting NGinx..."
|
||||
exec nginx
|
||||
9
kapowarr/updater.json
Normal file
9
kapowarr/updater.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"github_beta": "false",
|
||||
"last_update": "2026-08-19",
|
||||
"repository": "alexbelgium/hassio-addons",
|
||||
"slug": "kapowarr",
|
||||
"source": "github",
|
||||
"upstream_repo": "Casvt/Kapowarr",
|
||||
"upstream_version": "1.3.1"
|
||||
}
|
||||
Reference in New Issue
Block a user