From b36f42a7b99d8331d1286ba87a9f786309f1da39 Mon Sep 17 00:00:00 2001 From: Jan Schaufuss Date: Fri, 15 Aug 2025 13:27:29 +0200 Subject: [PATCH] prettier README / better duplicated notification handling --- .gitignore | 3 +- README.md | 134 +++++++++++++++++++++++++++++++++++++++ arr_api/notifications.py | 8 +-- 3 files changed, 140 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 46c76b2..437dd60 100644 --- a/.gitignore +++ b/.gitignore @@ -69,7 +69,8 @@ staticfiles/ media/ # Database -/db.sqlite3 +.data/ +data/ # Environment files .env.local diff --git a/README.md b/README.md index 663328b..70cabe7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,139 @@ # Subscribarr +

+ License MIT + Python 3.13 + Django 5 + Docker ready + ntfy supported + Apprise supported +

+ + + +Ein leichtgewichtiges Web‑Frontend für Benachrichtigungen und Abos rund um Sonarr/Radarr – mit Jellyfin‑Login, Kalender, Abo‑Verwaltung und flexiblen Notifications per E‑Mail, ntfy und Apprise. + +## Features +- Jellyfin‑Login (kein eigener Userstore nötig) +- Kalender im Sonarr/Radarr‑Stil (kommende Episoden/Filme) +- Abonnieren/Abbestellen direkt aus dem UI (Serien & Filme) +- Admin‑Übersicht aller Abos je Nutzer inkl. Poster +- Benachrichtigungen pro Nutzer wählbar: + - E‑Mail (SMTP) + - ntfy (Token oder Basic Auth) + - Apprise (zahlreiche Ziele wie Discord, Gotify, Pushover, Webhooks u. v. m.) +- Docker‑fertig, env‑gesteuerte Security‑Settings (ALLOWED_HOSTS, CSRF, Proxy) + +## Schnellstart + +## Screenshots +

+ Screenshot 1
+ Screenshot 2
+ Screenshot 3
+ Screenshot 4
+ Screenshot 5
+ Screenshot 6 +

