# Contributing ## Setup ```sh uv sync ``` Python 3.13. `onnxruntime` has no Python 3.14 wheels for Intel Macs, and none at all after 1.23, so Intel Macs stay on `onnxruntime` 1.23 while Linux and the image get the latest. ## Run it locally Put your settings in `.env` (ignored by git), then: ```sh set -a && . ./.env && set +a DATA_DIR=./data uv run posteryard preview "The Office" DATA_DIR=./data uv run posteryard serve ``` `preview` never writes to the server. Keep `DRY_RUN=true` for `serve` unless you test uploads on a server you own. To run the checks before each commit and the tests before each push: ```sh uvx pre-commit install --hook-type pre-commit --hook-type pre-push ``` ## How it fits together A title goes through these modules in order: | Module | Job | | --- | --- | | `service.py` | Webhook server, sweep, daily full pass and the work queue. | | `worker.py` | Handles one item: labels, overrides, plans, upload or preview, failures and alerts. | | `pipeline.py` | Plans the images for one item and fingerprints each plan before anything is drawn. | | `settings.py`, `sources.py`, `measures.py` | What a plan reads: the settings, art and metadata from TMDB, fanart.tv and Apple TV, and measurements of art and logos saved in `state.db`. `pipeline.Context` holds one of each. | | `artwork.py`, `ocr.py` | Choose TMDB art and logos; reject art with printed text. | | `render/` | Draw the designs: `designs.py` composes, `category.py` draws collection tiles, `lines.py` places the lines under the logo, `badges.py` and `layers.py` draw parts. `layers.font_for` picks a fallback font for scripts Inter lacks. | | `store.py` | SQLite state: what was uploaded, overrides, cached art choices. | | `plex.py`, `jellyfin.py` | The media servers, behind the `MediaServer` protocol in `server.py`. Jellyfin and Emby (`jellyfin.py`) answer with Plex-shaped items. | | `tmdb.py`, `maintainerr.py`, `notify.py`, `http.py` | Outside services. Every request goes through `http.request`, which redacts credentials. | | `services.py`, `automarks.py` | Streaming marks: built-in marks first, then TMDB network logos matched through `assets/networks.json` (and `assets/provider_networks.json` for a service with no network in the region), then a cut of the provider icon. | | `cli.py`, `config.py` | Commands and settings. | | `livetv.py` | Live TV: reads the guide from Plex or Jellyfin (`GuideServer` in `server.py`), matches titles on TMDB, uploads guide posters and selects them again after a guide refresh. `render/livetv.py` draws the title, frosted and guide picture cards, and puts the channel logo in the corner of TMDB posters. | | `why.py` | The `why` command: checks a poster's art candidates again and names the reason for each. | | `logfmt.py` | The log format and the startup block. | Log a short fixed message and put the values in `extra`: `log.info("poster uploaded", extra={"title": name})`. Keys must not be `LogRecord` attribute names, such as `name`, `module` or `thread`: logging raises `KeyError`. ## Scripts in `tools/` | Script | Job | Needs | | --- | --- | --- | | `build_marks.py` | Turns `assets/marks-src` into the white marks in `src/posteryard/assets/marks`. | | | `build_fonts.py` | Fetches the fallback fonts for scripts Inter lacks. | Internet | | `build_networks.py` | Rebuilds `assets/networks.json` and `assets/provider_networks.json` from TMDB. | `TMDB_API_KEY` | | `ocr_readings.py` | Adds real OCR readings to `tests/ocr_readings.json`. | `TMDB_API_KEY` | | `unraid_template.py` | Writes the settings help and `` in `templates/posteryard.xml` from `README.md` and `CHANGELOG.md`. `--check` exits 1 when the settings are out of date. | | | `dockerhub_description.py` | Prints `README.md` as the Docker Hub overview. | | Run each with `uv run python tools/