diff --git a/README.md b/README.md index 8cb1be20..38826645 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,7 @@ Every stack starts from the same [standard setup](documentation/standard-setup.m | **FreshRSS** | RSS and Atom feed reader that uses SQLite, with no separate database server. | [Details](services/freshrss) | | **Fusion** | Lightweight feed reader for RSS, Atom, and JSON feeds, with a Fever API. | [Details](services/fusion) | | **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..bcfe5b49 --- /dev/null +++ b/services/imagemaid/.env @@ -0,0 +1,36 @@ +#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/ + +# Required: the Plex data folder on this host, the one that contains the Cache, Metadata, and Plug-in Support folders. The stack does not start without it. Check the path before you start, because ImageMaid works on these files. +# Plex stack of this repository: ../plex/plex-data/config/Library/Application Support/Plex Media Server +# Plex on Linux: /var/lib/plexmediaserver/Library/Application Support/Plex Media Server +# Plex on macOS: /Users//Library/Application Support/Plex Media Server +# Other installs, such as a NAS: see https://support.plex.tv/articles/202915258-where-is-the-plex-media-server-data-directory-located/ +PLEX_DATA_DIR= +# 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..43e8a9fb --- /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.** Set `PLEX_DATA_DIR` in `.env` to the folder of your Plex server that contains `Cache`, `Metadata`, and `Plug-in Support`. It has no default, and Compose stops with an error until you set it. `.env` lists the folder of the [Plex stack](../plex/README.md) in this repository and the usual paths of other installs. Compose also stops when the folder does not exist, but it cannot tell whether the folder is the right one, so check the path yourself before you start. +- **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..fb1e08d3 --- /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:?Set PLEX_DATA_DIR in .env to the Plex data folder, the one that contains Cache, Metadata, and Plug-in Support} + 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.