Finish implementing IGDB plugin

Updated Plugin API
Updated Steam plugin
Other minor improvements
This commit is contained in:
grimsi
2024-12-21 19:01:33 +01:00
parent 7b12ce1029
commit 890748fb7c
22 changed files with 347 additions and 90 deletions
@@ -59,9 +59,43 @@ class IgdbPlugin(wrapper: PluginWrapper) : GameyfinPlugin(wrapper) {
@Extension
class IgdbMetadataProvider : GameMetadataProvider {
private val QUERY_FIELDS = listOf(
"slug",
"name",
"summary",
"first_release_date",
"rating",
"aggregated_rating",
"total_rating",
"category",
"multiplayer_modes.lancoop",
"game_modes.slug",
"game_modes.name",
"cover.image_id",
"screenshots.image_id",
"videos.video_id",
"involved_companies.company.slug",
"involved_companies.company.name",
"involved_companies.developer",
"involved_companies.publisher",
"involved_companies.company.logo.image_id",
"genres.slug",
"genres.name",
"keywords.slug",
"keywords.name",
"themes.slug",
"themes.name",
"player_perspectives.slug",
"player_perspectives.name",
"platforms.slug",
"platforms.name",
"platforms.platform_logo.image_id"
).joinToString(",")
override fun fetchMetadata(gameId: String): GameMetadata? {
val findBySlugQuery = APICalypse()
.fields("*")
.fields(QUERY_FIELDS)
.where("slug = \"${guessSlug(gameId)}\"")
// First step: Try to find the game by guessing the slug
@@ -70,7 +104,7 @@ class IgdbPlugin(wrapper: PluginWrapper) : GameyfinPlugin(wrapper) {
// Second step: Try a fuzzy search
if (game == null) {
val searchByNameQuery = APICalypse()
.fields("*")
.fields(QUERY_FIELDS)
.limit(100)
.search(gameId)
@@ -91,14 +125,15 @@ class IgdbPlugin(wrapper: PluginWrapper) : GameyfinPlugin(wrapper) {
release = Instant.ofEpochSecond(game.firstReleaseDate.seconds),
userRating = game.rating.toInt(),
criticRating = game.aggregatedRating.toInt(),
developedBy = game.involvedCompaniesList.filter { it.developer }.map { it.company.name },
publishedBy = game.involvedCompaniesList.filter { it.publisher }.map { it.company.name },
genres = game.genresList.map { Mapper.genre(it) },
themes = game.themesList.map { Mapper.theme(it) },
screenshotUrls = listOf(),
videoUrls = listOf(),
features = listOf(),
perspectives = listOf()
developedBy = game.involvedCompaniesList.filter { it.developer }.map { it.company.name }.toSet(),
publishedBy = game.involvedCompaniesList.filter { it.publisher }.map { it.company.name }.toSet(),
genres = game.genresList.map { Mapper.genre(it) }.toSet(),
themes = game.themesList.map { Mapper.theme(it) }.toSet(),
keywords = game.keywordsList.map { it.name }.toSet(),
screenshotUrls = game.screenshotsList.map { Mapper.screenshot(it) }.toSet(),
videoUrls = game.videosList.map { Mapper.video(it) }.toSet(),
features = Mapper.gameFeatures(game),
perspectives = game.playerPerspectivesList.map { Mapper.playerPerspective(it) }.toSet()
)
}
@@ -1,8 +1,15 @@
package de.grimsi.gameyfin.plugins.igdb
import com.api.igdb.utils.ImageSize
import com.api.igdb.utils.ImageType
import com.api.igdb.utils.imageBuilder
import de.grimsi.gameyfin.pluginapi.gamemetadata.GameFeature
import de.grimsi.gameyfin.pluginapi.gamemetadata.Genre
import de.grimsi.gameyfin.pluginapi.gamemetadata.PlayerPerspective
import de.grimsi.gameyfin.pluginapi.gamemetadata.Theme
import org.slf4j.LoggerFactory
import java.net.URI
import java.net.URL
class Mapper {
companion object {
@@ -70,5 +77,49 @@ class Mapper {
}
}
}
fun playerPerspective(perspective: proto.PlayerPerspective): PlayerPerspective {
return when (perspective.slug) {
"first-person" -> PlayerPerspective.FIRST_PERSON
"third-person" -> PlayerPerspective.THIRD_PERSON
"bird-view-isometric" -> PlayerPerspective.BIRD_VIEW_ISOMETRIC
"side-view" -> PlayerPerspective.SIDE_VIEW
"text" -> PlayerPerspective.TEXT
"auditory" -> PlayerPerspective.AUDITORY
"virtual-reality" -> PlayerPerspective.VIRTUAL_REALITY
else -> {
log.warn("Unknown player perspective: {}", perspective.slug)
PlayerPerspective.UNKNOWN
}
}
}
fun screenshot(screenshot: proto.Screenshot): URL {
return URI(imageBuilder(screenshot.imageId, ImageSize.SCREENSHOT_HUGE, ImageType.PNG)).toURL()
}
fun video(video: proto.GameVideo): URL {
return URI("https://www.youtube.com/watch?v=${video.videoId}").toURL()
}
fun gameFeatures(game: proto.Game): Set<GameFeature> {
var gameFeatures = mutableSetOf<GameFeature>()
// Get LAN support from multiplayer modes
if (game.multiplayerModesList.any { it.lancoop }) gameFeatures.add(GameFeature.LOCAL_MULTIPLAYER)
for (gameMode in game.gameModesList) {
when (gameMode.slug) {
"single-player" -> gameFeatures.add(GameFeature.SINGLEPLAYER)
"multiplayer" -> gameFeatures.add(GameFeature.MULTIPLAYER)
"co-operative" -> gameFeatures.add(GameFeature.CO_OP)
"split-screen" -> gameFeatures.add(GameFeature.SPLITSCREEN)
else -> {
log.warn("Unknown game mode: {}", gameMode.slug)
}
}
}
return gameFeatures
}
}
}
@@ -112,14 +112,15 @@ class SteamPlugin(wrapper: PluginWrapper) : GameyfinPlugin(wrapper) {
release = date(game["release_date"]?.jsonObject["date"]?.jsonPrimitive?.content!!),
userRating = 0,
criticRating = 0,
developedBy = stringList(game, "developers"),
publishedBy = stringList(game, "publishers"),
genres = emptyList(),
themes = emptyList(),
screenshotUrls = emptyList(),
videoUrls = emptyList(),
features = emptyList(),
perspectives = emptyList()
developedBy = stringList(game, "developers").toSet(),
publishedBy = stringList(game, "publishers").toSet(),
genres = emptySet(),
themes = emptySet(),
keywords = emptySet(),
screenshotUrls = emptySet(),
videoUrls = emptySet(),
features = emptySet(),
perspectives = emptySet()
)
return metadata