+ +### Mit Docker Compose +1) Lockfile aktuell halten (wenn `Pipfile` geändert wurde): +```bash +pipenv lock +``` +2) Image bauen/Starten: +```bash +docker compose build +docker compose up -d +``` +3) Öffne die App und führe das First‑Run‑Setup (Jellyfin + Arr‑URLs/Keys) durch. + +Wichtige Umgebungsvariablen (Beispiele): +- `DJANGO_ALLOWED_HOSTS=subscribarr.example.com,localhost,127.0.0.1` +- `DJANGO_CSRF_TRUSTED_ORIGINS=https://subscribarr.example.com,http://subscribarr.example.com` +- Reverse‑Proxy/TLS: + - `USE_X_FORWARDED_HOST=true` + - `DJANGO_SECURE_PROXY_SSL_HEADER=true` + - `DJANGO_CSRF_COOKIE_SECURE=true` + - `DJANGO_SESSION_COOKIE_SECURE=true` + +> Hinweis: In `DJANGO_CSRF_TRUSTED_ORIGINS` muss Schema+Host (und ggf. Port) exakt stimmen. + +### Lokal (Pipenv) +```bash +pipenv sync +pipenv run python manage.py migrate +pipenv run python manage.py runserver +``` + +## Konfiguration im UI +- Einstellungen → Jellyfin: Server‑URL + API‑Key +- Einstellungen → Sonarr/Radarr: Base‑URLs + API‑Keys (inkl. „Test“-Knopf) +- Einstellungen → Mailserver: SMTP (Host/Port/TLS/SSL/Benutzer/Passwort/From) +- Einstellungen → Notifications: + - ntfy: Server‑URL, Default‑Topic, Basic‑Auth oder Bearer‑Token + - Apprise: Default‑URL(s) (eine pro Zeile) +- Profil (pro Nutzer): + - Kanal wählen: E‑Mail, ntfy oder Apprise + - ntfy Topic (optional, überschreibt Default) + - Apprise URL(s) (optional, ergänzen die Defaults) + +## ntfy – Hinweise +- Server‑URL: z. B. `https://ntfy.sh` oder eigener Server +- Auth: + - Bearer‑Token (Header) + - Basic‑Auth (Benutzer/Passwort) +- Topic: + - pro Nutzer frei wählbar (Profil) oder globales Default‑Topic (Einstellungen) + +## Apprise – Hinweise +- Trag eine oder mehrere Ziel‑URLs ein (pro Zeile), z. B.: + - `gotify://TOKEN@gotify.example.com/` + - `discord://webhook_id/webhook_token` + - `mailto://user:pass@smtp.example.com` + - `pover://user@token` + - `json://webhook.example.com/path` +- Nutzer können eigene URLs ergänzen; die globalen Defaults bleiben zusätzlich aktiv. + +## Benachrichtigungslogik +- Serien: Es wird pro Abo am Release‑Tag geprüft, ob die Episode bereits als Datei vorhanden ist (Sonarr `hasFile`). +- Filme: Analog über Radarr `hasFile` und Release‑Datum (Digital/Disc/Kino‐Tag). +- Doppelversand wird per `SentNotification` unterdrückt (täglich pro Item/Nutzer). +- Fallback: Wenn ntfy/Apprise scheitern, wird E‑Mail versendet (falls konfiguriert). + +## Jobs / Manuell anstoßen +- Regelmäßiger Check per Management Command (z. B. via Cron): +```bash +pipenv run python manage.py check_new_media +``` +- In Docker: +```bash +docker compose exec web python manage.py check_new_media +``` + +## Sicherheit & Proxy +- Setze `DJANGO_ALLOWED_HOSTS` auf deine(n) Hostnamen. +- Füge alle genutzten Ursprünge in `DJANGO_CSRF_TRUSTED_ORIGINS` hinzu (http/https und Port beachten). +- Hinter Reverse‑Proxy TLS aktivieren: `USE_X_FORWARDED_HOST`, `DJANGO_SECURE_PROXY_SSL_HEADER`, Cookie‑Flags. + +## Tech‑Stack +- Backend: Django 5 + DRF +- Integrationen: Sonarr/Radarr (API v3) +- Auth: Jellyfin +- Notifications: SMTP, ntfy (HTTP), Apprise +- Frontend: Templates + FullCalendar +- DB: SQLite (default) + +## Lizenz +MIT +# Subscribarr + # Subscribarr Subscribarr is a notification tool for the *Arr ecosystem (Sonarr, Radarr) and Jellyfin. Users can subscribe to shows/movies; when new episodes/releases are available (and actually present), Subscribarr sends email notifications. diff --git a/arr_api/notifications.py b/arr_api/notifications.py index 5092913..4c4a5cf 100644 --- a/arr_api/notifications.py +++ b/arr_api/notifications.py @@ -361,9 +361,9 @@ def check_and_notify_users(): html = render_to_string('arr_api/email/new_media_notification.html', ctx) except Exception: pass - _dispatch_user_notification(sub.user, subject=subj, body_text=body, html_message=html) + ok = _dispatch_user_notification(sub.user, subject=subj, body_text=body, html_message=html) # mark as sent unless duplicates are allowed - if not getattr(settings, 'NOTIFICATIONS_ALLOW_DUPLICATES', False): + if ok and not getattr(settings, 'NOTIFICATIONS_ALLOW_DUPLICATES', False): SentNotification.objects.create( user=sub.user, media_id=sub.series_id, @@ -423,8 +423,8 @@ def check_and_notify_users(): html = render_to_string('arr_api/email/new_media_notification.html', ctx) except Exception: pass - _dispatch_user_notification(sub.user, subject=subj, body_text=body, html_message=html) - if not getattr(settings, 'NOTIFICATIONS_ALLOW_DUPLICATES', False): + ok = _dispatch_user_notification(sub.user, subject=subj, body_text=body, html_message=html) + if ok and not getattr(settings, 'NOTIFICATIONS_ALLOW_DUPLICATES', False): SentNotification.objects.create( user=sub.user, media_id=sub.movie_id,