0.2.76 - Icon Packs
This commit is contained in:
@@ -3,10 +3,10 @@ package api
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ponzischeme89/memby/server/internal/library"
|
||||
)
|
||||
|
||||
// Radarr's import notification arrives as a webhook, which is why this is the one part
|
||||
@@ -31,6 +31,30 @@ type radarrWebhookPayload struct {
|
||||
ID int `json:"id"`
|
||||
Quality string `json:"quality"`
|
||||
} `json:"movieFile"`
|
||||
// The delete events carry the file id at the top level rather than under movieFile,
|
||||
// and say whether the media went with the entry. Both are read by the catalogue half
|
||||
// only; the banner has nothing to say about a deletion.
|
||||
MovieFileID int `json:"movieFileId"`
|
||||
DeletedFiles bool `json:"deletedFiles"`
|
||||
}
|
||||
|
||||
// ingestPayload hands the same notification to the catalogue rules.
|
||||
//
|
||||
// Written out rather than shared as one struct because the two halves genuinely read
|
||||
// different fields for different reasons — the banner wants the quality string, the
|
||||
// catalogue wants the deletion flags — and a single type would grow whichever field
|
||||
// either of them needed next.
|
||||
func ingestPayload(payload radarrWebhookPayload) library.RadarrWebhook {
|
||||
var out library.RadarrWebhook
|
||||
out.EventType = payload.EventType
|
||||
out.IsUpgrade = payload.IsUpgrade
|
||||
out.Movie.ID = payload.Movie.ID
|
||||
out.Movie.Title = payload.Movie.Title
|
||||
out.Movie.Year = payload.Movie.Year
|
||||
out.MovieFile.ID = payload.MovieFile.ID
|
||||
out.MovieFileID = payload.MovieFileID
|
||||
out.DeletedFiles = payload.DeletedFiles
|
||||
return out
|
||||
}
|
||||
|
||||
// handleRadarrWebhook accepts Radarr's "On Import" notification.
|
||||
@@ -66,23 +90,20 @@ func (s *Server) handleRadarrWebhook(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
alert, ok := radarrImportAlert(payload, time.Now().UTC())
|
||||
if !ok {
|
||||
// A grab, a rename, a health check or an upgrade of something already in the
|
||||
// library: all real events, none of them "a new film is here".
|
||||
writeJSON(w, http.StatusOK, map[string]any{"ok": true, "announced": false})
|
||||
return
|
||||
// Recording is now the whole of what this hook does. The banner used to be published
|
||||
// from right here, which meant it was published before Emby had scanned the film in —
|
||||
// hence its wording, that the film would be available "shortly". It is announced from
|
||||
// the far end of the scan instead (AnnounceLibraryIngest), where it can say the film is
|
||||
// actually there and where an episode can be announced on the same terms.
|
||||
//
|
||||
// An upgrade is still recorded and still silent as news: the file genuinely changed, so
|
||||
// the row must be re-read, but the film was already there.
|
||||
queued := s.queueIngest(r, "radarr", payload.EventType, library.RadarrRequests(ingestPayload(payload)))
|
||||
if queued > 0 {
|
||||
s.loggerFor(r.Context()).Debug("radarr import recorded",
|
||||
"movie", payload.Movie.Title, "quality", payload.MovieFile.Quality)
|
||||
}
|
||||
window := s.radarrAlertWindow()
|
||||
if window <= 0 {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"ok": true, "announced": false})
|
||||
return
|
||||
}
|
||||
|
||||
s.publishAlert(r.Context(), alert, window)
|
||||
s.loggerFor(r.Context()).Info("radarr import announced",
|
||||
"movie", alert.Title, "alert_id", alert.ID, "quality", payload.MovieFile.Quality)
|
||||
writeJSON(w, http.StatusOK, map[string]any{"ok": true, "announced": true})
|
||||
writeJSON(w, http.StatusOK, map[string]any{"ok": true, "queued": queued})
|
||||
}
|
||||
|
||||
// webhookToken accepts the shared secret three ways because Radarr's webhook settings
|
||||
@@ -100,53 +121,3 @@ func webhookToken(r *http.Request) string {
|
||||
}
|
||||
return strings.TrimSpace(r.URL.Query().Get("token"))
|
||||
}
|
||||
|
||||
// radarrImportAlert turns an import notification into the banner a TV shows, or reports
|
||||
// that this event is not worth announcing.
|
||||
//
|
||||
// An upgrade is deliberately silent: the film was already there, and "new movie added"
|
||||
// would be a lie about a file that was replaced with a better copy.
|
||||
func radarrImportAlert(payload radarrWebhookPayload, now time.Time) (clientAlert, bool) {
|
||||
if !isRadarrImportEvent(payload.EventType) || payload.IsUpgrade {
|
||||
return clientAlert{}, false
|
||||
}
|
||||
title := strings.TrimSpace(payload.Movie.Title)
|
||||
if title == "" || payload.Movie.ID <= 0 {
|
||||
return clientAlert{}, false
|
||||
}
|
||||
|
||||
// Keyed on the file, so a title deleted and re-imported is news again while a
|
||||
// repeated delivery of the same import is not. Clients dedupe on this id forever.
|
||||
id := fmt.Sprintf("radarr:%d:file:%d", payload.Movie.ID, payload.MovieFile.ID)
|
||||
if payload.MovieFile.ID <= 0 {
|
||||
id = fmt.Sprintf("radarr:%d:imported:%d", payload.Movie.ID, now.Unix())
|
||||
}
|
||||
|
||||
name := title
|
||||
if payload.Movie.Year > 0 {
|
||||
name = fmt.Sprintf("%s (%d)", title, payload.Movie.Year)
|
||||
}
|
||||
return clientAlert{
|
||||
ID: id,
|
||||
Kind: alertKindRadarrImport,
|
||||
Label: "NEW MOVIE ADDED",
|
||||
Title: name,
|
||||
Message: fmt.Sprintf("%s will be available in Emby shortly.", title),
|
||||
// The image proxy already serves Radarr covers under this id and tag, so the
|
||||
// banner shows the poster before Emby has finished scanning the film in.
|
||||
ItemID: fmt.Sprintf("radarr:%d", payload.Movie.ID),
|
||||
ImageTag: "radarr",
|
||||
AiredAt: now.UTC().Format(time.RFC3339),
|
||||
}, true
|
||||
}
|
||||
|
||||
// isRadarrImportEvent matches the event Radarr fires once a downloaded file has been
|
||||
// imported into the library. The name has moved between versions, so both are accepted.
|
||||
func isRadarrImportEvent(eventType string) bool {
|
||||
switch strings.ToLower(strings.TrimSpace(eventType)) {
|
||||
case "download", "moviefileimported":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user