diff --git a/README.md b/README.md index c648808d..b76422ea 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,7 @@ Every stack starts from the same [standard setup](documentation/standard-setup.m | **Configarr** | Tool that applies YAML settings and TRaSH Guides profiles to Radarr and Sonarr, then exits. | [Details](services/configarr) | | **FreshRSS** | Feed reader for RSS and Atom, with themes, extensions, and no separate database server. | [Details](services/freshrss) | | **Hytale** | Hytale game server in a community image, for players on your Tailnet. | [Details](services/hytale) | +| **ImageMaid** | Cleaner that removes unused poster and background images from the Plex metadata folder. | [Details](services/imagemaid) | | **Immich** | Photo and video library that backs up mobile media, with search and sharing. | [Details](services/immich) | | **Jellyfin** | Media server that organizes and streams your movies, series, and music. | [Details](services/jellyfin) | | **Kavita** | Digital library for comics, manga, and books, with progress synced across devices. | [Details](services/kavita) | diff --git a/services/imagemaid/.env b/services/imagemaid/.env new file mode 100644 index 00000000..3fa0a8ff --- /dev/null +++ b/services/imagemaid/.env @@ -0,0 +1,33 @@ +#URL=https://github.com/tailscale-dev/ScaleTail +# To run a second copy, copy the folder under another name and change SERVICE. + +# Service Configuration +# Service name (e.g., adguard). Used as hostname in Tailscale and for container naming. +SERVICE=imagemaid +# Docker image URL from container registry (e.g., adguard/adguardhome:latest). +IMAGE_URL=kometateam/imagemaid:latest + +# Network Configuration +# Preferred DNS server for Tailscale. Uncomment the "dns:" section in compose.yaml to enable. +DNS_SERVER=9.9.9.9 + +# Tailscale Configuration +# Auth key from https://console.tailscale.com/admin/settings/keys. See: https://tailscale.com/kb/1085/auth-keys#generate-an-auth-key for instructions. +TS_AUTHKEY= + +# Time Zone setting for containers. See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones +TZ=Europe/Amsterdam + +# Any Container environment variables are declared below. See https://docs.docker.com/compose/how-tos/environment-variables/ + +# Folder of your Plex server data on this host, the one that contains the Cache, Metadata, and Plug-in Support folders. +# The default is the folder of the Plex stack of this repository. Change it when Plex runs elsewhere. +PLEX_DATA_DIR=../plex/plex-data/config/Library/Application Support/Plex Media Server +# What ImageMaid does with unused images: report (only list them), move (move them to a restore folder), or remove (delete them). +MODE=report +# When ImageMaid runs, as time|frequency, for example 05:00|weekly(sunday). Keep it set: ImageMaid runs once and exits when it is empty. +SCHEDULE=05:00|weekly(sunday) +# Address of your Plex server, for example http://100.64.0.1:32400. Leave empty, together with PLEX_TOKEN, to read the Plex database from PLEX_DATA_DIR. +PLEX_URL= +# Plex token. Leave empty to read the Plex database from PLEX_DATA_DIR. See: https://support.plex.tv/articles/204059436-finding-an-authentication-token-x-plex-token/ +PLEX_TOKEN= diff --git a/services/imagemaid/README.md b/services/imagemaid/README.md new file mode 100644 index 00000000..6509c67e --- /dev/null +++ b/services/imagemaid/README.md @@ -0,0 +1,57 @@ +# ImageMaid + +[ImageMaid](https://github.com/Kometa-Team/ImageMaid) removes unused poster and background images from the metadata folder of a Plex server, for example after you stop using Kometa overlays. It can also clean the photo transcoder cache, empty the trash, clean bundles, and optimize the database. + +This stack runs ImageMaid with a Tailscale sidecar, as described in [the standard setup](../../documentation/standard-setup.md). + +## At a glance + +| Item | Value | +| ------------- | ------------------------------------------------------------------------- | +| Web interface | None | +| Image | `kometateam/imagemaid:latest` | +| Data | `./imagemaid-data/config` (logs and the copy of the Plex database) | +| | `PLEX_DATA_DIR` in `.env` (the Plex data folder, mounted at `/plex`) | + +## Before you start + +ImageMaid changes files in the Plex data folder, so it must run on the host that holds that folder. + +- **Plex data folder.** `PLEX_DATA_DIR` in `.env` must point to the folder of your Plex server that contains `Cache`, `Metadata`, and `Plug-in Support`. The default is the folder of the [Plex stack](../plex/README.md) in this repository. Change it when Plex runs elsewhere. Compose stops with an error when the folder does not exist. +- **Schedule.** Keep `SCHEDULE` set in `.env`. When it is empty, ImageMaid runs once and exits, and `restart: always` then starts it again at once, over and over. +- **Mode.** `MODE=report` only lists the images that ImageMaid would remove. Check the list in the log, then set `MODE=move` to move them to an `ImageMaid Restore` folder, which you can restore. `MODE=remove` deletes them for good. +- **Plex access.** ImageMaid needs the Plex database to know which images are in use. Set `PLEX_URL` and `PLEX_TOKEN` to download it through the Plex API, or leave both empty to copy it from `PLEX_DATA_DIR`. Upstream recommends restarting Plex and keeping it idle before a copy. + +## Deviations from the standard setup + +- **No web interface.** The stack has no Tailscale Serve configuration, no `./config` folder, and no `ports` block. ImageMaid only makes outgoing connections: to Plex, and to Discord or Gotify when you set them up. +- **Plex data folder outside the stack.** The Plex data folder is mounted from `PLEX_DATA_DIR` instead of from `./imagemaid-data`, because ImageMaid works on the files of Plex. The mount fails when the folder is missing, so Docker does not create an empty one. +- **Runs as root.** The image has no `user` setting and runs as root, as upstream documents. Files that ImageMaid creates in `./imagemaid-data/config` belong to root. +- **Health check.** The image has no health check and no `pgrep`, so the check looks for the `python3` process, which is ImageMaid. + +## First run + +1. Start the stack. ImageMaid does not run at once. The log shows the schedule: + + ```bash + docker compose logs application + ``` + +2. To reach Plex over your Tailnet, for example the Plex stack of this repository, set `PLEX_URL` to the Tailscale IP address of the Plex device, such as `http://100.64.0.1:32400`. To use its MagicDNS name instead, uncomment `TS_ACCEPT_DNS=true` in `compose.yaml`, as described in the [DNS section of the standard setup](../../documentation/standard-setup.md#dns). +3. To run ImageMaid right away, in the mode set in `.env`: + + ```bash + docker exec -e SCHEDULE= app-imagemaid /tini -s python3 /imagemaid.py + ``` + + Stop Kometa and TitleCardMaker first, and run ImageMaid after the Plex scheduled tasks, as upstream advises. + +## Configuration + +`MODE`, `SCHEDULE`, `PLEX_URL`, and `PLEX_TOKEN` are the only options that `compose.yaml` passes on. ImageMaid reads every other option, such as `PHOTO_TRANSCODER`, `EMPTY_TRASH`, `CLEAN_BUNDLES`, `OPTIMIZE_DB`, `OVERLAYS_ONLY`, `DISCORD`, and the Gotify settings, from a file `.env` in `./imagemaid-data/config`. Environment variables take priority over that file. The [options](https://kometa.wiki/en/latest/kometa/scripts/imagemaid/) are described upstream. + +## Links + +- [ImageMaid documentation](https://kometa.wiki/en/latest/kometa/scripts/imagemaid/) +- [ImageMaid source code](https://github.com/Kometa-Team/ImageMaid) +- [ImageMaid on Docker Hub](https://hub.docker.com/r/kometateam/imagemaid) diff --git a/services/imagemaid/compose.yaml b/services/imagemaid/compose.yaml new file mode 100644 index 00000000..f200f9c7 --- /dev/null +++ b/services/imagemaid/compose.yaml @@ -0,0 +1,63 @@ +services: +# Make sure you have updated/checked the .env file with the correct variables. +# Every variable used in this file must be defined there, unless it has a default such as ${VAR:-value}. + # Tailscale Sidecar Configuration + tailscale: + image: tailscale/tailscale:latest # Image to be used + container_name: tailscale-${SERVICE} # Name for local container management + hostname: ${SERVICE} # Name used within your Tailscale environment + environment: + - TS_AUTHKEY=${TS_AUTHKEY} + - TS_STATE_DIR=/var/lib/tailscale + - TS_USERSPACE=false + - TS_ENABLE_HEALTH_CHECK=true # Enable healthcheck endpoint: "/healthz" + - TS_LOCAL_ADDR_PORT=127.0.0.1:41234 # The : for the healthz endpoint + #- TS_ACCEPT_DNS=true # Uncomment only if the service must resolve MagicDNS names - this replaces Docker DNS, so Compose service names no longer resolve + - TS_AUTH_ONCE=true + volumes: + - ./ts/state:/var/lib/tailscale # Tailscale requirement - you may need to change the path + devices: + - /dev/net/tun:/dev/net/tun # Network configuration for Tailscale to work + cap_add: + - net_admin # Tailscale requirement + # If any DNS issues arise, use your preferred DNS provider by uncommenting the config below + #dns: + # - ${DNS_SERVER} + healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://127.0.0.1:41234/healthz"] # Check Tailscale has a Tailnet IP and is operational + interval: 1m # How often to perform the check + timeout: 10s # Time to wait for the check to succeed + retries: 3 # Number of retries before marking as unhealthy + start_period: 10s # Time to wait before starting health checks + restart: always + + # Application + application: + image: ${IMAGE_URL} # Image to be used + network_mode: service:tailscale # Sidecar configuration to route the service through Tailscale + container_name: app-${SERVICE} # Name for local container management + environment: # Variables are declared in .env file. + - TZ=${TZ} + - MODE=${MODE} + - SCHEDULE=${SCHEDULE} + - PLEX_URL=${PLEX_URL} + - PLEX_TOKEN=${PLEX_TOKEN} + volumes: + - ./${SERVICE}-data/config:/config + - type: bind # Plex data folder with the Cache, Metadata, and Plug-in Support folders + source: ${PLEX_DATA_DIR} + target: /plex + bind: + create_host_path: false # Fail when the folder is missing, so Docker does not create an empty one + depends_on: + tailscale: + condition: service_healthy + # Healthcheck: the image has no HEALTHCHECK, no endpoint, and no pgrep. ImageMaid is the only python3 process + # in the container, so check for python3 with pidof. + healthcheck: + test: ["CMD", "pidof", "python3"] # Check if ImageMaid is running and waiting for its schedule + interval: 1m # How often to perform the check + timeout: 10s # Time to wait for the check to succeed + retries: 3 # Number of retries before marking as unhealthy + start_period: 30s # Time to wait before starting health checks + restart: always # Without SCHEDULE, ImageMaid runs once and exits, and Docker would start it again at once.