- Go 93.2%
- HTML 4.1%
- CSS 2.3%
- Dockerfile 0.4%
| .forgejo/workflows | ||
| api | ||
| cmd | ||
| internal | ||
| .dockerignore | ||
| .gitignore | ||
| Dockerfile | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| README.md | ||
zeleerr
A one-page front for the family in front of Seerr, Radarr and Sonarr: search for a movie or a series, request it, and watch the download queue. It has no sign-in of its own and trusts a header set by the authenticating proxy in front of it.
How it works
- The signed-in user's email comes from a request header,
X-Auth-Request-Emailby default, as oauth2-proxy sets it with--set-xauthrequest. A request without it gets 401. - Each email is matched to a Seerr user. If Seerr has none, zeleerr creates a local one
and gives it the permissions in
ZELEERR_PERMISSIONS; a user Seerr already has keeps its own. - A request goes to Seerr on behalf of that user. A series is requested with every season.
- The queue is read from Radarr and Sonarr directly. A series' episodes are folded into one entry per season. Below the downloads come the requests Seerr is still processing with nothing downloading yet.
- The page speaks Russian, or C, its untranslated English, to anyone asking for another
language; it names movies and series in that language where TMDB has the name. The
language is the one picked on the page, kept in a cookie, else the
localeclaim of the person's OpenID Connect profile, else the browser'sAccept-Language. Each movie and series links to its page in Seerr. - With
ZELEERR_OIDC_ISSUERset, the page shows the person's name and picture from the provider's userinfo, asked with the access token the proxy passes on.
Run it
SEERR_URL=http://seerr:5055 SEERR_API_KEY=... \
RADARR_URL=http://radarr:7878 RADARR_API_KEY=... \
SONARR_URL=http://sonarr:8989 SONARR_API_KEY=... \
go run ./cmd/zeleerr
The image is sarak.sh/arr/zeleerr, built by .forgejo/workflows/ci.yaml on
Forgejo Actions at https://forge.sarak.sh/arr/zeleerr: every push to main
is tagged main-<sha>-<unix time>, and a vX.Y.Z tag X.Y.Z.
Configuration
| Variable | Default | Meaning |
|---|---|---|
SEERR_URL, SEERR_API_KEY |
Seerr, without /api/v1 |
|
SEERR_PUBLIC_URL |
SEERR_URL |
Seerr as the browser reaches it, for links |
RADARR_URL, RADARR_API_KEY |
Radarr | |
SONARR_URL, SONARR_API_KEY |
Sonarr | |
ZELEERR_ADDR |
:8080 |
listen address |
ZELEERR_USER_HEADER |
X-Auth-Request-Email |
header carrying the user's email |
ZELEERR_OIDC_ISSUER |
OpenID Connect issuer for names, pictures and locales; without it people are shown by email | |
ZELEERR_TOKEN_HEADER |
X-Forwarded-Access-Token |
header carrying the access token, as oauth2-proxy sets it with --pass-access-token |
ZELEERR_PERMISSIONS |
160 |
Seerr permission bits for a user zeleerr creates: REQUEST and AUTO_APPROVE |
/healthz answers without the header.
seerr-gate
The image also carries /seerr-gate, a reverse proxy that serves Seerr's own pages to
people the authenticating proxy has signed in, without a sign-in of Seerr's. It keeps a
Seerr session for each email and puts it on their requests; the browser never holds one.
It signs in as the local Seerr user of that email with the password
HMAC-SHA256(GATE_KEY, email), and sets that password through the API, creating the
user if Seerr has none, when the sign-in fails. Seerr wants the current password to
change the API key owner's own, so a new GATE_KEY needs that user's password reset by
hand.
| Variable | Default | Meaning |
|---|---|---|
SEERR_URL, SEERR_API_KEY |
Seerr, without /api/v1, and a key with MANAGE_USERS |
|
GATE_KEY |
key the passwords derive from | |
GATE_ADDR |
:8081 |
listen address |
GATE_USER_HEADER |
X-Forwarded-Email |
header carrying the user's email |
GATE_PERMISSIONS |
160 |
Seerr permission bits for a user the gate creates |
/_gate/healthz answers without the header.
torznab-years
The image also carries /torznab-years, a reverse proxy to Prowlarr for Sonarr. TheTVDB,
and Sonarr with it, titles a series "Dark Matter (2024)" when another series shares the
name, while RuTracker titles its releases "Темная материя / Dark Matter / S2E1-7 of 10
[2026, ...]": no year by the name, and the year in the tags is the season's. Sonarr
rejects such releases as an unknown series. In Torznab search answers the proxy replaces
the name with Sonarr's title, taking, of the series of that name, the one with the latest
year not after the year in the tags. Series titled without a year are left alone, and
everything but search answers passes through. Point Sonarr's indexers at it through the
Prowlarr Server URL of the Sonarr application in Prowlarr.
| Variable | Default | Meaning |
|---|---|---|
PROWLARR_URL |
Prowlarr | |
SONARR_URL, SONARR_API_KEY |
Sonarr, for its series | |
YEARS_ADDR |
:9696 |
listen address |
YEARS_REFRESH |
10m |
how often the series are fetched again |
/_years/healthz answers itself.
Development
The API clients in internal/{seerr,radarr,sonarr} are generated by
oapi-codegen from the specs in api/:
go generate ./...
go test ./...
License
MIT