mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-16 16:20:04 +00:00
Very basic implementation of IGDB plugin
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
package de.grimsi.gameyfin.pluginapi.gamemetadata
|
package de.grimsi.gameyfin.pluginapi.gamemetadata
|
||||||
|
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ class GameMetadata(
|
|||||||
)
|
)
|
||||||
|
|
||||||
enum class Genre {
|
enum class Genre {
|
||||||
|
UNKNOWN,
|
||||||
PINBALL,
|
PINBALL,
|
||||||
ADVENTURE,
|
ADVENTURE,
|
||||||
INDIE,
|
INDIE,
|
||||||
@@ -45,6 +47,7 @@ enum class Genre {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum class Theme {
|
enum class Theme {
|
||||||
|
UNKNOWN,
|
||||||
ACTION,
|
ACTION,
|
||||||
FANTASY,
|
FANTASY,
|
||||||
SCIENCE_FICTION,
|
SCIENCE_FICTION,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ subprojects {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly(project(":plugin-api"))
|
compileOnly(project(":plugin-api"))
|
||||||
|
implementation("io.github.oshai:kotlin-logging-jvm:7.0.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.jar {
|
tasks.jar {
|
||||||
@@ -26,4 +27,19 @@ subprojects {
|
|||||||
from(sourceSets["main"].output.classesDirs)
|
from(sourceSets["main"].output.classesDirs)
|
||||||
from(sourceSets["main"].resources)
|
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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,18 +8,3 @@ dependencies {
|
|||||||
// IGDB API client
|
// IGDB API client
|
||||||
implementation("io.github.husnjak:igdb-api-jvm:1.2.0")
|
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
|
package de.grimsi.gameyfin.plugins.igdb
|
||||||
|
|
||||||
|
import com.api.igdb.apicalypse.APICalypse
|
||||||
import com.api.igdb.request.IGDBWrapper
|
import com.api.igdb.request.IGDBWrapper
|
||||||
import com.api.igdb.request.TwitchAuthenticator
|
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.GameMetadata
|
||||||
import de.grimsi.gameyfin.pluginapi.gamemetadata.GameMetadataFetcher
|
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.Extension
|
||||||
import org.pf4j.Plugin
|
import org.pf4j.Plugin
|
||||||
import org.pf4j.PluginWrapper
|
import org.pf4j.PluginWrapper
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
import kotlin.collections.filter
|
||||||
|
|
||||||
class IgdbPlugin(wrapper: PluginWrapper) : Plugin(wrapper) {
|
class IgdbPlugin(wrapper: PluginWrapper) : Plugin(wrapper) {
|
||||||
|
|
||||||
|
private val log = KotlinLogging.logger {}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val config: IgdbPluginConfig = IgdbPluginConfig(null, null)
|
||||||
|
}
|
||||||
|
|
||||||
override fun start() {
|
override fun start() {
|
||||||
authenticate()
|
authenticate()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun stop() {
|
override fun stop() {
|
||||||
println("IgdbPlugin.stop()")
|
log.debug { "IgdbPlugin.stop()" }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun authenticate() {
|
private fun authenticate() {
|
||||||
// Kotlin example
|
log.debug { "Authenticating on Twitch API..." }
|
||||||
val token = TwitchAuthenticator.requestTwitchToken("CLIENT_ID", "CLIENT_SECRET")
|
|
||||||
if (token == null) {
|
val clientId: String = config.clientId ?: throw PluginConfigError("Twitch Client ID not set")
|
||||||
println("Failed to authenticate with Twitch")
|
val clientSecret: String = config.clientSecret ?: throw PluginConfigError("Twitch Client Secret not set")
|
||||||
return
|
|
||||||
}
|
val token = TwitchAuthenticator.requestTwitchToken(clientId, clientSecret)
|
||||||
IGDBWrapper.setCredentials("client_id", token.access_token)
|
?: throw PluginConfigError("Failed to authenticate on Twitch API")
|
||||||
|
|
||||||
|
IGDBWrapper.setCredentials(clientId, token.access_token)
|
||||||
|
|
||||||
|
log.debug { "Authentication successful" }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Extension
|
@Extension
|
||||||
class IgdbMetadataFetcher : GameMetadataFetcher {
|
class IgdbMetadataFetcher : GameMetadataFetcher {
|
||||||
override fun getConfig(): Map<String, String> {
|
private val log = KotlinLogging.logger {}
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setConfig(config: Map<String, String>) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun fetchMetadata(gameId: String): GameMetadata {
|
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(
|
return GameMetadata(
|
||||||
title = "Test Game",
|
title = game.name,
|
||||||
description = "This is a test game",
|
description = game.summary,
|
||||||
release = Instant.now(),
|
release = Instant.ofEpochSecond(game.firstReleaseDate.seconds),
|
||||||
userRating = 0,
|
userRating = game.rating.toInt(),
|
||||||
criticRating = 0,
|
criticRating = game.aggregatedRating.toInt(),
|
||||||
developedBy = listOf("Test Developer"),
|
developedBy = game.involvedCompaniesList.filter { it.developer }.map { it.company.name },
|
||||||
publishedBy = listOf("Test Publisher"),
|
publishedBy = game.involvedCompaniesList.filter { it.publisher }.map { it.company.name },
|
||||||
genres = listOf(),
|
genres = game.genresList.map { mapGenre(it) },
|
||||||
themes = listOf(),
|
themes = game.themesList.map { mapTheme(it) },
|
||||||
screenshotUrls = listOf(),
|
screenshotUrls = listOf(),
|
||||||
videoUrls = listOf(),
|
videoUrls = listOf(),
|
||||||
features = listOf(),
|
features = listOf(),
|
||||||
perspectives = 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user