refactor(library): one IGDB split and merge for time to beat and moods

This commit is contained in:
lobo committed 2026-09-30 09:37:16 +02:00
1 parent c1472c7d59
commit b499e79c41
3 files changed
+62 -50

No files matched your search

@@ -0,0 +1,54 @@
package core_service.modules.library.service;
import core_service.modules.library.domain.GameKeys;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Function;
/**
* IGDB finds a Steam game by its appid and a game off Steam by its IGDB id: one call per key kind, answers by appid.
*/
final class IgdbLookup {
/**
* @param answered the appids whose call worked, sorted; an appid without a value in {@code found} has no data
*/
record Answer<T>(Set<Long> answered, Map<Long, T> found) {}
private IgdbLookup() {
}
static <T> Answer<T> byAppid(Collection<Long> appids,
Function<Set<Long>, Optional<Map<Long, T>>> bySteamAppid,
Function<Set<Long>, Optional<Map<Long, T>>> byIgdbId) {
Set<Long> steamAppids = new TreeSet<>();
Set<Long> igdbIds = new TreeSet<>();
for (Long appid : appids) {
if (GameKeys.isSteam(appid)) {
steamAppids.add(appid);
} else {
igdbIds.add(GameKeys.igdbId(appid));
}
}
Map<Long, T> found = new HashMap<>();
Set<Long> answered = new TreeSet<>();
if (!steamAppids.isEmpty()) {
bySteamAppid.apply(steamAppids).ifPresent(values -> {
found.putAll(values);
answered.addAll(steamAppids);
});
}
if (!igdbIds.isEmpty()) {
byIgdbId.apply(igdbIds).ifPresent(values -> {
values.forEach((igdbId, value) -> found.put(GameKeys.ofIgdb(igdbId), value));
igdbIds.forEach(igdbId -> answered.add(GameKeys.ofIgdb(igdbId)));
});
}
return new Answer<>(answered, found);
}
}
@@ -1,7 +1,6 @@
package core_service.modules.library.service;
import core_service.modules.igdb_adapter.service.IgdbApiService;
import core_service.modules.library.domain.GameKeys;
import core_service.modules.library.domain.Mood;
import core_service.modules.library.repo.GameMoodsRepository;
import core_service.modules.library.repo.UserGameRepository;
@@ -14,7 +13,6 @@ import org.springframework.stereotype.Service;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
@@ -42,29 +40,10 @@ public class MoodService {
stale.removeAll(gameMoodsRepository.findFreshAppids(appids, Instant.now().minus(Duration.ofDays(ttlDays))));
if (stale.isEmpty()) return;
Set<Long> steamAppids = new TreeSet<>();
Set<Long> igdbIds = new TreeSet<>();
for (Long appid : stale) {
if (GameKeys.isSteam(appid)) {
steamAppids.add(appid);
} else {
igdbIds.add(GameKeys.igdbId(appid));
}
}
Map<Long, IgdbApiService.GameTags> tags = new HashMap<>();
Set<Long> answered = new TreeSet<>();
if (!steamAppids.isEmpty()) {
igdbApiService.getGameTags(steamAppids).ifPresent(found -> {
tags.putAll(found);
answered.addAll(steamAppids);
});
}
if (!igdbIds.isEmpty()) {
igdbApiService.getGameTagsByGameIds(igdbIds).ifPresent(found -> {
found.forEach((igdbId, gameTags) -> tags.put(GameKeys.ofIgdb(igdbId), gameTags));
igdbIds.forEach(igdbId -> answered.add(GameKeys.ofIgdb(igdbId)));
});
}
IgdbLookup.Answer<IgdbApiService.GameTags> answer = IgdbLookup.byAppid(stale, igdbApiService::getGameTags,
igdbApiService::getGameTagsByGameIds);
Set<Long> answered = answer.answered();
Map<Long, IgdbApiService.GameTags> tags = answer.found();
if (answered.size() < stale.size()) {
log.warn("Moods of {} games not refreshed, IGDB did not answer", stale.size() - answered.size());
}
@@ -1,7 +1,6 @@
package core_service.modules.library.service;
import core_service.modules.igdb_adapter.service.IgdbApiService;
import core_service.modules.library.domain.GameKeys;
import core_service.modules.library.repo.GameTimeToBeatRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -12,7 +11,6 @@ import org.springframework.stereotype.Service;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
@@ -51,29 +49,10 @@ public class TimeToBeatService {
stale.removeAll(gameTimeToBeatRepository.findFreshAppids(appids, Instant.now().minus(Duration.ofDays(ttlDays))));
if (stale.isEmpty()) return;
Set<Long> steamAppids = new TreeSet<>();
Set<Long> igdbIds = new TreeSet<>();
for (Long appid : stale) {
if (GameKeys.isSteam(appid)) {
steamAppids.add(appid);
} else {
igdbIds.add(GameKeys.igdbId(appid));
}
}
Map<Long, IgdbApiService.TimeToBeat> times = new HashMap<>();
Set<Long> answered = new TreeSet<>();
if (!steamAppids.isEmpty()) {
igdbApiService.getTimeToBeat(steamAppids).ifPresent(found -> {
times.putAll(found);
answered.addAll(steamAppids);
});
}
if (!igdbIds.isEmpty()) {
igdbApiService.getTimeToBeatByGameIds(igdbIds).ifPresent(found -> {
found.forEach((igdbId, time) -> times.put(GameKeys.ofIgdb(igdbId), time));
igdbIds.forEach(igdbId -> answered.add(GameKeys.ofIgdb(igdbId)));
});
}
IgdbLookup.Answer<IgdbApiService.TimeToBeat> answer = IgdbLookup.byAppid(stale, igdbApiService::getTimeToBeat,
igdbApiService::getTimeToBeatByGameIds);
Set<Long> answered = answer.answered();
Map<Long, IgdbApiService.TimeToBeat> times = answer.found();
if (answered.size() < stale.size()) {
log.warn("Time to beat for {} apps not refreshed, IGDB did not answer", stale.size() - answered.size());
}