Very basic implementation of IGDB plugin

This commit is contained in:
grimsi
2024-10-30 16:30:28 +01:00
parent fdfeac3725
commit a4ce0826cc
4 changed files with 125 additions and 39 deletions
@@ -1,4 +1,5 @@
package de.grimsi.gameyfin.pluginapi.gamemetadata
import java.net.URL
import java.time.Instant
@@ -19,6 +20,7 @@ class GameMetadata(
)
enum class Genre {
UNKNOWN,
PINBALL,
ADVENTURE,
INDIE,
@@ -45,6 +47,7 @@ enum class Genre {
}
enum class Theme {
UNKNOWN,
ACTION,
FANTASY,
SCIENCE_FICTION,
+16
View File
@@ -7,6 +7,7 @@ subprojects {
dependencies {
compileOnly(project(":plugin-api"))
implementation("io.github.oshai:kotlin-logging-jvm:7.0.0")
}
tasks.jar {
@@ -26,4 +27,19 @@ subprojects {
from(sourceSets["main"].output.classesDirs)
from(sourceSets["main"].resources)
}
tasks.register<Copy>("copyDependencyClasses") {
dependsOn(tasks.jar)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from(configurations.runtimeClasspath.get().map { project.zipTree(it) }) {
include("**/*.class")
}
into(layout.buildDirectory.get().asFile.resolve("classes/kotlin/main"))
}
tasks.build {
dependsOn("copyDependencyClasses")
}
}
-15
View File
@@ -7,19 +7,4 @@ dependencies {
// IGDB API client
implementation("io.github.husnjak:igdb-api-jvm:1.2.0")
}
tasks.register<Copy>("copyDependencyClasses") {
dependsOn(tasks.jar)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from(configurations.runtimeClasspath.get().map { project.zipTree(it) }) {
include("**/*.class")
}
into(layout.buildDirectory.get().asFile.resolve("classes/kotlin/main"))
}
tasks.build {
dependsOn("copyDependencyClasses")
}
@@ -1,60 +1,142 @@
package de.grimsi.gameyfin.plugins.igdb
import com.api.igdb.apicalypse.APICalypse
import com.api.igdb.request.IGDBWrapper
import com.api.igdb.request.TwitchAuthenticator
import com.api.igdb.request.games
import de.grimsi.gameyfin.pluginapi.core.PluginConfigError
import de.grimsi.gameyfin.pluginapi.gamemetadata.GameMetadata
import de.grimsi.gameyfin.pluginapi.gamemetadata.GameMetadataFetcher
import de.grimsi.gameyfin.pluginapi.gamemetadata.Genre
import de.grimsi.gameyfin.pluginapi.gamemetadata.Theme
import io.github.oshai.kotlinlogging.KotlinLogging
import org.pf4j.Extension
import org.pf4j.Plugin
import org.pf4j.PluginWrapper
import java.time.Instant
import kotlin.collections.filter
class IgdbPlugin(wrapper: PluginWrapper) : Plugin(wrapper) {
private val log = KotlinLogging.logger {}
companion object {
val config: IgdbPluginConfig = IgdbPluginConfig(null, null)
}
override fun start() {
authenticate()
}
override fun stop() {
println("IgdbPlugin.stop()")
log.debug { "IgdbPlugin.stop()" }
}
private fun authenticate() {
// Kotlin example
val token = TwitchAuthenticator.requestTwitchToken("CLIENT_ID", "CLIENT_SECRET")
if (token == null) {
println("Failed to authenticate with Twitch")
return
}
IGDBWrapper.setCredentials("client_id", token.access_token)
log.debug { "Authenticating on Twitch API..." }
val clientId: String = config.clientId ?: throw PluginConfigError("Twitch Client ID not set")
val clientSecret: String = config.clientSecret ?: throw PluginConfigError("Twitch Client Secret not set")
val token = TwitchAuthenticator.requestTwitchToken(clientId, clientSecret)
?: throw PluginConfigError("Failed to authenticate on Twitch API")
IGDBWrapper.setCredentials(clientId, token.access_token)
log.debug { "Authentication successful" }
}
@Extension
class IgdbMetadataFetcher : GameMetadataFetcher {
override fun getConfig(): Map<String, String> {
TODO("Not yet implemented")
}
override fun setConfig(config: Map<String, String>) {
TODO("Not yet implemented")
}
private val log = KotlinLogging.logger {}
override fun fetchMetadata(gameId: String): GameMetadata {
val findGameByName = APICalypse()
.fields("*")
.limit(100)
.search(gameId)
val game = IGDBWrapper.games(findGameByName).filter { it.slug == gameId.lowercase() }.firstOrNull()
?: throw IllegalArgumentException("Could not match game with ID '$gameId'")
return GameMetadata(
title = "Test Game",
description = "This is a test game",
release = Instant.now(),
userRating = 0,
criticRating = 0,
developedBy = listOf("Test Developer"),
publishedBy = listOf("Test Publisher"),
genres = listOf(),
themes = listOf(),
title = game.name,
description = game.summary,
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 { mapGenre(it) },
themes = game.themesList.map { mapTheme(it) },
screenshotUrls = listOf(),
videoUrls = listOf(),
features = listOf(),
perspectives = listOf()
)
}
private fun mapGenre(genre: proto.Genre): Genre {
return when (genre.slug) {
"pinball" -> Genre.PINBALL
"adventure" -> Genre.ADVENTURE
"indie" -> Genre.INDIE
"arcade" -> Genre.ARCADE
"visual-novel" -> Genre.VISUAL_NOVEL
"card-and-board-game" -> Genre.CARD_AND_BOARD_GAME
"moba" -> Genre.MOBA
"point-and-click" -> Genre.POINT_AND_CLICK
"fighting" -> Genre.FIGHTING
"shooter" -> Genre.SHOOTER
"music" -> Genre.MUSIC
"platform" -> Genre.PLATFORM
"puzzle" -> Genre.PUZZLE
"racing" -> Genre.RACING
"real-time-strategy-rts" -> Genre.REAL_TIME_STRATEGY
"role-playing-rpg" -> Genre.ROLE_PLAYING
"simulator" -> Genre.SIMULATOR
"sport" -> Genre.SPORT
"strategy" -> Genre.STRATEGY
"turn-based-strategy-tbs" -> Genre.TURN_BASED_STRATEGY
"tactical" -> Genre.TACTICAL
"hack-and-slash-beat-em-up" -> Genre.HACK_AND_SLASH_BEAT_EM_UP
"quiz-trivia" -> Genre.QUIZ_TRIVIA
else -> {
log.warn { "Unknown genre: ${genre.slug}" }
Genre.UNKNOWN
}
}
}
private fun mapTheme(theme: proto.Theme): Theme {
return when (theme.slug) {
"action" -> Theme.ACTION
"fantasy" -> Theme.FANTASY
"horror" -> Theme.HORROR
"sci-fi" -> Theme.SCIENCE_FICTION
"mystery" -> Theme.MYSTERY
"thriller" -> Theme.THRILLER
"survival" -> Theme.SURVIVAL
"historical" -> Theme.HISTORICAL
"stealth" -> Theme.STEALTH
"comedy" -> Theme.COMEDY
"business" -> Theme.BUSINESS
"drama" -> Theme.DRAMA
"non-fiction" -> Theme.NON_FICTION
"sandbox" -> Theme.SANDBOX
"educational" -> Theme.EDUCATIONAL
"kids" -> Theme.KIDS
"open-world" -> Theme.OPEN_WORLD
"warfare" -> Theme.WARFARE
"party" -> Theme.PARTY
"4x-explore-expand-exploit-and-exterminate" -> Theme.FOUR_X
"erotic" -> Theme.EROTIC
"romance" -> Theme.ROMANCE
else -> {
log.warn { "Unknown theme: ${theme.slug}" }
Theme.UNKNOWN
}
}
}
}
}