0.2.63 update
This commit is contained in:
@@ -48,7 +48,7 @@ type requestLookupResponse struct {
|
||||
}
|
||||
|
||||
func (s *Server) requestAllowed(r *http.Request, sess store.Session) bool {
|
||||
if s.store == nil || (s.sonarr == nil && s.radarr == nil) {
|
||||
if s.store == nil || (!s.sonarrEnabled(r.Context()) && !s.radarrEnabled(r.Context())) {
|
||||
return false
|
||||
}
|
||||
policy, err := s.store.RequestPolicy(r.Context())
|
||||
@@ -73,7 +73,7 @@ func (s *Server) handleRequestLookup(w http.ResponseWriter, r *http.Request, ses
|
||||
var movieCandidates []requestCandidate
|
||||
var seriesCandidates []requestCandidate
|
||||
var wg sync.WaitGroup
|
||||
if s.radarr != nil {
|
||||
if s.radarrEnabled(r.Context()) {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
@@ -98,7 +98,7 @@ func (s *Server) handleRequestLookup(w http.ResponseWriter, r *http.Request, ses
|
||||
}
|
||||
}()
|
||||
}
|
||||
if s.sonarr != nil {
|
||||
if s.sonarrEnabled(r.Context()) {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
@@ -235,7 +235,7 @@ func (s *Server) handleRequest(w http.ResponseWriter, r *http.Request, sess stor
|
||||
|
||||
switch req.MediaType {
|
||||
case "movie":
|
||||
if s.radarr == nil {
|
||||
if !s.radarrEnabled(r.Context()) {
|
||||
s.logMediaRequest(r.Context(), req, "failed", errors.New("movie requests are not configured"))
|
||||
writeError(w, http.StatusServiceUnavailable, "movie requests are not configured")
|
||||
return
|
||||
@@ -265,13 +265,22 @@ func (s *Server) handleRequest(w http.ResponseWriter, r *http.Request, sess stor
|
||||
return
|
||||
}
|
||||
req.Title = movie.Title
|
||||
added, err := s.radarr.AddRequested(r.Context(), movie)
|
||||
requestOptions, rootFolder, profileName, err := s.radarrRequestOptions(r.Context())
|
||||
if err != nil {
|
||||
s.logRadarrRequest(r.Context(), sess, req, movie, 0, "failed", "", 0, "", false, err)
|
||||
s.publishRadarrRequestConfigurationProblem(r.Context(), err)
|
||||
writeError(w, http.StatusServiceUnavailable, "movie requests are unavailable: "+err.Error())
|
||||
return
|
||||
}
|
||||
added, err := s.radarr.AddRequested(r.Context(), movie, rootFolder, requestOptions)
|
||||
if err != nil {
|
||||
s.logRadarrRequest(r.Context(), sess, req, movie, 0, "failed", profileName, requestOptions.QualityProfileID, rootFolder, requestOptions.SearchImmediately, err)
|
||||
s.logMediaRequest(r.Context(), req, "failed", err)
|
||||
s.writeRequestUpstreamError(r.Context(), w, err, "could not request that movie")
|
||||
return
|
||||
}
|
||||
req.Title = added.Title
|
||||
s.logRadarrRequest(r.Context(), sess, req, added, added.ID, "successful", profileName, requestOptions.QualityProfileID, rootFolder, requestOptions.SearchImmediately, nil)
|
||||
s.recordMediaRequest(r.Context(), sess, req, added.Year,
|
||||
radarrCoverURL(added.Images, "poster"))
|
||||
s.logMediaRequest(r.Context(), req, "successful", nil)
|
||||
@@ -279,7 +288,7 @@ func (s *Server) handleRequest(w http.ResponseWriter, r *http.Request, sess stor
|
||||
return
|
||||
}
|
||||
case "series":
|
||||
if s.sonarr == nil {
|
||||
if !s.sonarrEnabled(r.Context()) {
|
||||
s.logMediaRequest(r.Context(), req, "failed", errors.New("series requests are not configured"))
|
||||
writeError(w, http.StatusServiceUnavailable, "series requests are not configured")
|
||||
return
|
||||
@@ -392,7 +401,7 @@ func (s *Server) writeRequestUpstreamError(
|
||||
// sonarrRequestOptions validates every component before a POST can reach Sonarr. A missing
|
||||
// configured profile is an error, not permission to fall back to Sonarr's "Any" profile.
|
||||
func (s *Server) sonarrRequestOptions(ctx context.Context) (sonarr.RequestOptions, string, string, error) {
|
||||
if s.sonarr == nil {
|
||||
if !s.sonarrEnabled(ctx) {
|
||||
return sonarr.RequestOptions{}, "", "", errors.New("Sonarr integration is unavailable")
|
||||
}
|
||||
policy, err := s.store.SonarrRequestPolicy(ctx)
|
||||
@@ -465,3 +474,74 @@ func (s *Server) publishSonarrRequestConfigurationProblem(ctx context.Context, e
|
||||
Link: "/admin/integrations", Metadata: adminevents.Meta(map[string]any{"error": err.Error()}),
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) radarrRequestOptions(ctx context.Context) (radarr.RequestOptions, string, string, error) {
|
||||
if !s.radarrEnabled(ctx) {
|
||||
return radarr.RequestOptions{}, "", "", errors.New("Radarr integration is unavailable")
|
||||
}
|
||||
policy, err := s.store.RadarrRequestPolicy(ctx)
|
||||
if err != nil {
|
||||
return radarr.RequestOptions{}, "", "", errors.New("could not read the Radarr request policy")
|
||||
}
|
||||
roots, err := s.radarr.RootFolders(ctx)
|
||||
if err != nil {
|
||||
return radarr.RequestOptions{}, "", "", errors.New("could not validate Radarr root folders")
|
||||
}
|
||||
if len(roots) == 0 || strings.TrimSpace(roots[0].Path) == "" {
|
||||
return radarr.RequestOptions{}, "", "", errors.New("Radarr has no valid root folder")
|
||||
}
|
||||
profiles, err := s.radarr.QualityProfiles(ctx)
|
||||
if err != nil {
|
||||
return radarr.RequestOptions{}, "", "", errors.New("could not validate Radarr quality profiles")
|
||||
}
|
||||
profileID := policy.QualityProfileID
|
||||
if profileID == 0 {
|
||||
for _, profile := range profiles {
|
||||
if is720pProfile(profile.Name) {
|
||||
profileID = profile.ID
|
||||
break
|
||||
}
|
||||
}
|
||||
if profileID == 0 {
|
||||
return radarr.RequestOptions{}, "", "", errors.New("no request quality profile is configured and Radarr has no 720p profile")
|
||||
}
|
||||
policy.QualityProfileID = profileID
|
||||
if err := s.store.SetRadarrRequestPolicy(ctx, policy); err != nil {
|
||||
return radarr.RequestOptions{}, "", "", errors.New("could not save the default Radarr request quality profile")
|
||||
}
|
||||
}
|
||||
for _, profile := range profiles {
|
||||
if profile.ID == profileID {
|
||||
return radarr.RequestOptions{QualityProfileID: profile.ID, SearchImmediately: policy.SearchImmediately}, roots[0].Path, profile.Name, nil
|
||||
}
|
||||
}
|
||||
return radarr.RequestOptions{}, "", "", errors.New("the configured Radarr request quality profile no longer exists")
|
||||
}
|
||||
|
||||
func (s *Server) logRadarrRequest(
|
||||
ctx context.Context, sess store.Session, req requestPayload, movie radarr.Movie, movieID int,
|
||||
outcome, profileName string, profileID int, rootFolder string, searchImmediately bool, err error,
|
||||
) {
|
||||
fields := []any{
|
||||
"user", clientLogValue(sess.Username), "user_id", sess.EmbyUserID,
|
||||
"title", clientLogValue(movie.Title), "tmdb_id", movie.TMDBID,
|
||||
"radarr_movie_id", movieID, "quality_profile", profileName,
|
||||
"quality_profile_id", profileID, "monitoring_strategy", "movie",
|
||||
"root_folder", rootFolder, "search_immediately", searchImmediately, "outcome", outcome,
|
||||
}
|
||||
if err != nil {
|
||||
fields = append(fields, "radarr_result", err.Error())
|
||||
s.loggerFor(ctx).Warn("Radarr movie request", fields...)
|
||||
return
|
||||
}
|
||||
fields = append(fields, "radarr_result", "created")
|
||||
s.loggerFor(ctx).Info("Radarr movie request", fields...)
|
||||
}
|
||||
|
||||
func (s *Server) publishRadarrRequestConfigurationProblem(ctx context.Context, err error) {
|
||||
s.publishAdmin(ctx, adminevents.Event{
|
||||
Type: "radarr.request_configuration", Severity: adminevents.SeverityError,
|
||||
Title: "Radarr movie requests need attention", Summary: err.Error(), Actor: "memby-server",
|
||||
Link: "/admin/integrations", Metadata: adminevents.Meta(map[string]any{"error": err.Error()}),
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user