From f572d95bd0ec5057654ecfbba75a9f307db3a61c Mon Sep 17 00:00:00 2001 From: Barely Removable Date: Thu, 27 Aug 2026 07:51:07 -0700 Subject: [PATCH] Make the listen port configurable via PORT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit app.py's dev server and gunicorn both hardcoded 5000, which is awkward locally — macOS ControlCenter already holds that port, so the app can't bind on the dev laptop without editing source. Both now read PORT, defaulting to 5000 so EXPOSE, the compose `${HOST_PORT}:5000` mapping and the deployed container are unchanged. Read at run time rather than import time so a dev harness can assign a free port. Also tracks .claude/launch.json with autoPort set. It doesn't actually launch on this machine — the preview sandbox can't read files under ~/Desktop — so CLAUDE.md notes that running from a shell with an explicit PORT is the working local path. Co-Authored-By: Claude Opus 5 --- .claude/launch.json | 12 ++++++++++++ CLAUDE.md | 10 ++++++++++ app.py | 6 +++++- gunicorn.conf.py | 6 +++++- 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 .claude/launch.json diff --git a/.claude/launch.json b/.claude/launch.json new file mode 100644 index 0000000..7f54ad1 --- /dev/null +++ b/.claude/launch.json @@ -0,0 +1,12 @@ +{ + "version": "0.0.1", + "configurations": [ + { + "name": "arr-summary", + "runtimeExecutable": "python3", + "runtimeArgs": ["app.py"], + "port": 5000, + "autoPort": true + } + ] +} diff --git a/CLAUDE.md b/CLAUDE.md index 5d56a8f..11f6b4b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -143,6 +143,16 @@ reload alone will silently serve the cached template. And the login password comes from `LOGIN_PASSWORD`, so set it explicitly rather than hunting for the real one. +The listen port comes from `PORT` (default `5000`, matching `EXPOSE`, +`gunicorn.conf.py` and the `${HOST_PORT}:5000` compose mapping — change +all four together or none). Set it when running locally: macOS +`ControlCenter` already holds port 5000, so `python3 app.py` with no +`PORT` will fail to bind on the dev laptop. `.claude/launch.json` sets +`autoPort` so a dev harness can assign a free one, but note that on this +machine the preview sandbox can't read files under `~/Desktop` +("Operation not permitted"), so launching by name fails and running the +app from a shell on an explicit `PORT` is the working path. + ## Deployment **Target:** Unraid server, container path `/mnt/user/appdata/greendale` diff --git a/app.py b/app.py index 3dbc230..4c67e7b 100644 --- a/app.py +++ b/app.py @@ -1543,4 +1543,8 @@ def add_to_sonarr(): if __name__ == "__main__": - app.run(host="0.0.0.0", port=5000) + # PORT is read at run time, not import time, so a dev harness can hand us + # a free port. Defaults to 5000 to match EXPOSE/gunicorn and the + # `${HOST_PORT}:5000` mapping in docker-compose.yml — don't change the + # default without changing all three. + app.run(host="0.0.0.0", port=int(os.environ.get("PORT", "5000"))) diff --git a/gunicorn.conf.py b/gunicorn.conf.py index b276b64..d9322fc 100644 --- a/gunicorn.conf.py +++ b/gunicorn.conf.py @@ -1,8 +1,12 @@ # Gunicorn configuration +import os + workers = 2 # 2 workers × 4 threads = 8 concurrent requests; fewer cold-cache workers threads = 4 worker_class = "gthread" -bind = "0.0.0.0:5000" +# Defaults to 5000 to match EXPOSE, the `${HOST_PORT}:5000` mapping in +# docker-compose.yml, and app.py's own dev-server default. +bind = "0.0.0.0:" + os.environ.get("PORT", "5000") timeout = 30 # fail fast — app has its own 5s internal deadline keepalive = 5