mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-13 16:40:01 +00:00
Fix handling of duplicates
Corrupted files are now automatically re-downloaded
This commit is contained in:
@@ -19,6 +19,7 @@ import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -53,6 +54,7 @@ public class GameMapper {
|
||||
.playerPerspectives(PlayerPerspectiveMapper.toPlayerPerspectives(g.getPlayerPerspectivesList()))
|
||||
.path(path.toString())
|
||||
.diskSize(calculateDiskSize(g, path))
|
||||
.addedToLibrary(Instant.now())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ public class DownloadService {
|
||||
|
||||
MultiValueMap<String, String> gameToImageIds = new LinkedMultiValueMap<>(
|
||||
detectedGameRepository.findAll().stream()
|
||||
.collect(Collectors.toMap(DetectedGame::getTitle, g -> Collections.singletonList(g.getCoverId()))));
|
||||
.collect(Collectors.toMap(DetectedGame::getSlug, g -> Collections.singletonList(g.getCoverId()))));
|
||||
|
||||
int downloadCount = downloadImagesIntoCache(gameToImageIds, IgdbApiProperties.COVER_IMAGE_SIZE, "cover", "game");
|
||||
|
||||
@@ -133,7 +133,7 @@ public class DownloadService {
|
||||
|
||||
MultiValueMap<String, String> gamesToImageIds = new LinkedMultiValueMap<>(
|
||||
detectedGameRepository.findAll().stream()
|
||||
.collect(Collectors.toMap(DetectedGame::getTitle, DetectedGame::getScreenshotIds)));
|
||||
.collect(Collectors.toMap(DetectedGame::getSlug, DetectedGame::getScreenshotIds)));
|
||||
|
||||
int downloadCount = downloadImagesIntoCache(gamesToImageIds, IgdbApiProperties.SCREENSHOT_IMAGE_SIZE, "screenshot", "game");
|
||||
|
||||
@@ -150,7 +150,7 @@ public class DownloadService {
|
||||
|
||||
Map<String, List<String>> companyToLogoIdMap = detectedGameRepository.findAll().stream()
|
||||
.flatMap(g -> g.getCompanies().stream())
|
||||
.collect(Collectors.toMap(Company::getName, c -> Collections.singletonList(c.getLogoId()), (c1, c2) -> c1));
|
||||
.collect(Collectors.toMap(Company::getSlug, c -> Collections.singletonList(c.getLogoId()), (c1, c2) -> c1));
|
||||
|
||||
MultiValueMap<String, String> companiesToLogoIds = new LinkedMultiValueMap<>(companyToLogoIdMap);
|
||||
|
||||
@@ -215,12 +215,24 @@ public class DownloadService {
|
||||
String imgUrl = "t_%s/%s".formatted(imageSize, imgFileName);
|
||||
|
||||
if (Files.exists(Path.of(cacheFolderPath, imgFileName))) {
|
||||
log.debug("{} for {} '{}' already downloaded ({}), skipping.",
|
||||
imageType.substring(0, 1).toUpperCase() + imageType.substring(1).toLowerCase(),
|
||||
entityType,
|
||||
entry.getKey(),
|
||||
imgFileName);
|
||||
return;
|
||||
|
||||
Path existingImageFile = Path.of(cacheFolderPath, imgFileName);
|
||||
|
||||
try {
|
||||
if(Files.size(existingImageFile) == 0L) {
|
||||
log.info("File '{}' is corrupt, retrying download...", imgFileName);
|
||||
Files.delete(existingImageFile);
|
||||
} else {
|
||||
log.debug("{} for {} '{}' already downloaded ({}), skipping.",
|
||||
imageType.substring(0, 1).toUpperCase() + imageType.substring(1).toLowerCase(),
|
||||
entityType,
|
||||
entry.getKey(),
|
||||
imgFileName);
|
||||
return;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Error while checking file '{}'.", existingImageFile);
|
||||
}
|
||||
}
|
||||
|
||||
Flux<DataBuffer> dataBuffer = igdbImageClient.get()
|
||||
|
||||
@@ -19,6 +19,7 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static de.grimsi.gameyfin.util.FilenameUtil.getFilenameWithoutExtension;
|
||||
@@ -83,11 +84,17 @@ public class LibraryService {
|
||||
.toList();
|
||||
|
||||
// For each new game, load the info from IGDB
|
||||
// If a game is not found on IGDB, add it to the list of unmapped files so we won't query the API later on for the same path
|
||||
// If a game is not found on IGDB, add it to the list of unmapped files, so we won't query the API later on for the same path
|
||||
// If a game is not found on IGDB, blacklist the path, so we won't query the API later for the same path
|
||||
List<DetectedGame> newDetectedGames = gameFiles.parallelStream()
|
||||
.map(p -> {
|
||||
Optional<Igdb.Game> optionalGame = igdbWrapper.searchForGameByTitle(getFilenameWithoutExtension(p));
|
||||
|
||||
if(optionalGame.isPresent() && detectedGameRepository.existsBySlug(optionalGame.get().getSlug())) {
|
||||
log.warn("Game with slug '{}' already exists in database", optionalGame.get().getSlug());
|
||||
optionalGame = Optional.empty();
|
||||
}
|
||||
|
||||
return optionalGame.map(game -> Map.entry(p, game)).or(() -> {
|
||||
unmappableFileRepository.save(new UnmappableFile(p.toString()));
|
||||
newUnmappedFilesCounter.getAndIncrement();
|
||||
@@ -99,7 +106,11 @@ public class LibraryService {
|
||||
.map(Optional::get)
|
||||
.peek(e -> log.info("Mapped file '{}' to game '{}' (slug: {})", e.getKey(), e.getValue().getName(), e.getValue().getSlug()))
|
||||
.map(e -> GameMapper.toDetectedGame(e.getValue(), e.getKey()))
|
||||
.toList();
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<DetectedGame> duplicateGames = getDuplicates(newDetectedGames);
|
||||
newUnmappedFilesCounter.getAndAdd(duplicateGames.size());
|
||||
newDetectedGames.removeAll(duplicateGames);
|
||||
|
||||
newDetectedGames = detectedGameRepository.saveAll(newDetectedGames);
|
||||
|
||||
@@ -112,4 +123,13 @@ public class LibraryService {
|
||||
public List<AutocompleteSuggestionDto> getAutocompleteSuggestions(String searchTerm, int limit) {
|
||||
return igdbWrapper.findPossibleMatchingTitles(searchTerm, limit);
|
||||
}
|
||||
|
||||
private List<DetectedGame> getDuplicates(List<DetectedGame> gamesToFilter) {
|
||||
return gamesToFilter.stream().filter(g -> Collections.frequency(gamesToFilter, g) >1)
|
||||
.peek(d -> {
|
||||
log.warn("Found duplicate for game '{}' under path '{}'. Mapping must be done manually.", d.getTitle(), d.getPath());
|
||||
unmappableFileRepository.save(new UnmappableFile(d.getPath()));
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user