mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-13 16:40:01 +00:00
Use Protobuf endpoints (WIP)
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
|
||||
<properties>
|
||||
<java.version>18</java.version>
|
||||
<protoc.plugin.version>3.11.4</protoc.plugin.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -49,6 +50,19 @@
|
||||
<version>2.11.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Protobuf dependencies -->
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
<version>3.21.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java-util</artifactId>
|
||||
<version>3.21.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@@ -89,6 +103,34 @@
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- Protobuf source generation plugin -->
|
||||
<plugin>
|
||||
<groupId>com.github.os72</groupId>
|
||||
<artifactId>protoc-jar-maven-plugin</artifactId>
|
||||
<version>${protoc.plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeStdTypes>true</includeStdTypes>
|
||||
<inputDirectories>
|
||||
<include>${project.basedir}/src/main/resources/proto</include>
|
||||
</inputDirectories>
|
||||
<outputTargets>
|
||||
<outputTarget>
|
||||
<type>java</type>
|
||||
<outputDirectory>${project.build.directory}/generated-sources/protobuf
|
||||
</outputDirectory>
|
||||
</outputTarget>
|
||||
</outputTargets>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package de.grimsi.gameyfin.config;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.web.reactive.function.client.WebClientCustomizer;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class WebClientConfig implements WebClientCustomizer {
|
||||
|
||||
@Override
|
||||
public void customize(WebClient.Builder webClientBuilder) {
|
||||
webClientBuilder.filter(logResponse());
|
||||
webClientBuilder.filter(logRequest());
|
||||
webClientBuilder.clientConnector(new ReactorClientHttpConnector(HttpClient.create().proxyWithSystemProperties()));
|
||||
}
|
||||
|
||||
private ExchangeFilterFunction logResponse() {
|
||||
return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
|
||||
log.debug("Response: {}", clientResponse.statusCode());
|
||||
return Mono.just(clientResponse);
|
||||
});
|
||||
}
|
||||
|
||||
private ExchangeFilterFunction logRequest() {
|
||||
return (clientRequest, next) -> {
|
||||
log.debug("Request: {} {}", clientRequest.method(), clientRequest.url());
|
||||
return next.exchange(clientRequest);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,17 @@
|
||||
package de.grimsi.gameyfin.igdb;
|
||||
|
||||
import de.grimsi.gameyfin.igdb.dto.IgdbAccessToken;
|
||||
import de.grimsi.gameyfin.igdb.dto.IgdbGame;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.igdb.proto.Game;
|
||||
import de.grimsi.gameyfin.igdb.dto.TwitchOAuthTokenDto;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.net.URI;
|
||||
@@ -30,16 +32,18 @@ public class IgdbWrapper {
|
||||
@Value("${gameyfin.igdb.config.preferred-platform}")
|
||||
private int preferredPlatform;
|
||||
|
||||
private final WebClient twitchApiClient = WebClient.builder()
|
||||
.clientConnector(new ReactorClientHttpConnector(HttpClient.create().proxyWithSystemProperties()))
|
||||
.build();
|
||||
@Autowired
|
||||
private WebClient.Builder webclientBuilder;
|
||||
|
||||
private WebClient twitchApiClient;
|
||||
|
||||
private WebClient igdbApiClient;
|
||||
|
||||
private IgdbAccessToken accessToken;
|
||||
private TwitchOAuthTokenDto accessToken;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
twitchApiClient = webclientBuilder.build();
|
||||
authenticate();
|
||||
initIgdbClient();
|
||||
}
|
||||
@@ -57,25 +61,29 @@ public class IgdbWrapper {
|
||||
.uri(url)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.retrieve()
|
||||
.bodyToMono(IgdbAccessToken.class)
|
||||
.bodyToMono(TwitchOAuthTokenDto.class)
|
||||
.block();
|
||||
|
||||
log.info("Successfully authenticated.");
|
||||
}
|
||||
|
||||
public IgdbGame findGameByTitle(String title) {
|
||||
public Game findGameByTitle(String title) {
|
||||
return searchForGameByTitle(title).orElseThrow(() -> new RuntimeException("Could not find game with title: \"%s\"".formatted(title)));
|
||||
}
|
||||
|
||||
private Optional<IgdbGame> getGameById(Long id) {
|
||||
return Optional.ofNullable(
|
||||
igdbApiClient.post()
|
||||
.uri("games")
|
||||
public Optional<Game> getGameById(Long id) {
|
||||
byte[] gameBytes = igdbApiClient.post()
|
||||
.uri("games.pb")
|
||||
.bodyValue("fields *; where id = %d;".formatted(id))
|
||||
.retrieve()
|
||||
.bodyToMono(IgdbGame.class)
|
||||
.block()
|
||||
);
|
||||
.bodyToMono(byte[].class)
|
||||
.block();
|
||||
|
||||
try {
|
||||
return Optional.ofNullable(Game.parseFrom(gameBytes));
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private void initIgdbClient() {
|
||||
@@ -83,22 +91,21 @@ public class IgdbWrapper {
|
||||
authenticate();
|
||||
}
|
||||
|
||||
igdbApiClient = WebClient.builder()
|
||||
.clientConnector(new ReactorClientHttpConnector(HttpClient.create().proxyWithSystemProperties()))
|
||||
igdbApiClient = webclientBuilder
|
||||
.baseUrl("https://api.igdb.com/v4/")
|
||||
.defaultHeader("Client-ID", clientId)
|
||||
.defaultHeader("Authorization", "Bearer %s".formatted(accessToken.getAccessToken()))
|
||||
.build();
|
||||
}
|
||||
|
||||
private Optional<IgdbGame> searchForGameByTitle(String searchTerm) {
|
||||
List<IgdbGame> games = new ArrayList<>();
|
||||
private Optional<Game> searchForGameByTitle(String searchTerm) {
|
||||
List<Game> games = new ArrayList<>();
|
||||
|
||||
igdbApiClient.post()
|
||||
.uri("games")
|
||||
.uri("games.pb")
|
||||
.bodyValue("fields *; search \"%s\";".formatted(searchTerm))
|
||||
.retrieve()
|
||||
.bodyToFlux(IgdbGame.class)
|
||||
.bodyToFlux(Game.class)
|
||||
.doOnNext(games::add)
|
||||
.blockLast();
|
||||
|
||||
@@ -112,10 +119,10 @@ public class IgdbWrapper {
|
||||
// Example: Searching for "Rainbow Six Siege" will result in returning "Tom Clancy's Rainbow Six Siege" (the game we want)
|
||||
// If we just used the first result from IGDB we would get something like "Tom Clancy's Rainbow Six Siege Demon Veil" as a result
|
||||
|
||||
Optional<IgdbGame> srExactTitleMatch = games.stream().filter(s -> s.getName().equals(searchTerm)).findFirst();
|
||||
Optional<Game> srExactTitleMatch = games.stream().filter(s -> s.getName().equals(searchTerm)).findFirst();
|
||||
if (srExactTitleMatch.isPresent()) return srExactTitleMatch;
|
||||
|
||||
Optional<IgdbGame> srTitleEndsWithMatch = games.stream().filter(s -> s.getName().endsWith(searchTerm)).findFirst();
|
||||
Optional<Game> srTitleEndsWithMatch = games.stream().filter(s -> s.getName().endsWith(searchTerm)).findFirst();
|
||||
if (srTitleEndsWithMatch.isPresent()) return srTitleEndsWithMatch;
|
||||
|
||||
return Optional.of(games.get(0));
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import lombok.NoArgsConstructor;
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
|
||||
public class IgdbAccessToken {
|
||||
public class TwitchOAuthTokenDto {
|
||||
private String accessToken;
|
||||
private Long expiresIn;
|
||||
private String tokenType;
|
||||
@@ -1,10 +1,10 @@
|
||||
package de.grimsi.gameyfin.rest;
|
||||
|
||||
import com.igdb.proto.Game;
|
||||
import de.grimsi.gameyfin.dto.GameDto;
|
||||
import de.grimsi.gameyfin.igdb.IgdbWrapper;
|
||||
import de.grimsi.gameyfin.igdb.dto.IgdbGame;
|
||||
import de.grimsi.gameyfin.service.FilesystemService;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import de.grimsi.gameyfin.util.ProtobufUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -15,7 +15,6 @@ import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
public class GameyfinDevController {
|
||||
@@ -28,7 +27,7 @@ public class GameyfinDevController {
|
||||
|
||||
@GetMapping(value = "/dev/findGameByTitle/{title}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public GameDto findGameByTitle(@PathVariable("title") String title) {
|
||||
IgdbGame game;
|
||||
Game game;
|
||||
|
||||
try {
|
||||
game = igdbWrapper.findGameByTitle(title);
|
||||
@@ -36,7 +35,10 @@ public class GameyfinDevController {
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
|
||||
}
|
||||
|
||||
return GameDto.builder().name(game.getName()).releaseDate(game.getFirstReleaseDate()).build();
|
||||
return GameDto.builder()
|
||||
.name(game.getName())
|
||||
.releaseDate(ProtobufUtils.toInstant(game.getFirstReleaseDate()))
|
||||
.build();
|
||||
}
|
||||
|
||||
@GetMapping(value = "/dev/gameFiles", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@@ -48,7 +50,10 @@ public class GameyfinDevController {
|
||||
public List<GameDto> getAllGames() {
|
||||
return filesystemService.getGameFileNames().stream()
|
||||
.map(t -> igdbWrapper.findGameByTitle(t))
|
||||
.map(g -> GameDto.builder().name(g.getName()).releaseDate(g.getFirstReleaseDate()).build())
|
||||
.map(g -> GameDto.builder()
|
||||
.name(g.getName())
|
||||
.releaseDate(ProtobufUtils.toInstant(g.getFirstReleaseDate()))
|
||||
.build())
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package de.grimsi.gameyfin.util;
|
||||
|
||||
import com.google.protobuf.Timestamp;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
public class ProtobufUtils {
|
||||
public static Instant toInstant(Timestamp t) {
|
||||
return Instant.ofEpochSecond(t.getSeconds(), t.getNanos());
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
gameyfin:
|
||||
root: C:\Projects\privat\gameyfin-library
|
||||
cache: C:\Projects\privat\gameyfin-library\.gameyfin
|
||||
db: C:\Projects\privat\gameyfin-library\.gameyfin
|
||||
igdb:
|
||||
api:
|
||||
client-id: 23l3l5qshx4dwjuao6yb8jyf1qrd08
|
||||
|
||||
@@ -0,0 +1,907 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package com.igdb.proto;
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
//option java_outer_classname = "Igdb";
|
||||
option java_multiple_files = true; // Must be true because of private access in files.
|
||||
option optimize_for = CODE_SIZE;
|
||||
|
||||
message Count {
|
||||
int64 count = 1;
|
||||
}
|
||||
|
||||
message MultiQueryResult {
|
||||
string name = 1;
|
||||
repeated bytes results = 2;
|
||||
int64 count = 3;
|
||||
}
|
||||
|
||||
message MultiQueryResultArray {
|
||||
repeated MultiQueryResult result = 1;
|
||||
}
|
||||
|
||||
message AgeRatingResult {
|
||||
repeated AgeRating ageratings = 1;
|
||||
}
|
||||
|
||||
message AgeRating {
|
||||
uint64 id = 1;
|
||||
AgeRatingCategoryEnum category = 2;
|
||||
repeated AgeRatingContentDescription content_descriptions = 3;
|
||||
AgeRatingRatingEnum rating = 4;
|
||||
string rating_cover_url = 5;
|
||||
string synopsis = 6;
|
||||
string checksum = 7;
|
||||
}
|
||||
|
||||
|
||||
enum AgeRatingCategoryEnum {
|
||||
AGERATING_CATEGORY_NULL = 0;
|
||||
ESRB = 1;
|
||||
PEGI = 2;
|
||||
CERO = 3;
|
||||
USK = 4;
|
||||
GRAC = 5;
|
||||
CLASS_IND = 6;
|
||||
ACB = 7;
|
||||
}
|
||||
|
||||
|
||||
enum AgeRatingRatingEnum {
|
||||
AGERATING_RATING_NULL = 0;
|
||||
THREE = 1;
|
||||
SEVEN = 2;
|
||||
TWELVE = 3;
|
||||
SIXTEEN = 4;
|
||||
EIGHTEEN = 5;
|
||||
RP = 6;
|
||||
EC = 7;
|
||||
E = 8;
|
||||
E10 = 9;
|
||||
T = 10;
|
||||
M = 11;
|
||||
AO = 12;
|
||||
CERO_A = 13;
|
||||
CERO_B = 14;
|
||||
CERO_C = 15;
|
||||
CERO_D = 16;
|
||||
CERO_Z = 17;
|
||||
USK_0 = 18;
|
||||
USK_6 = 19;
|
||||
USK_12 = 20;
|
||||
USK_18 = 21;
|
||||
GRAC_ALL = 22;
|
||||
GRAC_TWELVE = 23;
|
||||
GRAC_FIFTEEN = 24;
|
||||
GRAC_EIGHTEEN = 25;
|
||||
GRAC_TESTING = 26;
|
||||
CLASS_IND_L = 27;
|
||||
CLASS_IND_TEN = 28;
|
||||
CLASS_IND_TWELVE = 29;
|
||||
CLASS_IND_FOURTEEN = 30;
|
||||
CLASS_IND_SIXTEEN = 31;
|
||||
CLASS_IND_EIGHTEEN = 32;
|
||||
ACB_G = 33;
|
||||
ACB_PG = 34;
|
||||
ACB_M = 35;
|
||||
ACB_MA15 = 36;
|
||||
ACB_R18 = 37;
|
||||
ACB_RC = 38;
|
||||
}
|
||||
|
||||
message AgeRatingContentDescriptionResult {
|
||||
repeated AgeRatingContentDescription ageratingcontentdescriptions = 1;
|
||||
}
|
||||
|
||||
message AgeRatingContentDescription {
|
||||
uint64 id = 1;
|
||||
AgeRatingRatingEnum category = 2;
|
||||
string description = 3;
|
||||
string checksum = 4;
|
||||
}
|
||||
|
||||
message AlternativeNameResult {
|
||||
repeated AlternativeName alternativenames = 1;
|
||||
}
|
||||
|
||||
message AlternativeName {
|
||||
uint64 id = 1;
|
||||
string comment = 2;
|
||||
Game game = 3;
|
||||
string name = 4;
|
||||
string checksum = 5;
|
||||
}
|
||||
|
||||
message ArtworkResult {
|
||||
repeated Artwork artworks = 1;
|
||||
}
|
||||
|
||||
message Artwork {
|
||||
uint64 id = 1;
|
||||
bool alpha_channel = 2;
|
||||
bool animated = 3;
|
||||
Game game = 4;
|
||||
int32 height = 5;
|
||||
string image_id = 6;
|
||||
string url = 7;
|
||||
int32 width = 8;
|
||||
string checksum = 9;
|
||||
}
|
||||
|
||||
message CharacterResult {
|
||||
repeated Character characters = 1;
|
||||
}
|
||||
|
||||
message Character {
|
||||
uint64 id = 1;
|
||||
repeated string akas = 2;
|
||||
string country_name = 3;
|
||||
google.protobuf.Timestamp created_at = 4;
|
||||
string description = 5;
|
||||
repeated Game games = 6;
|
||||
GenderGenderEnum gender = 7;
|
||||
CharacterMugShot mug_shot = 8;
|
||||
string name = 9;
|
||||
string slug = 10;
|
||||
CharacterSpeciesEnum species = 11;
|
||||
google.protobuf.Timestamp updated_at = 12;
|
||||
string url = 13;
|
||||
string checksum = 14;
|
||||
}
|
||||
|
||||
|
||||
enum GenderGenderEnum {
|
||||
MALE = 0;
|
||||
FEMALE = 1;
|
||||
OTHER = 2;
|
||||
}
|
||||
|
||||
|
||||
enum CharacterSpeciesEnum {
|
||||
CHARACTER_SPECIES_NULL = 0;
|
||||
HUMAN = 1;
|
||||
ALIEN = 2;
|
||||
ANIMAL = 3;
|
||||
ANDROID = 4;
|
||||
UNKNOWN = 5;
|
||||
}
|
||||
|
||||
message CharacterMugShotResult {
|
||||
repeated CharacterMugShot charactermugshots = 1;
|
||||
}
|
||||
|
||||
message CharacterMugShot {
|
||||
uint64 id = 1;
|
||||
bool alpha_channel = 2;
|
||||
bool animated = 3;
|
||||
int32 height = 4;
|
||||
string image_id = 5;
|
||||
string url = 6;
|
||||
int32 width = 7;
|
||||
string checksum = 8;
|
||||
}
|
||||
|
||||
message CollectionResult {
|
||||
repeated Collection collections = 1;
|
||||
}
|
||||
|
||||
message Collection {
|
||||
uint64 id = 1;
|
||||
google.protobuf.Timestamp created_at = 2;
|
||||
repeated Game games = 3;
|
||||
string name = 4;
|
||||
string slug = 5;
|
||||
google.protobuf.Timestamp updated_at = 6;
|
||||
string url = 7;
|
||||
string checksum = 8;
|
||||
}
|
||||
|
||||
message CompanyResult {
|
||||
repeated Company companies = 1;
|
||||
}
|
||||
|
||||
message Company {
|
||||
uint64 id = 1;
|
||||
google.protobuf.Timestamp change_date = 2;
|
||||
DateFormatChangeDateCategoryEnum change_date_category = 3;
|
||||
Company changed_company_id = 4;
|
||||
int32 country = 5;
|
||||
google.protobuf.Timestamp created_at = 6;
|
||||
string description = 7;
|
||||
repeated Game developed = 8;
|
||||
CompanyLogo logo = 9;
|
||||
string name = 10;
|
||||
Company parent = 11;
|
||||
repeated Game published = 12;
|
||||
string slug = 13;
|
||||
google.protobuf.Timestamp start_date = 14;
|
||||
DateFormatChangeDateCategoryEnum start_date_category = 15;
|
||||
google.protobuf.Timestamp updated_at = 16;
|
||||
string url = 17;
|
||||
repeated CompanyWebsite websites = 18;
|
||||
string checksum = 19;
|
||||
}
|
||||
|
||||
|
||||
enum DateFormatChangeDateCategoryEnum {
|
||||
YYYYMMMMDD = 0;
|
||||
YYYYMMMM = 1;
|
||||
YYYY = 2;
|
||||
YYYYQ1 = 3;
|
||||
YYYYQ2 = 4;
|
||||
YYYYQ3 = 5;
|
||||
YYYYQ4 = 6;
|
||||
TBD = 7;
|
||||
}
|
||||
|
||||
message CompanyLogoResult {
|
||||
repeated CompanyLogo companylogos = 1;
|
||||
}
|
||||
|
||||
message CompanyLogo {
|
||||
uint64 id = 1;
|
||||
bool alpha_channel = 2;
|
||||
bool animated = 3;
|
||||
int32 height = 4;
|
||||
string image_id = 5;
|
||||
string url = 6;
|
||||
int32 width = 7;
|
||||
string checksum = 8;
|
||||
}
|
||||
|
||||
message CompanyWebsiteResult {
|
||||
repeated CompanyWebsite companywebsites = 1;
|
||||
}
|
||||
|
||||
message CompanyWebsite {
|
||||
uint64 id = 1;
|
||||
WebsiteCategoryEnum category = 2;
|
||||
bool trusted = 3;
|
||||
string url = 4;
|
||||
string checksum = 5;
|
||||
}
|
||||
|
||||
|
||||
enum WebsiteCategoryEnum {
|
||||
WEBSITE_CATEGORY_NULL = 0;
|
||||
WEBSITE_OFFICIAL = 1;
|
||||
WEBSITE_WIKIA = 2;
|
||||
WEBSITE_WIKIPEDIA = 3;
|
||||
WEBSITE_FACEBOOK = 4;
|
||||
WEBSITE_TWITTER = 5;
|
||||
WEBSITE_TWITCH = 6;
|
||||
WEBSITE_INSTAGRAM = 8;
|
||||
WEBSITE_YOUTUBE = 9;
|
||||
WEBSITE_IPHONE = 10;
|
||||
WEBSITE_IPAD = 11;
|
||||
WEBSITE_ANDROID = 12;
|
||||
WEBSITE_STEAM = 13;
|
||||
WEBSITE_REDDIT = 14;
|
||||
WEBSITE_ITCH = 15;
|
||||
WEBSITE_EPICGAMES = 16;
|
||||
WEBSITE_GOG = 17;
|
||||
WEBSITE_DISCORD = 18;
|
||||
}
|
||||
|
||||
message CoverResult {
|
||||
repeated Cover covers = 1;
|
||||
}
|
||||
|
||||
message Cover {
|
||||
uint64 id = 1;
|
||||
bool alpha_channel = 2;
|
||||
bool animated = 3;
|
||||
Game game = 4;
|
||||
int32 height = 5;
|
||||
string image_id = 6;
|
||||
string url = 7;
|
||||
int32 width = 8;
|
||||
string checksum = 9;
|
||||
}
|
||||
|
||||
message ExternalGameResult {
|
||||
repeated ExternalGame externalgames = 1;
|
||||
}
|
||||
|
||||
message ExternalGame {
|
||||
uint64 id = 1;
|
||||
ExternalGameCategoryEnum category = 2;
|
||||
google.protobuf.Timestamp created_at = 3;
|
||||
Game game = 4;
|
||||
string name = 5;
|
||||
string uid = 6;
|
||||
google.protobuf.Timestamp updated_at = 7;
|
||||
string url = 8;
|
||||
int32 year = 9;
|
||||
ExternalGameMediaEnum media = 10;
|
||||
Platform platform = 11;
|
||||
repeated int32 countries = 12;
|
||||
string checksum = 13;
|
||||
}
|
||||
|
||||
|
||||
enum ExternalGameCategoryEnum {
|
||||
EXTERNALGAME_CATEGORY_NULL = 0;
|
||||
EXTERNALGAME_STEAM = 1;
|
||||
EXTERNALGAME_GOG = 5;
|
||||
EXTERNALGAME_YOUTUBE = 10;
|
||||
EXTERNALGAME_MICROSOFT = 11;
|
||||
EXTERNALGAME_APPLE = 13;
|
||||
EXTERNALGAME_TWITCH = 14;
|
||||
EXTERNALGAME_ANDROID = 15;
|
||||
EXTERNALGAME_AMAZON_ASIN = 20;
|
||||
EXTERNALGAME_AMAZON_LUNA = 22;
|
||||
EXTERNALGAME_AMAZON_ADG = 23;
|
||||
EXTERNALGAME_EPIC_GAME_STORE = 26;
|
||||
EXTERNALGAME_OCULUS = 28;
|
||||
}
|
||||
|
||||
|
||||
enum ExternalGameMediaEnum {
|
||||
EXTERNALGAME_MEDIA_NULL = 0;
|
||||
EXTERNALGAME_DIGITAL = 1;
|
||||
EXTERNALGAME_PHYSICAL = 2;
|
||||
}
|
||||
|
||||
message FranchiseResult {
|
||||
repeated Franchise franchises = 1;
|
||||
}
|
||||
|
||||
message Franchise {
|
||||
uint64 id = 1;
|
||||
google.protobuf.Timestamp created_at = 2;
|
||||
repeated Game games = 3;
|
||||
string name = 4;
|
||||
string slug = 5;
|
||||
google.protobuf.Timestamp updated_at = 6;
|
||||
string url = 7;
|
||||
string checksum = 8;
|
||||
}
|
||||
|
||||
message GameResult {
|
||||
repeated Game games = 1;
|
||||
}
|
||||
|
||||
message Game {
|
||||
uint64 id = 1;
|
||||
repeated AgeRating age_ratings = 2;
|
||||
double aggregated_rating = 3;
|
||||
int32 aggregated_rating_count = 4;
|
||||
repeated AlternativeName alternative_names = 5;
|
||||
repeated Artwork artworks = 6;
|
||||
repeated Game bundles = 7;
|
||||
GameCategoryEnum category = 8;
|
||||
Collection collection = 9;
|
||||
Cover cover = 10;
|
||||
google.protobuf.Timestamp created_at = 11;
|
||||
repeated Game dlcs = 12;
|
||||
repeated Game expansions = 13;
|
||||
repeated ExternalGame external_games = 14;
|
||||
google.protobuf.Timestamp first_release_date = 15;
|
||||
int32 follows = 16;
|
||||
Franchise franchise = 17;
|
||||
repeated Franchise franchises = 18;
|
||||
repeated GameEngine game_engines = 19;
|
||||
repeated GameMode game_modes = 20;
|
||||
repeated Genre genres = 21;
|
||||
int32 hypes = 22;
|
||||
repeated InvolvedCompany involved_companies = 23;
|
||||
repeated Keyword keywords = 24;
|
||||
repeated MultiplayerMode multiplayer_modes = 25;
|
||||
string name = 26;
|
||||
Game parent_game = 27;
|
||||
repeated Platform platforms = 28;
|
||||
repeated PlayerPerspective player_perspectives = 29;
|
||||
double rating = 30;
|
||||
int32 rating_count = 31;
|
||||
repeated ReleaseDate release_dates = 32;
|
||||
repeated Screenshot screenshots = 33;
|
||||
repeated Game similar_games = 34;
|
||||
string slug = 35;
|
||||
repeated Game standalone_expansions = 36;
|
||||
GameStatusEnum status = 37;
|
||||
string storyline = 38;
|
||||
string summary = 39;
|
||||
repeated int32 tags = 40;
|
||||
repeated Theme themes = 41;
|
||||
double total_rating = 42;
|
||||
int32 total_rating_count = 43;
|
||||
google.protobuf.Timestamp updated_at = 44;
|
||||
string url = 45;
|
||||
Game version_parent = 46;
|
||||
string version_title = 47;
|
||||
repeated GameVideo videos = 48;
|
||||
repeated Website websites = 49;
|
||||
string checksum = 50;
|
||||
repeated Game remakes = 51;
|
||||
repeated Game remasters = 52;
|
||||
repeated Game expanded_games = 53;
|
||||
repeated Game ports = 54;
|
||||
repeated Game forks = 55;
|
||||
}
|
||||
|
||||
|
||||
enum GameCategoryEnum {
|
||||
MAIN_GAME = 0;
|
||||
DLC_ADDON = 1;
|
||||
EXPANSION = 2;
|
||||
BUNDLE = 3;
|
||||
STANDALONE_EXPANSION = 4;
|
||||
MOD = 5;
|
||||
EPISODE = 6;
|
||||
SEASON = 7;
|
||||
REMAKE = 8;
|
||||
REMASTER = 9;
|
||||
EXPANDED_GAME = 10;
|
||||
PORT = 11;
|
||||
FORK = 12;
|
||||
}
|
||||
|
||||
|
||||
enum GameStatusEnum {
|
||||
RELEASED = 0;
|
||||
ALPHA = 2;
|
||||
BETA = 3;
|
||||
EARLY_ACCESS = 4;
|
||||
OFFLINE = 5;
|
||||
CANCELLED = 6;
|
||||
RUMORED = 7;
|
||||
DELISTED = 8;
|
||||
}
|
||||
|
||||
message GameEngineResult {
|
||||
repeated GameEngine gameengines = 1;
|
||||
}
|
||||
|
||||
message GameEngine {
|
||||
uint64 id = 1;
|
||||
repeated Company companies = 2;
|
||||
google.protobuf.Timestamp created_at = 3;
|
||||
string description = 4;
|
||||
GameEngineLogo logo = 5;
|
||||
string name = 6;
|
||||
repeated Platform platforms = 7;
|
||||
string slug = 8;
|
||||
google.protobuf.Timestamp updated_at = 9;
|
||||
string url = 10;
|
||||
string checksum = 11;
|
||||
}
|
||||
|
||||
message GameEngineLogoResult {
|
||||
repeated GameEngineLogo gameenginelogos = 1;
|
||||
}
|
||||
|
||||
message GameEngineLogo {
|
||||
uint64 id = 1;
|
||||
bool alpha_channel = 2;
|
||||
bool animated = 3;
|
||||
int32 height = 4;
|
||||
string image_id = 5;
|
||||
string url = 6;
|
||||
int32 width = 7;
|
||||
string checksum = 8;
|
||||
}
|
||||
|
||||
message GameModeResult {
|
||||
repeated GameMode gamemodes = 1;
|
||||
}
|
||||
|
||||
message GameMode {
|
||||
uint64 id = 1;
|
||||
google.protobuf.Timestamp created_at = 2;
|
||||
string name = 3;
|
||||
string slug = 4;
|
||||
google.protobuf.Timestamp updated_at = 5;
|
||||
string url = 6;
|
||||
string checksum = 7;
|
||||
}
|
||||
|
||||
message GameVersionResult {
|
||||
repeated GameVersion gameversions = 1;
|
||||
}
|
||||
|
||||
message GameVersion {
|
||||
uint64 id = 1;
|
||||
google.protobuf.Timestamp created_at = 2;
|
||||
repeated GameVersionFeature features = 3;
|
||||
Game game = 4;
|
||||
repeated Game games = 5;
|
||||
google.protobuf.Timestamp updated_at = 6;
|
||||
string url = 7;
|
||||
string checksum = 8;
|
||||
}
|
||||
|
||||
message GameVersionFeatureResult {
|
||||
repeated GameVersionFeature gameversionfeatures = 1;
|
||||
}
|
||||
|
||||
message GameVersionFeature {
|
||||
uint64 id = 1;
|
||||
GameVersionFeatureCategoryEnum category = 2;
|
||||
string description = 3;
|
||||
int32 position = 4;
|
||||
string title = 5;
|
||||
repeated GameVersionFeatureValue values = 6;
|
||||
string checksum = 7;
|
||||
}
|
||||
|
||||
|
||||
enum GameVersionFeatureCategoryEnum {
|
||||
BOOLEAN = 0;
|
||||
DESCRIPTION = 1;
|
||||
}
|
||||
|
||||
message GameVersionFeatureValueResult {
|
||||
repeated GameVersionFeatureValue gameversionfeaturevalues = 1;
|
||||
}
|
||||
|
||||
message GameVersionFeatureValue {
|
||||
uint64 id = 1;
|
||||
Game game = 2;
|
||||
GameVersionFeature game_feature = 3;
|
||||
GameVersionFeatureValueIncludedFeatureEnum included_feature = 4;
|
||||
string note = 5;
|
||||
string checksum = 6;
|
||||
}
|
||||
|
||||
|
||||
enum GameVersionFeatureValueIncludedFeatureEnum {
|
||||
NOT_INCLUDED = 0;
|
||||
INCLUDED = 1;
|
||||
PRE_ORDER_ONLY = 2;
|
||||
}
|
||||
|
||||
message GameVideoResult {
|
||||
repeated GameVideo gamevideos = 1;
|
||||
}
|
||||
|
||||
message GameVideo {
|
||||
uint64 id = 1;
|
||||
Game game = 2;
|
||||
string name = 3;
|
||||
string video_id = 4;
|
||||
string checksum = 5;
|
||||
}
|
||||
|
||||
message GenreResult {
|
||||
repeated Genre genres = 1;
|
||||
}
|
||||
|
||||
message Genre {
|
||||
uint64 id = 1;
|
||||
google.protobuf.Timestamp created_at = 2;
|
||||
string name = 3;
|
||||
string slug = 4;
|
||||
google.protobuf.Timestamp updated_at = 5;
|
||||
string url = 6;
|
||||
string checksum = 7;
|
||||
}
|
||||
|
||||
message InvolvedCompanyResult {
|
||||
repeated InvolvedCompany involvedcompanies = 1;
|
||||
}
|
||||
|
||||
message InvolvedCompany {
|
||||
uint64 id = 1;
|
||||
Company company = 2;
|
||||
google.protobuf.Timestamp created_at = 3;
|
||||
bool developer = 4;
|
||||
Game game = 5;
|
||||
bool porting = 6;
|
||||
bool publisher = 7;
|
||||
bool supporting = 8;
|
||||
google.protobuf.Timestamp updated_at = 9;
|
||||
string checksum = 10;
|
||||
}
|
||||
|
||||
message KeywordResult {
|
||||
repeated Keyword keywords = 1;
|
||||
}
|
||||
|
||||
message Keyword {
|
||||
uint64 id = 1;
|
||||
google.protobuf.Timestamp created_at = 2;
|
||||
string name = 3;
|
||||
string slug = 4;
|
||||
google.protobuf.Timestamp updated_at = 5;
|
||||
string url = 6;
|
||||
string checksum = 7;
|
||||
}
|
||||
|
||||
message MultiplayerModeResult {
|
||||
repeated MultiplayerMode multiplayermodes = 1;
|
||||
}
|
||||
|
||||
message MultiplayerMode {
|
||||
uint64 id = 1;
|
||||
bool campaigncoop = 2;
|
||||
bool dropin = 3;
|
||||
Game game = 4;
|
||||
bool lancoop = 5;
|
||||
bool offlinecoop = 6;
|
||||
int32 offlinecoopmax = 7;
|
||||
int32 offlinemax = 8;
|
||||
bool onlinecoop = 9;
|
||||
int32 onlinecoopmax = 10;
|
||||
int32 onlinemax = 11;
|
||||
Platform platform = 12;
|
||||
bool splitscreen = 13;
|
||||
bool splitscreenonline = 14;
|
||||
string checksum = 15;
|
||||
}
|
||||
|
||||
message PlatformResult {
|
||||
repeated Platform platforms = 1;
|
||||
}
|
||||
|
||||
message Platform {
|
||||
uint64 id = 1;
|
||||
string abbreviation = 2;
|
||||
string alternative_name = 3;
|
||||
PlatformCategoryEnum category = 4;
|
||||
google.protobuf.Timestamp created_at = 5;
|
||||
int32 generation = 6;
|
||||
string name = 7;
|
||||
PlatformLogo platform_logo = 8;
|
||||
PlatformFamily platform_family = 9;
|
||||
string slug = 10;
|
||||
string summary = 11;
|
||||
google.protobuf.Timestamp updated_at = 12;
|
||||
string url = 13;
|
||||
repeated PlatformVersion versions = 14;
|
||||
repeated PlatformWebsite websites = 15;
|
||||
string checksum = 16;
|
||||
}
|
||||
|
||||
|
||||
enum PlatformCategoryEnum {
|
||||
PLATFORM_CATEGORY_NULL = 0;
|
||||
CONSOLE = 1;
|
||||
ARCADE = 2;
|
||||
PLATFORM = 3;
|
||||
OPERATING_SYSTEM = 4;
|
||||
PORTABLE_CONSOLE = 5;
|
||||
COMPUTER = 6;
|
||||
}
|
||||
|
||||
message PlatformFamilyResult {
|
||||
repeated PlatformFamily platformfamilies = 1;
|
||||
}
|
||||
|
||||
message PlatformFamily {
|
||||
uint64 id = 1;
|
||||
string name = 2;
|
||||
string slug = 3;
|
||||
string checksum = 4;
|
||||
}
|
||||
|
||||
message PlatformLogoResult {
|
||||
repeated PlatformLogo platformlogos = 1;
|
||||
}
|
||||
|
||||
message PlatformLogo {
|
||||
uint64 id = 1;
|
||||
bool alpha_channel = 2;
|
||||
bool animated = 3;
|
||||
int32 height = 4;
|
||||
string image_id = 5;
|
||||
string url = 6;
|
||||
int32 width = 7;
|
||||
string checksum = 8;
|
||||
}
|
||||
|
||||
message PlatformVersionResult {
|
||||
repeated PlatformVersion platformversions = 1;
|
||||
}
|
||||
|
||||
message PlatformVersion {
|
||||
uint64 id = 1;
|
||||
repeated PlatformVersionCompany companies = 2;
|
||||
string connectivity = 3;
|
||||
string cpu = 4;
|
||||
string graphics = 5;
|
||||
PlatformVersionCompany main_manufacturer = 6;
|
||||
string media = 7;
|
||||
string memory = 8;
|
||||
string name = 9;
|
||||
string online = 10;
|
||||
string os = 11;
|
||||
string output = 12;
|
||||
PlatformLogo platform_logo = 13;
|
||||
repeated PlatformVersionReleaseDate platform_version_release_dates = 14;
|
||||
string resolutions = 15;
|
||||
string slug = 16;
|
||||
string sound = 17;
|
||||
string storage = 18;
|
||||
string summary = 19;
|
||||
string url = 20;
|
||||
string checksum = 21;
|
||||
}
|
||||
|
||||
message PlatformVersionCompanyResult {
|
||||
repeated PlatformVersionCompany platformversioncompanies = 1;
|
||||
}
|
||||
|
||||
message PlatformVersionCompany {
|
||||
uint64 id = 1;
|
||||
string comment = 2;
|
||||
Company company = 3;
|
||||
bool developer = 4;
|
||||
bool manufacturer = 5;
|
||||
string checksum = 6;
|
||||
}
|
||||
|
||||
message PlatformVersionReleaseDateResult {
|
||||
repeated PlatformVersionReleaseDate platformversionreleasedates = 1;
|
||||
}
|
||||
|
||||
message PlatformVersionReleaseDate {
|
||||
uint64 id = 1;
|
||||
DateFormatChangeDateCategoryEnum category = 2;
|
||||
google.protobuf.Timestamp created_at = 3;
|
||||
google.protobuf.Timestamp date = 4;
|
||||
string human = 5;
|
||||
int32 m = 6;
|
||||
PlatformVersion platform_version = 7;
|
||||
RegionRegionEnum region = 8;
|
||||
google.protobuf.Timestamp updated_at = 9;
|
||||
int32 y = 10;
|
||||
string checksum = 11;
|
||||
}
|
||||
|
||||
|
||||
enum RegionRegionEnum {
|
||||
REGION_REGION_NULL = 0;
|
||||
EUROPE = 1;
|
||||
NORTH_AMERICA = 2;
|
||||
AUSTRALIA = 3;
|
||||
NEW_ZEALAND = 4;
|
||||
JAPAN = 5;
|
||||
CHINA = 6;
|
||||
ASIA = 7;
|
||||
WORLDWIDE = 8;
|
||||
KOREA = 9;
|
||||
BRAZIL = 10;
|
||||
}
|
||||
|
||||
message PlatformWebsiteResult {
|
||||
repeated PlatformWebsite platformwebsites = 1;
|
||||
}
|
||||
|
||||
message PlatformWebsite {
|
||||
uint64 id = 1;
|
||||
WebsiteCategoryEnum category = 2;
|
||||
bool trusted = 3;
|
||||
string url = 4;
|
||||
string checksum = 5;
|
||||
}
|
||||
|
||||
message PlayerPerspectiveResult {
|
||||
repeated PlayerPerspective playerperspectives = 1;
|
||||
}
|
||||
|
||||
message PlayerPerspective {
|
||||
uint64 id = 1;
|
||||
google.protobuf.Timestamp created_at = 2;
|
||||
string name = 3;
|
||||
string slug = 4;
|
||||
google.protobuf.Timestamp updated_at = 5;
|
||||
string url = 6;
|
||||
string checksum = 7;
|
||||
}
|
||||
|
||||
message ReleaseDateResult {
|
||||
repeated ReleaseDate releasedates = 1;
|
||||
}
|
||||
|
||||
message ReleaseDate {
|
||||
uint64 id = 1;
|
||||
DateFormatChangeDateCategoryEnum category = 2;
|
||||
google.protobuf.Timestamp created_at = 3;
|
||||
google.protobuf.Timestamp date = 4;
|
||||
Game game = 5;
|
||||
string human = 6;
|
||||
int32 m = 7;
|
||||
Platform platform = 8;
|
||||
RegionRegionEnum region = 9;
|
||||
google.protobuf.Timestamp updated_at = 10;
|
||||
int32 y = 11;
|
||||
string checksum = 12;
|
||||
}
|
||||
|
||||
message ScreenshotResult {
|
||||
repeated Screenshot screenshots = 1;
|
||||
}
|
||||
|
||||
message Screenshot {
|
||||
uint64 id = 1;
|
||||
bool alpha_channel = 2;
|
||||
bool animated = 3;
|
||||
Game game = 4;
|
||||
int32 height = 5;
|
||||
string image_id = 6;
|
||||
string url = 7;
|
||||
int32 width = 8;
|
||||
string checksum = 9;
|
||||
}
|
||||
|
||||
message SearchResult {
|
||||
repeated Search searches = 1;
|
||||
}
|
||||
|
||||
message Search {
|
||||
uint64 id = 1;
|
||||
string alternative_name = 2;
|
||||
Character character = 3;
|
||||
Collection collection = 4;
|
||||
Company company = 5;
|
||||
string description = 6;
|
||||
Game game = 7;
|
||||
string name = 8;
|
||||
Platform platform = 9;
|
||||
google.protobuf.Timestamp published_at = 10;
|
||||
TestDummy test_dummy = 11;
|
||||
Theme theme = 12;
|
||||
string checksum = 13;
|
||||
}
|
||||
|
||||
message TestDummyResult {
|
||||
repeated TestDummy testdummies = 1;
|
||||
}
|
||||
|
||||
message TestDummy {
|
||||
uint64 id = 1;
|
||||
bool bool_value = 2;
|
||||
google.protobuf.Timestamp created_at = 3;
|
||||
TestDummyEnumTestEnum enum_test = 4;
|
||||
double float_value = 5;
|
||||
Game game = 6;
|
||||
repeated int32 integer_array = 7;
|
||||
int32 integer_value = 8;
|
||||
string name = 9;
|
||||
int32 new_integer_value = 10;
|
||||
bool private = 11;
|
||||
string slug = 12;
|
||||
repeated string string_array = 13;
|
||||
repeated TestDummy test_dummies = 14;
|
||||
TestDummy test_dummy = 15;
|
||||
google.protobuf.Timestamp updated_at = 16;
|
||||
string url = 17;
|
||||
string checksum = 18;
|
||||
}
|
||||
|
||||
|
||||
enum TestDummyEnumTestEnum {
|
||||
TESTDUMMY_ENUM_TEST_NULL = 0;
|
||||
ENUM1 = 1;
|
||||
ENUM2 = 2;
|
||||
}
|
||||
|
||||
message ThemeResult {
|
||||
repeated Theme themes = 1;
|
||||
}
|
||||
|
||||
message Theme {
|
||||
uint64 id = 1;
|
||||
google.protobuf.Timestamp created_at = 2;
|
||||
string name = 3;
|
||||
string slug = 4;
|
||||
google.protobuf.Timestamp updated_at = 5;
|
||||
string url = 6;
|
||||
string checksum = 7;
|
||||
}
|
||||
|
||||
message WebsiteResult {
|
||||
repeated Website websites = 1;
|
||||
}
|
||||
|
||||
message Website {
|
||||
uint64 id = 1;
|
||||
WebsiteCategoryEnum category = 2;
|
||||
Game game = 3;
|
||||
bool trusted = 4;
|
||||
string url = 5;
|
||||
string checksum = 6;
|
||||
}
|
||||
Reference in New Issue
Block a user