diff --git a/src/main/java/com/backend/unifier/title/mapper/KodikAndShikimoriDetailMapper.java b/src/main/java/com/backend/unifier/title/mapper/KodikAndShikimoriDetailMapper.java index 32a6133..e859a91 100644 --- a/src/main/java/com/backend/unifier/title/mapper/KodikAndShikimoriDetailMapper.java +++ b/src/main/java/com/backend/unifier/title/mapper/KodikAndShikimoriDetailMapper.java @@ -2,6 +2,7 @@ package com.backend.unifier.title.mapper; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; import org.mapstruct.AfterMapping; @@ -13,7 +14,6 @@ import org.mapstruct.MappingTarget; import org.mapstruct.Named; import org.mapstruct.NullValuePropertyMappingStrategy; -import com.backend.metadata.kodik.api.model.KodikResponse; import com.backend.metadata.kodik.api.model.KodikResponse.Result; import com.backend.metadata.shikimori.api.model.Anime; import com.backend.metadata.shikimori.api.model.CharacterRole; @@ -43,22 +43,18 @@ public interface KodikAndShikimoriDetailMapper { @Mapping(target = "directors", source = "result.materialData.directors") @Mapping(target = "related", ignore = true) @Mapping(target = "characters", ignore = true) - ContentDetailEntry toDto(Result result, @Context KodikResponse allKodikResults, @Context Anime anime); + ContentDetailEntry toDto(Result result, @Context Anime anime); @AfterMapping default void mergeShikimoriAndKodik(@MappingTarget ContentDetailEntry dto, Result result, - @Context KodikResponse allKodikResults, @Context Anime anime) { - if (allKodikResults != null && allKodikResults.results != null) { - Map seen = allKodikResults.results.stream() - .filter(r -> r.translation != null) - .collect(Collectors.toMap( - r -> r.translation.id, - r -> new TranslationDto(r.translation.id, r.translation.title, r.translation.type), - (a, b) -> a)); - dto.translations = List.copyOf(seen.values()); + if (result.translations != null) { + dto.translations = result.translations.stream() + .filter(Objects::nonNull) + .map(t -> new TranslationDto(t.id, t.title, t.type)) + .toList(); } if (anime == null) diff --git a/src/main/java/com/backend/unifier/title/service/GeneralDetailService.java b/src/main/java/com/backend/unifier/title/service/GeneralDetailService.java index 52fd2e0..dc24895 100644 --- a/src/main/java/com/backend/unifier/title/service/GeneralDetailService.java +++ b/src/main/java/com/backend/unifier/title/service/GeneralDetailService.java @@ -3,6 +3,8 @@ package com.backend.unifier.title.service; import java.util.Optional; import java.util.UUID; +import org.jboss.logging.Logger; + import com.backend.unifier.title.model.ContentDetailEntry; import com.backend.unifier.title.model.ContentIdentifier; import com.backend.unifier.title.model.ContentProviderSource; @@ -12,6 +14,8 @@ import jakarta.enterprise.inject.Instance; @ApplicationScoped public class GeneralDetailService { + Logger logger = Logger.getLogger(GeneralDetailService.class); + private final IdentifierMaskService maskService; private final Instance detailServices; @@ -22,8 +26,10 @@ public class GeneralDetailService { public Optional details(UUID id) { ContentIdentifier realIdentifier = maskService.realIdentifier(id); - if (realIdentifier == null) - throw new IllegalStateException("content identifier not found for id '" + id + "'"); + if (realIdentifier == null) { + logger.info("content identifier not found for id '" + id + "', returning no details"); + return Optional.empty(); + } ContentProviderSource source = ContentProviderSource.valueOf(realIdentifier.source()); for (DetailService detailService : detailServices) { if (detailService.source() == source) diff --git a/src/main/java/com/backend/unifier/title/service/IdentifierMaskService.java b/src/main/java/com/backend/unifier/title/service/IdentifierMaskService.java index 524daae..65f9c79 100644 --- a/src/main/java/com/backend/unifier/title/service/IdentifierMaskService.java +++ b/src/main/java/com/backend/unifier/title/service/IdentifierMaskService.java @@ -11,21 +11,37 @@ import jakarta.enterprise.context.ApplicationScoped; @ApplicationScoped public class IdentifierMaskService { - private ValueCommands countCommands; + private ValueCommands pointerToIdentifier; + private ValueCommands identifierToPointer; public IdentifierMaskService(RedisDataSource ds) { - countCommands = ds.value(ContentIdentifier.class); + pointerToIdentifier = ds.value(ContentIdentifier.class); + identifierToPointer = ds.value(String.class); + } + + private String reverseKey(String id, ContentProviderSource source) { + return "reverse:" + source.name() + ":" + id; } public UUID createMask(String id, ContentProviderSource source) { + String rKey = reverseKey(id, source); + + String existingPointer = identifierToPointer.get(rKey); + if (existingPointer != null) { + return UUID.fromString(existingPointer); + } + ContentIdentifier contentIdentifier = new ContentIdentifier(source.name(), id); UUID pointerID = UUID.randomUUID(); - countCommands.set(pointerID.toString(), contentIdentifier); + + pointerToIdentifier.set(pointerID.toString(), contentIdentifier); + identifierToPointer.set(rKey, pointerID.toString()); + return pointerID; } public ContentIdentifier realIdentifier(UUID id) { - return countCommands.get(id.toString()); + return pointerToIdentifier.get(id.toString()); } } diff --git a/src/main/java/com/backend/unifier/title/service/kodik/KodikDetailService.java b/src/main/java/com/backend/unifier/title/service/kodik/KodikDetailService.java index 1d2d692..174b876 100644 --- a/src/main/java/com/backend/unifier/title/service/kodik/KodikDetailService.java +++ b/src/main/java/com/backend/unifier/title/service/kodik/KodikDetailService.java @@ -1,9 +1,12 @@ package com.backend.unifier.title.service.kodik; +import java.util.List; import java.util.Optional; import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.jboss.logging.Logger; +import com.backend.metadata.kodik.api.model.KodikResponse; import com.backend.unifier.title.api.KodikAPI; import com.backend.unifier.title.api.ShikimoriAPI; import com.backend.unifier.title.mapper.KodikAndShikimoriDetailMapper; @@ -15,6 +18,8 @@ import jakarta.enterprise.context.ApplicationScoped; @ApplicationScoped public class KodikDetailService implements DetailService { + Logger LOG = Logger.getLogger(KodikDetailService.class); + private final KodikAPI kodikAPI; private final ShikimoriAPI shikimoriAPI; private final KodikAndShikimoriDetailMapper detailMapper; @@ -33,15 +38,46 @@ public class KodikDetailService implements DetailService { @Override public Optional details(String id) { - var kodikResponse = kodikAPI.findByKodikId(id); - int totalSize = kodikResponse.total; - if (kodikResponse.results != null) - totalSize = kodikResponse.results.size(); + var firstOnlyKodikResponse = kodikAPI.findByKodikId(id); + var firstResult = findFirst(firstOnlyKodikResponse); + if (firstResult.isEmpty()) + return Optional.empty(); + var groupedResponse = findAllGrouped(firstResult.get()); + var firstGroupedResult = findFirst(groupedResponse); + if (firstGroupedResult.isEmpty()) + return Optional.empty(); + + var shikimoriResponse = shikimoriAPI.findById(firstGroupedResult.get().shikimoriId); + return Optional.ofNullable(detailMapper.toDto(firstGroupedResult.get(), shikimoriResponse)); + } + + private Optional findFirst(KodikResponse response) { + int totalSize = response.total; + if (response.results != null) + totalSize = response.results.size(); if (totalSize <= 0) return Optional.empty(); - var kodikResult = kodikResponse.results.get(0); - var shikimoriResponse = shikimoriAPI.findById(kodikResult.shikimoriId); - return Optional.ofNullable(detailMapper.toDto(kodikResult, kodikResponse, shikimoriResponse)); + if (totalSize > 1) + LOG.infof("excess results, {}", response); + return Optional.ofNullable(response.results.get(0)); + + } + + private KodikResponse findAllGrouped(KodikResponse.Result firstOnly) { + if (firstOnly.shikimoriId != null) { + return kodikAPI.findByShikimoriId(firstOnly.shikimoriId); + } + if (firstOnly.kinopoiskId != null) { + return kodikAPI.findByKinopoiskId(firstOnly.kinopoiskId); + } + if (firstOnly.imdbId != null) { + return kodikAPI.findByImdbId(firstOnly.imdbId); + } + LOG.warnf("cannot form grouped result, {}", firstOnly); + KodikResponse result = new KodikResponse(); + result.total = 1; + result.results = List.of(firstOnly); + return result; } }