prettier README / better duplicated notification handling
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -69,7 +69,8 @@ staticfiles/
|
||||
media/
|
||||
|
||||
# Database
|
||||
/db.sqlite3
|
||||
.data/
|
||||
data/
|
||||
|
||||
# Environment files
|
||||
.env.local
|
||||
|
134
README.md
134
README.md
@@ -1,5 +1,139 @@
|
||||
# Subscribarr
|
||||
|
||||
<p align="center">
|
||||
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License MIT"></a>
|
||||
<img src="https://img.shields.io/badge/python-3.13-blue.svg" alt="Python 3.13">
|
||||
<img src="https://img.shields.io/badge/django-5.x-092e20?logo=django&logoColor=white" alt="Django 5">
|
||||
<img src="https://img.shields.io/badge/docker-ready-2496ED?logo=docker&logoColor=white" alt="Docker ready">
|
||||
<img src="https://img.shields.io/badge/ntfy-supported-4c1" alt="ntfy supported">
|
||||
<img src="https://img.shields.io/badge/Apprise-supported-4c1" alt="Apprise supported">
|
||||
</p>
|
||||
|
||||
<!-- Optional dynamic badges (uncomment and replace OWNER/REPO / IMAGE if you want):
|
||||
<p align="center">
|
||||
<a href="https://github.com/OWNER/REPO/releases"><img src="https://img.shields.io/github/v/release/OWNER/REPO?sort=semver" alt="latest release"></a>
|
||||
<a href="https://hub.docker.com/r/OWNER/IMAGE"><img src="https://img.shields.io/docker/pulls/OWNER/IMAGE" alt="docker pulls"></a>
|
||||
<a href="https://github.com/OWNER/REPO/commits/main"><img src="https://img.shields.io/github/commit-activity/m/OWNER/REPO" alt="commit activity"></a>
|
||||
</p>
|
||||
-->
|
||||
|
||||
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
|
||||
<p align="center">
|
||||
<img src="./screenshots/SCR-20250811-lfrm.png" alt="Screenshot 1" width="800"><br/>
|
||||
<img src="./screenshots/SCR-20250811-lfvc.png" alt="Screenshot 2" width="800"><br/>
|
||||
<img src="./screenshots/SCR-20250811-lfod.png" alt="Screenshot 3" width="800"><br/>
|
||||
<img src="./screenshots/SCR-20250811-lfyq.png" alt="Screenshot 4" width="800"><br/>
|
||||
<img src="./screenshots/SCR-20250811-lgau.png" alt="Screenshot 5" width="800"><br/>
|
||||
<img src="./screenshots/SCR-20250811-lgcz.png" alt="Screenshot 6" width="800">
|
||||
</p>
|
||||
|
||||
### 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.
|
||||
|
@@ -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,
|
||||
|
3
mailmap.txt
Normal file
3
mailmap.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
Jan Schaufuss <jschaufuss@js-devop.de> <jschaufuss@leitwerk.de>
|
||||
Jan Schaufuss <jschaufuss@js-devop.de> Jan Schaufuss <jschaufuss@leitwerk.de>
|
||||
<jschaufuss@js-devop.de> <jschaufuss@leitwerk.de>
|
Reference in New Issue
Block a user