mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-15 08:15:37 +00:00
Polishing and code clean-up
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
package de.grimsi.gameyfin.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.PropertiesPropertySource;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PropertiesLoaderUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Configuration
|
||||
public class SecureProperties {
|
||||
|
||||
@Autowired
|
||||
public void setConfigurableEnvironment(ConfigurableEnvironment env) {
|
||||
try {
|
||||
Resource resource = new ClassPathResource("/config/secure.properties");
|
||||
env.getPropertySources().addFirst(new PropertiesPropertySource(Objects.requireNonNull(resource.getFilename()), PropertiesLoaderUtils.loadProperties(resource)));
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package de.grimsi.gameyfin.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AutocompleteSuggestionDto {
|
||||
private String slug;
|
||||
private String title;
|
||||
private Instant releaseDate;
|
||||
}
|
||||
@@ -2,7 +2,9 @@ package de.grimsi.gameyfin.igdb;
|
||||
|
||||
import com.igdb.proto.Igdb;
|
||||
import de.grimsi.gameyfin.config.WebClientConfig;
|
||||
import de.grimsi.gameyfin.dto.AutocompleteSuggestionDto;
|
||||
import de.grimsi.gameyfin.igdb.dto.TwitchOAuthTokenDto;
|
||||
import de.grimsi.gameyfin.mapper.GameMapper;
|
||||
import io.github.resilience4j.reactor.bulkhead.operator.BulkheadOperator;
|
||||
import io.github.resilience4j.reactor.ratelimiter.operator.RateLimiterOperator;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -15,6 +17,7 @@ import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -91,6 +94,18 @@ public class IgdbWrapper {
|
||||
return Optional.of(gameResult.getGames(0));
|
||||
}
|
||||
|
||||
public List<AutocompleteSuggestionDto> findPossibleMatchingTitles(String searchTerm, int limit) {
|
||||
Igdb.GameResult gameResult = queryIgdbApi(
|
||||
IgdbApiProperties.ENPOINT_GAMES_PROTOBUF,
|
||||
"search \"%s\"; fields slug,name,first_release_date; where platforms = (%s); limit %d;".formatted(searchTerm, preferredPlatforms, limit),
|
||||
Igdb.GameResult.class
|
||||
);
|
||||
|
||||
if(gameResult == null) return Collections.emptyList();
|
||||
|
||||
return gameResult.getGamesList().stream().map(GameMapper::toAutocompleteSuggestionDto).toList();
|
||||
}
|
||||
|
||||
public Optional<Igdb.Game> searchForGameByTitle(String searchTerm) {
|
||||
Igdb.GameResult gameResult = queryIgdbApi(
|
||||
IgdbApiProperties.ENPOINT_GAMES_PROTOBUF,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package de.grimsi.gameyfin.mapper;
|
||||
|
||||
import com.igdb.proto.Igdb;
|
||||
import de.grimsi.gameyfin.dto.AutocompleteSuggestionDto;
|
||||
import de.grimsi.gameyfin.dto.GameOverviewDto;
|
||||
import de.grimsi.gameyfin.entities.DetectedGame;
|
||||
import de.grimsi.gameyfin.service.LibraryService;
|
||||
@@ -60,6 +61,14 @@ public class GameMapper {
|
||||
.build();
|
||||
}
|
||||
|
||||
public static AutocompleteSuggestionDto toAutocompleteSuggestionDto(Igdb.Game game) {
|
||||
return AutocompleteSuggestionDto.builder()
|
||||
.slug(game.getSlug())
|
||||
.title(game.getName())
|
||||
.releaseDate(ProtobufUtil.toInstant(game.getFirstReleaseDate()))
|
||||
.build();
|
||||
}
|
||||
|
||||
private static String getCoverId(Igdb.Game g) {
|
||||
String coverId = g.getCover().getImageId();
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package de.grimsi.gameyfin.rest;
|
||||
import de.grimsi.gameyfin.service.DownloadService;
|
||||
import de.grimsi.gameyfin.service.LibraryService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@@ -20,6 +21,7 @@ import java.util.List;
|
||||
@RequestMapping("/v1/library")
|
||||
@PreAuthorize("hasAuthority('ADMIN_API_ACCESS')")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class LibraryController {
|
||||
|
||||
private final LibraryService libraryService;
|
||||
@@ -37,6 +39,8 @@ public class LibraryController {
|
||||
downloadService.downloadGameCoversFromIgdb();
|
||||
downloadService.downloadGameScreenshotsFromIgdb();
|
||||
downloadService.downloadCompanyLogosFromIgdb();
|
||||
|
||||
log.info("Downloading images completed.");
|
||||
}
|
||||
|
||||
@GetMapping(value = "/files", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package de.grimsi.gameyfin.rest;
|
||||
|
||||
|
||||
import de.grimsi.gameyfin.dto.AutocompleteSuggestionDto;
|
||||
import de.grimsi.gameyfin.dto.PathToSlugDto;
|
||||
import de.grimsi.gameyfin.entities.DetectedGame;
|
||||
import de.grimsi.gameyfin.entities.UnmappableFile;
|
||||
import de.grimsi.gameyfin.repositories.DetectedGameRepository;
|
||||
import de.grimsi.gameyfin.service.DownloadService;
|
||||
import de.grimsi.gameyfin.service.GameService;
|
||||
import de.grimsi.gameyfin.service.LibraryService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
@@ -23,6 +25,8 @@ public class LibraryManagementController {
|
||||
private final GameService gameService;
|
||||
private final DownloadService downloadService;
|
||||
|
||||
private final LibraryService libraryService;
|
||||
|
||||
@DeleteMapping(value = "/delete-game/{slug}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public void deleteGame(@PathVariable String slug) {
|
||||
gameService.deleteGame(slug);
|
||||
@@ -53,4 +57,9 @@ public class LibraryManagementController {
|
||||
public List<UnmappableFile> getUnmappedFiles() {
|
||||
return gameService.getAllUnmappedFiles();
|
||||
}
|
||||
|
||||
@GetMapping(value = "/autocomplete-suggestions", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public List<AutocompleteSuggestionDto> getAutocompleteSuggestions(@RequestParam String searchTerm, @RequestParam(required = false, defaultValue = "10") int limit) {
|
||||
return libraryService.getAutocompleteSuggestions(searchTerm, limit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package de.grimsi.gameyfin.service;
|
||||
|
||||
import com.igdb.proto.Igdb;
|
||||
import de.grimsi.gameyfin.dto.AutocompleteSuggestionDto;
|
||||
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.DetectedGameRepository;
|
||||
import de.grimsi.gameyfin.repositories.UnmappableFileRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -24,21 +26,15 @@ import static de.grimsi.gameyfin.util.FilenameUtil.hasGameArchiveExtension;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class LibraryService {
|
||||
|
||||
@Value("${gameyfin.root}")
|
||||
private String rootFolderPath;
|
||||
|
||||
@Value("${gameyfin.cache}")
|
||||
private String cacheFolderPath;
|
||||
@Autowired
|
||||
private IgdbWrapper igdbWrapper;
|
||||
|
||||
@Autowired
|
||||
private DetectedGameRepository detectedGameRepository;
|
||||
|
||||
@Autowired
|
||||
private UnmappableFileRepository unmappableFileRepository;
|
||||
private final IgdbWrapper igdbWrapper;
|
||||
private final DetectedGameRepository detectedGameRepository;
|
||||
private final UnmappableFileRepository unmappableFileRepository;
|
||||
|
||||
public List<Path> getGameFiles() {
|
||||
|
||||
@@ -108,4 +104,8 @@ public class LibraryService {
|
||||
log.info("Scan finished in {} seconds: Found {} new games, deleted {} games, could not map {} files/folders, {} games total.",
|
||||
(int) stopWatch.getTotalTimeSeconds(), newDetectedGames.size(), deletedGames.size() + deletedUnmappableFiles.size(), newUnmappedFilesCounter.get(), detectedGameRepository.count());
|
||||
}
|
||||
|
||||
public List<AutocompleteSuggestionDto> getAutocompleteSuggestions(String searchTerm, int limit) {
|
||||
return igdbWrapper.findPossibleMatchingTitles(searchTerm, limit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
gameyfin:
|
||||
user: admin
|
||||
password: 112
|
||||
#root: C:\Projects\privat\gameyfin-library
|
||||
root: \\NAS-Simon\Öffentlich\Spiele
|
||||
password: password
|
||||
cache: ${gameyfin.root}\.gameyfin\cache
|
||||
db: ${gameyfin.root}\.gameyfin\db
|
||||
#db: ./data
|
||||
igdb:
|
||||
api:
|
||||
client-id: 23l3l5qshx4dwjuao6yb8jyf1qrd08
|
||||
client-secret: hf4iivmkzgne552j17p2d64xm03die
|
||||
|
||||
logging:
|
||||
level:
|
||||
|
||||
@@ -1,34 +1,3 @@
|
||||
server:
|
||||
port: 8080
|
||||
error.include-stacktrace: never
|
||||
|
||||
spring:
|
||||
mvc:
|
||||
async.request-timeout: -1
|
||||
jackson.default-property-inclusion: non_null
|
||||
datasource.db-name: gameyfin_db
|
||||
datasource.url: jdbc:h2:file:${gameyfin.db}/${spring.datasource.db-name};AUTO_SERVER=TRUE
|
||||
datasource.username: gfadmin
|
||||
datasource.password: gameyfin
|
||||
datasource.driverClassName: org.h2.Driver
|
||||
jpa:
|
||||
database-platform: org.hibernate.dialect.H2Dialect
|
||||
hibernate.ddl-auto: update
|
||||
open-in-view: true
|
||||
properties:
|
||||
hibernate:
|
||||
event.merge.entity_copy_observer: allow
|
||||
|
||||
gameyfin:
|
||||
user: ""
|
||||
password: ""
|
||||
root: ""
|
||||
cache: ${gameyfin.root}\.gameyfin\cache
|
||||
db: ${gameyfin.root}\.gameyfin\db # Currently unused
|
||||
file-extensions: iso, zip, rar, 7z, exe
|
||||
igdb:
|
||||
config:
|
||||
preferred-platforms: 6
|
||||
api:
|
||||
client-id: ""
|
||||
client-secret: ""
|
||||
# General
|
||||
logging.level:
|
||||
root: info
|
||||
@@ -0,0 +1,10 @@
|
||||
${AnsiColor.GREEN}
|
||||
_____ ___ _
|
||||
/ ___/ ___ _ __ _ ___ __ __ / _/ (_) ___
|
||||
/ (_ / / _ `/ / ' \/ -_) / // / / _/ / / / _ \
|
||||
\___/ \_,_/ /_/_/_/\__/ \_, / /_/ /_/ /_//_/
|
||||
/___/
|
||||
${AnsiColor.WHITE}
|
||||
${application.name} ${application.version}
|
||||
Powered by Spring Boot ${spring-boot.version}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# This file contains properties related to the database configuration
|
||||
#
|
||||
#
|
||||
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
|
||||
spring.datasource.db-name=gameyfin_db
|
||||
spring.datasource.url=jdbc:h2:file:${gameyfin.db}/${spring.datasource.db-name}
|
||||
spring.datasource.username=gfadmin
|
||||
spring.datasource.password=gameyfin
|
||||
spring.datasource.driverClassName=org.h2.Driver
|
||||
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
spring.jpa.open-in-view=true
|
||||
spring.jpa.properties.hibernate.event.merge.entity_copy_observer=allow
|
||||
@@ -0,0 +1,21 @@
|
||||
# This file contains properties related to the configuration of Gameyfin
|
||||
#
|
||||
#
|
||||
# Username and password for the web interface
|
||||
gameyfin.user=
|
||||
gameyfin.password=
|
||||
|
||||
# Root folder of your game library
|
||||
gameyfin.root=
|
||||
# Folders where gameyfin will store cached images and the database
|
||||
gameyfin.cache=${gameyfin.root}\.gameyfin\cache
|
||||
gameyfin.db=${gameyfin.root}\.gameyfin\db
|
||||
|
||||
# File extensions which gameyfin will recognize as game files
|
||||
gameyfin.file-extensions=iso, zip, rar, 7z, exe
|
||||
|
||||
# List of IGDB platform enums to limit search results. FOr possible values see: https://api-docs.igdb.com/#platform
|
||||
gameyfin.igdb.config.preferred-platforms=6
|
||||
# Twitch Client ID and Client Secret
|
||||
gameyfin.igdb.api.client-id=
|
||||
gameyfin.igdb.api.client-secret=
|
||||
@@ -0,0 +1,19 @@
|
||||
# This file contains properties that are *NOT* safe to override by the user
|
||||
# In theory a user should not be able to override them since they will be loaded from the classpath at launch, overriding existing user properties with the same key
|
||||
#
|
||||
#
|
||||
# System Info
|
||||
application.name=Gameyfin
|
||||
application.version=@project.version@
|
||||
# API
|
||||
server.servlet.context-path=/
|
||||
# Spring Actuator
|
||||
management.endpoints.enabled-by-default=false
|
||||
management.endpoint.health.enabled=true
|
||||
# Server
|
||||
server.error.include-stacktrace=never
|
||||
spring.mvc.async.request-timeout=-1
|
||||
# Jackson JSON Mapping
|
||||
spring.jackson.default-property-inclusion=non_null
|
||||
spring.jackson.mapper.accept-case-insensitive-enums=true
|
||||
spring.jackson.deserialization.fail-on-unknown-properties=false
|
||||
Reference in New Issue
Block a user