Extend Plugin API to return a list of covers and header images

Implement dedicated header image in GameView
Implement GameHeaderPicker
This commit is contained in:
GRIMSIM
2025-06-16 16:56:46 +02:00
parent ac4eaf915e
commit 5e52d11835
33 changed files with 454 additions and 159 deletions
@@ -1,4 +1,4 @@
Plugin-Version: 1.0.0-beta1
Plugin-Version: 1.0.0.beta1
Plugin-Class: org.gameyfin.plugins.download.direct.DirectDownloadPlugin
Plugin-Id: org.gameyfin.plugins.download.direct
Plugin-Name: Direct Download
@@ -190,7 +190,7 @@ class IgdbPlugin(wrapper: PluginWrapper) : ConfigurableGameyfinPlugin(wrapper) {
originalId = game.slug,
title = game.name,
description = game.summary,
coverUrl = Mapper.cover(game.cover),
coverUrls = Mapper.cover(game.cover)?.let { listOf(it) },
release = if (game.firstReleaseDate.seconds > 0) Instant.ofEpochSecond(game.firstReleaseDate.seconds) else null,
userRating = game.rating.toInt(),
criticRating = game.aggregatedRating.toInt(),
+2 -2
View File
@@ -1,6 +1,6 @@
Plugin-Version: 1.0.0-beta1
Plugin-Version: 1.0.0.beta2
Plugin-Class: org.gameyfin.plugins.metadata.igdb.IgdbPlugin
Plugin-Id: org.gameyfin.plugins.metadata.igdb.
Plugin-Id: org.gameyfin.plugins.metadata.igdb
Plugin-Name: IGDB Metadata
Plugin-Description: Fetches metadata from IGDB.<br>
Requires a Twitch account and IGDB API credentials.<br>
@@ -115,14 +115,14 @@ class SteamPlugin(wrapper: PluginWrapper) : GameyfinPlugin(wrapper) {
originalId = id.toString(),
title = sanitizeTitle(game.name),
description = game.detailedDescription,
coverUrl = game.headerImage?.let { URI(it) },
coverUrls = game.headerImage?.let { URI(it) }?.let { listOf(it) },
release = game.releaseDate?.date,
developedBy = game.developers?.toSet(),
publishedBy = game.publishers?.toSet(),
genres = game.genres?.let { it.map { Mapper.genre(it) }.toSet() },
keywords = game.categories?.let { it.mapNotNull { it.description }.toSet() },
screenshotUrls = game.screenshots?.let { it.map { URI(it.pathFull) }.toSet() },
videoUrls = game.movies?.let { it.mapNotNull { it.webm?.let { URI(it.max) } }.toSet() }
genres = game.genres?.let { genre -> genre.map { Mapper.genre(it) }.toSet() },
keywords = game.categories?.mapNotNull { it.description }?.toSet(),
screenshotUrls = game.screenshots?.map { URI(it.pathFull) }?.toSet(),
videoUrls = game.movies?.mapNotNull { video -> video.webm?.let { URI(it.max) } }?.toSet()
)
return metadata
+1 -1
View File
@@ -1,4 +1,4 @@
Plugin-Version: 1.0.0-beta1
Plugin-Version: 1.0.0.beta2
Plugin-Class: org.gameyfin.plugins.metadata.steam.SteamPlugin
Plugin-Id: org.gameyfin.plugins.metadata.steam
Plugin-Name: Steam Metadata
@@ -8,6 +8,7 @@ import org.gameyfin.pluginapi.gamemetadata.GameMetadataProvider
import org.gameyfin.plugins.metadata.steamgriddb.api.SteamGridDbApiClient
import org.gameyfin.plugins.metadata.steamgriddb.dto.SteamGridDbGame
import org.gameyfin.plugins.metadata.steamgriddb.dto.SteamGridDbGrid
import org.gameyfin.plugins.metadata.steamgriddb.dto.SteamGridDbHero
import org.pf4j.Extension
import org.pf4j.PluginWrapper
import java.net.URI
@@ -74,25 +75,18 @@ class SteamGridDbPlugin(wrapper: PluginWrapper) : ConfigurableGameyfinPlugin(wra
override fun fetchByTitle(gameTitle: String, maxResults: Int): List<GameMetadata> {
return runBlocking {
val covers = mutableListOf<GameMetadata>()
val games = searchSteamGridDb(gameTitle)
val results = searchSteamGridDb(gameTitle)
for (game in games) {
val gameDetails = client?.grids(game.id)
val grids = gameDetails?.data.orEmpty()
for (grid in grids) {
covers.add(
GameMetadata(
originalId = game.id.toString(),
title = game.name,
coverUrl = URI(grid.url)
)
)
if (covers.size >= maxResults) break
}
if (covers.size >= maxResults) break
}
covers
results.map { game ->
val grids = getGridsForGame(game.id)
val heroes = getHeroesForGame(game.id)
GameMetadata(
originalId = game.id.toString(),
title = game.name,
coverUrls = grids?.map { URI(it.url) },
headerUrls = heroes?.map { URI(it.url) }
)
}.take(maxResults)
}
}
@@ -101,10 +95,14 @@ class SteamGridDbPlugin(wrapper: PluginWrapper) : ConfigurableGameyfinPlugin(wra
val gameId = id.toIntOrNull() ?: return@runBlocking null
val game = getGameById(gameId) ?: return@runBlocking null
val grids = getGridsForGame(game.id)
val heroes = getHeroesForGame(game.id)
return@runBlocking GameMetadata(
originalId = game.id.toString(),
title = game.name,
coverUrl = getGridForGame(game.id)?.let { grid -> URI(grid.url) }
coverUrls = grids?.map { URI(it.url) },
headerUrls = heroes?.map { URI(it.url) }
)
}
}
@@ -121,12 +119,20 @@ class SteamGridDbPlugin(wrapper: PluginWrapper) : ConfigurableGameyfinPlugin(wra
}
}
private suspend fun getGridForGame(gameId: Int): SteamGridDbGrid? {
private suspend fun getGridsForGame(gameId: Int): List<SteamGridDbGrid>? {
val client = client ?: throw PluginConfigError("SteamGridDB API client not initialized")
val gameDetails = client.grids(gameId)
return gameDetails.data?.firstOrNull()
return gameDetails.data
}
private suspend fun getHeroesForGame(gameId: Int): List<SteamGridDbHero>? {
val client = client ?: throw PluginConfigError("SteamGridDB API client not initialized")
val gameDetails = client.heroes(gameId)
return gameDetails.data
}
private suspend fun getGameById(gameId: Int): SteamGridDbGame? {
@@ -11,6 +11,7 @@ import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Json
import org.gameyfin.plugins.metadata.steamgriddb.dto.SteamGridDbGameResult
import org.gameyfin.plugins.metadata.steamgriddb.dto.SteamGridDbGridResult
import org.gameyfin.plugins.metadata.steamgriddb.dto.SteamGridDbHeroResult
import org.gameyfin.plugins.metadata.steamgriddb.dto.SteamGridDbSearchResult
@@ -52,6 +53,12 @@ class SteamGridDbApiClient(private val apiKey: String) {
}.body()
}
suspend fun heroes(gameId: Int, block: HttpRequestBuilder.() -> Unit = {}): SteamGridDbHeroResult {
return get("heroes/game/$gameId") {
block()
}.body()
}
suspend fun game(gameId: Int, block: HttpRequestBuilder.() -> Unit = {}): SteamGridDbGameResult {
return get("games/id/$gameId", block).body()
}
@@ -11,7 +11,5 @@ data class SteamGridDbGridResult(
@Serializable
data class SteamGridDbGrid(
val id: Int,
val width: Int,
val height: Int,
val url: String
)
@@ -0,0 +1,15 @@
package org.gameyfin.plugins.metadata.steamgriddb.dto
import kotlinx.serialization.Serializable
@Serializable
data class SteamGridDbHeroResult(
val success: Boolean,
val data: List<SteamGridDbHero>?
)
@Serializable
data class SteamGridDbHero(
val id: Int,
val url: String
)
@@ -1,4 +1,4 @@
Plugin-Version: 1.0.0-beta1
Plugin-Version: 1.0.0.beta2
Plugin-Class: org.gameyfin.plugins.metadata.steamgriddb.SteamGridDbPlugin
Plugin-Id: org.gameyfin.plugins.metadata.steamgriddb
Plugin-Name: SteamGridDB Covers
@@ -1,4 +1,4 @@
Plugin-Version: 1.0.0-beta1
Plugin-Version: 1.0.0.beta1
Plugin-Class: org.gameyfin.plugins.download.torrent.TorrentDownloadPlugin
Plugin-Id: org.gameyfin.plugins.download.torrent
Plugin-Name: Torrent Download