sonarrtfy
A small Flask service to combine Sonarr events for a season.
Tech Stack
Sonarr Season Notification Webhook
A lightweight Flask automation service that improves Sonarr notifications by grouping episode download events at the season level. Instead of sending one notification for every episode, it buffers related downloads and delivers a single ntfy message once a season is complete or after a configurable timeout.
Overview
This project was built to reduce notification noise in self-hosted media workflows. Sonarr can emit frequent webhook events during active downloads, especially when multiple episodes from the same season arrive close together, so this service consolidates those events into cleaner, more meaningful notifications.
What the project does
- Receives Sonarr webhook payloads through a Flask endpoint.
- Groups episode download events by series and season.
- Buffers partial season downloads in memory using debounce timers.
- Checks Sonarr to detect whether a full season has been completed.
- Sends a single ntfy notification for either a completed season or a buffered partial-season batch.
- Includes notification metadata such as title, message, tags, click URL, and optional poster image.
- Sends a startup notification when the service launches.
- Exposes a health endpoint for runtime checks.
Problem
Default automation notifications often prioritize immediacy over clarity. In a media stack, that can result in several nearly identical alerts arriving within minutes of each other, making it harder to tell whether a full season is available or only a few episodes have landed.
Solution
This service adds a notification layer between Sonarr and ntfy. By buffering incoming episode events and checking season completeness through the Sonarr API, it converts noisy episode-by-episode alerts into concise, context-aware notifications that are easier to scan and more useful in practice.
Complete Season Notification
This screenshot shows the notification sent when the service detects that all episodes of a season have been downloaded. Instead of sending multiple episode-level alerts, the webhook consolidates them into a single season-level notification.

Partial Season Notification
This screenshot shows the notification sent when only part of a season has been downloaded and the debounce timeout is reached. It highlights the buffered batch of episodes in one message, making partial progress easier to understand than separate per-episode alerts.

Technical highlights
| Area | Details |
|---|---|
| Framework | Flask-based webhook listener with lightweight API endpoints. |
| Input handling | Accepts Sonarr webhook payloads and validates key fields such as JSON body, series ID, season number, and episode number. |
| Buffering | Uses in-memory grouping by series_id:season_number with debounce timers to merge related events. |
| Season detection | Queries the Sonarr API to compare received episodes against the expected total for that season. |
| Notification delivery | Publishes consolidated updates to ntfy with support for title, body text, tags, click links, and optional media. |
| Observability | Provides a /health route and startup/runtime logging for service state and debugging. |