Flip to IN_LIBRARY immediately on successful Radarr/Sonarr add

Previously a title stayed NEVER_HAD until the next full recompute's library
sync, so it kept showing in Recommendations right after being added. Now
RadarrClient.addMovie/SonarrClient.addSeries return the created resource (its
new id), and MediaActionController stores that id and sets status=IN_LIBRARY
right on the 2xx response - RestClient throws on non-2xx, so this only
happens on genuine success. Drops the title out of Recommendations and into
"Просмотрено" instantly, no recompute needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Kayashov.SM
2026-09-15 12:42:09 +04:00
co-authored by Claude Sonnet 5
parent 5aa363713a
commit 99cfcb1b5a
3 changed files with 28 additions and 10 deletions
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.recommendarr.dto.AddToLibraryRequest;
import com.recommendarr.dto.RatingRequest;
import com.recommendarr.entity.MediaEntity;
import com.recommendarr.entity.MediaStatus;
import com.recommendarr.entity.MediaType;
import com.recommendarr.entity.PersonalRating;
import com.recommendarr.entity.Snooze;
@@ -108,16 +109,30 @@ public class MediaActionController {
public record AddOptions(List<JsonNode> qualityProfiles, List<JsonNode> rootFolders) {
}
/**
* On a successful Radarr/Sonarr add, immediately flip this title to
* IN_LIBRARY and store the new radarrId/sonarrId - so it drops out of
* Recommendations and shows up on "Просмотрено" right away, without
* waiting for the next full recompute/library sync.
*/
@PostMapping("/{id}/add-to-library")
public ResponseEntity<Void> addToLibrary(@PathVariable Long id, @RequestBody AddToLibraryRequest request) {
MediaEntity media = mediaRepository.findById(id).orElseThrow();
if (media.getType() == MediaType.SERIES) {
sonarrClient.addSeries(media.getTitle(), null, request.getQualityProfileId(),
JsonNode created = sonarrClient.addSeries(media.getTitle(), null, request.getQualityProfileId(),
request.getRootFolderPath(), request.getTags());
if (created != null && created.has("id")) {
media.setSonarrId(created.get("id").asInt());
}
} else {
radarrClient.addMovie(media.getTmdbId(), media.getTitle(), media.getYear(),
JsonNode created = radarrClient.addMovie(media.getTmdbId(), media.getTitle(), media.getYear(),
request.getQualityProfileId(), request.getRootFolderPath(), request.getTags());
if (created != null && created.has("id")) {
media.setRadarrId(created.get("id").asInt());
}
}
media.setStatus(MediaStatus.IN_LIBRARY);
mediaRepository.save(media);
return ResponseEntity.ok().build();
}
}
@@ -77,9 +77,9 @@ public class RadarrClient {
return result;
}
/** Adds a movie to Radarr by TMDB id. */
public void addMovie(Long tmdbId, String title, Integer year, Integer qualityProfileId,
String rootFolderPath, List<String> tags) {
/** Adds a movie to Radarr by TMDB id. Returns the created Radarr movie resource (has its new "id"). */
public JsonNode addMovie(Long tmdbId, String title, Integer year, Integer qualityProfileId,
String rootFolderPath, List<String> tags) {
IntegrationSetting setting = settingService.getOrCreate(IntegrationType.RADARR);
Map<String, Object> body = Map.of(
"tmdbId", tmdbId,
@@ -91,6 +91,6 @@ public class RadarrClient {
"addOptions", Map.of("searchForMovie", true),
"tags", tags == null ? List.of() : tags
);
client(setting).post().uri("/api/v3/movie").body(body).retrieve().toBodilessEntity();
return client(setting).post().uri("/api/v3/movie").body(body).retrieve().body(JsonNode.class);
}
}
@@ -69,9 +69,12 @@ public class SonarrClient {
return result;
}
/** Adds a series to Sonarr by TVDB-less lookup via TMDB title/year (best effort for MVP). */
public void addSeries(String title, Integer tvdbId, Integer qualityProfileId,
String rootFolderPath, List<String> tags) {
/**
* Adds a series to Sonarr by TVDB-less lookup via TMDB title/year (best
* effort for MVP). Returns the created Sonarr series resource (has its new "id").
*/
public JsonNode addSeries(String title, Integer tvdbId, Integer qualityProfileId,
String rootFolderPath, List<String> tags) {
IntegrationSetting setting = settingService.getOrCreate(IntegrationType.SONARR);
Map<String, Object> body = Map.of(
"title", title,
@@ -82,6 +85,6 @@ public class SonarrClient {
"addOptions", Map.of("searchForMissingEpisodes", true),
"tags", tags == null ? List.of() : tags
);
client(setting).post().uri("/api/v3/series").body(body).retrieve().toBodilessEntity();
return client(setting).post().uri("/api/v3/series").body(body).retrieve().body(JsonNode.class);
}
}