mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-13 16:40:01 +00:00
Implement manual mapping for files that could not be automatically mapped
This commit is contained in:
@@ -21,8 +21,6 @@ import java.util.Optional;
|
||||
@Service
|
||||
public class IgdbWrapper {
|
||||
|
||||
private static final int MAIN_GAME_CATEGORY_VALUE = 0;
|
||||
|
||||
@Value("${gameyfin.igdb.api.client-id}")
|
||||
private String clientId;
|
||||
|
||||
@@ -70,7 +68,21 @@ public class IgdbWrapper {
|
||||
public Optional<Igdb.Game> getGameById(Long id) {
|
||||
Igdb.GameResult gameResult = igdbApiClient.post()
|
||||
.uri("games.pb")
|
||||
.bodyValue("fields *; where id = %d & category = %d; limit 1;".formatted(id, MAIN_GAME_CATEGORY_VALUE))
|
||||
.bodyValue("fields *; where id = %d; limit 1;".formatted(id))
|
||||
.retrieve()
|
||||
.bodyToMono(Igdb.GameResult.class)
|
||||
.transformDeferred(RateLimiterOperator.of(WebClientConfig.IGDB_RATE_LIMITER))
|
||||
.block();
|
||||
|
||||
if (gameResult == null) return Optional.empty();
|
||||
|
||||
return Optional.of(gameResult.getGames(0));
|
||||
}
|
||||
|
||||
public Optional<Igdb.Game> getGameBySlug(String slug) {
|
||||
Igdb.GameResult gameResult = igdbApiClient.post()
|
||||
.uri("games.pb")
|
||||
.bodyValue("fields *; where slug = \"%s\"; limit 1;".formatted(slug))
|
||||
.retrieve()
|
||||
.bodyToMono(Igdb.GameResult.class)
|
||||
.transformDeferred(RateLimiterOperator.of(WebClientConfig.IGDB_RATE_LIMITER))
|
||||
@@ -84,7 +96,7 @@ public class IgdbWrapper {
|
||||
public Optional<Igdb.Game> searchForGameByTitle(String searchTerm) {
|
||||
Igdb.GameResult gameResult = igdbApiClient.post()
|
||||
.uri("games.pb")
|
||||
.bodyValue("fields *; search \"%s\"; where platforms = (%s) & category = %d;".formatted(searchTerm, preferredPlatforms, MAIN_GAME_CATEGORY_VALUE))
|
||||
.bodyValue("fields *; search \"%s\"; where platforms = (%s);".formatted(searchTerm, preferredPlatforms))
|
||||
.retrieve()
|
||||
.bodyToMono(Igdb.GameResult.class)
|
||||
.transformDeferred(RateLimiterOperator.of(WebClientConfig.IGDB_RATE_LIMITER))
|
||||
|
||||
@@ -3,7 +3,7 @@ package de.grimsi.gameyfin.repositories;
|
||||
import de.grimsi.gameyfin.entities.UnmappableFile;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface UnmappableFileRepository extends JpaRepository<UnmappableFile, String> {
|
||||
public interface UnmappableFileRepository extends JpaRepository<UnmappableFile, Long> {
|
||||
|
||||
boolean existsByPath(String path);
|
||||
}
|
||||
|
||||
@@ -11,9 +11,7 @@ import de.grimsi.gameyfin.util.ProtobufUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.nio.file.Path;
|
||||
@@ -64,7 +62,7 @@ public class GameyfinDevController {
|
||||
return gameService.getAllDetectedGames();
|
||||
}
|
||||
|
||||
@GetMapping(value = "/dev/startScan", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@GetMapping(value = "/dev/scan", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public void scanLibrary() {
|
||||
filesystemService.scanGameLibrary();
|
||||
}
|
||||
@@ -74,4 +72,10 @@ public class GameyfinDevController {
|
||||
return gameService.getAllUnmappedFiles();
|
||||
}
|
||||
|
||||
@PostMapping(value = "/dev/unmappedFiles/{unmappedGameId}/mapTo/{igdbSlug}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public DetectedGame mapGameManually(@PathVariable Long unmappedGameId, @PathVariable String igdbSlug) {
|
||||
return gameService.mapUnmappedFile(unmappedGameId, igdbSlug);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ public class FilesystemService {
|
||||
.toList();
|
||||
|
||||
// For each new game, load the info from IGDB
|
||||
// If a game is not found on IGDB, blacklist the path 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
|
||||
List<DetectedGame> newDetectedGames = gameFiles.parallelStream()
|
||||
.map(p -> {
|
||||
Optional<Igdb.Game> optionalGame = igdbWrapper.searchForGameByTitle(getFilename(p));
|
||||
@@ -91,7 +91,7 @@ public class FilesystemService {
|
||||
|
||||
newDetectedGames = detectedGameRepository.saveAll(newDetectedGames);
|
||||
|
||||
log.info("Scan finished: Found {} new games, deleted {} games, backlisted {} files/folders, {} games total.", newDetectedGames.size(), "NOT_IMPLEMENTED_YET", newBlacklistCounter.get(), detectedGameRepository.count());
|
||||
log.info("Scan finished: Found {} new games, deleted {} games, could not map {} files/folders, {} games total.", newDetectedGames.size(), "NOT_IMPLEMENTED_YET", newBlacklistCounter.get(), detectedGameRepository.count());
|
||||
}
|
||||
|
||||
private String getFilename(Path p) {
|
||||
|
||||
@@ -1,17 +1,26 @@
|
||||
package de.grimsi.gameyfin.service;
|
||||
|
||||
import com.igdb.proto.Igdb;
|
||||
import de.grimsi.gameyfin.entities.DetectedGame;
|
||||
import de.grimsi.gameyfin.entities.UnmappableFile;
|
||||
import de.grimsi.gameyfin.igdb.IgdbWrapper;
|
||||
import de.grimsi.gameyfin.mapper.GameMapper;
|
||||
import de.grimsi.gameyfin.repositories.UnmappableFileRepository;
|
||||
import de.grimsi.gameyfin.repositories.DetectedGameRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class GameService {
|
||||
|
||||
@Autowired
|
||||
private IgdbWrapper igdbWrapper;
|
||||
|
||||
@Autowired
|
||||
private DetectedGameRepository detectedGameRepository;
|
||||
|
||||
@@ -25,4 +34,19 @@ public class GameService {
|
||||
public List<UnmappableFile> getAllUnmappedFiles() {
|
||||
return unmappableFileRepository.findAll();
|
||||
}
|
||||
|
||||
public DetectedGame mapUnmappedFile(Long unmappedGameId, String igdbSlug) {
|
||||
UnmappableFile unmappableFile = unmappableFileRepository.findById(unmappedGameId)
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Unmapped file with id '%d' does not exist.".formatted(unmappedGameId)));
|
||||
|
||||
Igdb.Game igdbGame = igdbWrapper.getGameBySlug(igdbSlug)
|
||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Game with slug '%s' does not exist on IGDB.".formatted(igdbSlug)));
|
||||
|
||||
DetectedGame game = GameMapper.toDetectedGame(igdbGame, Path.of(unmappableFile.getPath()));
|
||||
game = detectedGameRepository.save(game);
|
||||
|
||||
unmappableFileRepository.delete(unmappableFile);
|
||||
|
||||
return game;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user