mirror of
https://github.com/grimsi/gameyfin.git
synced 2026-02-06 11:27:07 +00:00
Finish implementing IGDB plugin
Updated Plugin API Updated Steam plugin Other minor improvements
This commit is contained in:
parent
7b12ce1029
commit
890748fb7c
@ -10,6 +10,7 @@
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="clean" />
|
||||
<option value="build" />
|
||||
</list>
|
||||
</option>
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="clean" />
|
||||
<option value="build" />
|
||||
</list>
|
||||
</option>
|
||||
|
||||
@ -94,19 +94,15 @@ class GameyfinPluginManager(
|
||||
}
|
||||
|
||||
try {
|
||||
log.info { "${"Start plugin '{}'"} ${getPluginLabel(pluginWrapper.descriptor)}"}
|
||||
log.info { "Start plugin '${getPluginLabel(pluginWrapper.descriptor)}'"}
|
||||
pluginWrapper.plugin.start()
|
||||
pluginWrapper.pluginState = PluginState.STARTED
|
||||
pluginWrapper.failedException = null
|
||||
startedPlugins.add(pluginWrapper)
|
||||
} catch (e: LinkageError) {
|
||||
pluginWrapper.pluginState = PluginState.FAILED
|
||||
pluginWrapper.failedException = e
|
||||
log.error { "${"Unable to start plugin '{}'"} ${getPluginLabel(pluginWrapper.descriptor)} $e"}
|
||||
} catch (e: Exception) {
|
||||
pluginWrapper.pluginState = PluginState.FAILED
|
||||
pluginWrapper.failedException = e
|
||||
log.error { "${"Unable to start plugin '{}'"} ${getPluginLabel(pluginWrapper.descriptor)} $e"}
|
||||
log.error { "Unable to start plugin '${getPluginLabel(pluginWrapper.descriptor)}': $e"}
|
||||
} finally {
|
||||
firePluginStateEvent(PluginStateEvent(this, pluginWrapper, pluginState))
|
||||
}
|
||||
|
||||
@ -9,9 +9,9 @@ import jakarta.annotation.security.RolesAllowed
|
||||
class PluginManagementEndpoint(
|
||||
private val pluginManagementService: PluginManagementService
|
||||
) {
|
||||
fun getPlugins() = pluginManagementService.getPlugins()
|
||||
fun getPlugins() = pluginManagementService.getPluginDtos()
|
||||
|
||||
fun getPlugin(pluginId: String) = pluginManagementService.getPlugin(pluginId)
|
||||
fun getPlugin(pluginId: String) = pluginManagementService.getPluginDto(pluginId)
|
||||
|
||||
fun startPlugin(pluginId: String) = pluginManagementService.startPlugin(pluginId)
|
||||
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
package de.grimsi.gameyfin.core.plugins.management
|
||||
|
||||
import org.pf4j.ExtensionPoint
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class PluginManagementService(
|
||||
private val pluginManager: GameyfinPluginManager
|
||||
private val pluginManager: GameyfinPluginManager,
|
||||
private val pluginManagementRepository: PluginManagementRepository
|
||||
) {
|
||||
fun getPlugins(): List<PluginDto> {
|
||||
fun getPluginDtos(): List<PluginDto> {
|
||||
return pluginManager.plugins.map {
|
||||
PluginDto(
|
||||
it.pluginId,
|
||||
@ -18,7 +21,7 @@ class PluginManagementService(
|
||||
}
|
||||
}
|
||||
|
||||
fun getPlugin(pluginId: String): PluginDto {
|
||||
fun getPluginDto(pluginId: String): PluginDto {
|
||||
val plugin = pluginManager.getPlugin(pluginId)
|
||||
return PluginDto(
|
||||
plugin.pluginId,
|
||||
@ -29,6 +32,17 @@ class PluginManagementService(
|
||||
)
|
||||
}
|
||||
|
||||
fun getPluginManagementEntry(pluginId: String): PluginManagementEntry {
|
||||
return pluginManagementRepository.findByIdOrNull(pluginId)
|
||||
?: throw IllegalArgumentException("Plugin with ID $pluginId not found")
|
||||
}
|
||||
|
||||
fun getPluginManagementEntry(clazz: Class<ExtensionPoint>): PluginManagementEntry {
|
||||
val pluginWrapper = pluginManager.whichPlugin(clazz)
|
||||
return pluginManagementRepository.findByIdOrNull(pluginWrapper.pluginId)
|
||||
?: throw IllegalArgumentException("Plugin with class $clazz not found")
|
||||
}
|
||||
|
||||
fun startPlugin(pluginId: String) {
|
||||
pluginManager.startPlugin(pluginId)
|
||||
}
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
package de.grimsi.gameyfin.games
|
||||
|
||||
import jakarta.persistence.*
|
||||
import java.time.Instant
|
||||
|
||||
@Entity
|
||||
class Game(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
var id: Long? = null,
|
||||
|
||||
val title: String,
|
||||
|
||||
@Lob
|
||||
@Column(columnDefinition = "CLOB")
|
||||
val comment: String? = null,
|
||||
|
||||
@Lob
|
||||
@Column(columnDefinition = "CLOB")
|
||||
val summary: String,
|
||||
|
||||
val release: Instant,
|
||||
|
||||
@ElementCollection
|
||||
val publishers: List<String>,
|
||||
|
||||
@ElementCollection
|
||||
val developers: List<String>,
|
||||
|
||||
@Column(unique = true)
|
||||
val path: String,
|
||||
|
||||
val source: String
|
||||
)
|
||||
@ -1,5 +1,14 @@
|
||||
package de.grimsi.gameyfin.games
|
||||
|
||||
import de.grimsi.gameyfin.core.plugins.management.PluginManagementService
|
||||
import de.grimsi.gameyfin.games.entities.Company
|
||||
import de.grimsi.gameyfin.games.entities.CompanyType
|
||||
import de.grimsi.gameyfin.games.entities.Game
|
||||
import de.grimsi.gameyfin.games.entities.Screenshot
|
||||
import de.grimsi.gameyfin.games.repositories.CompanyRepository
|
||||
import de.grimsi.gameyfin.games.repositories.GameRepository
|
||||
import de.grimsi.gameyfin.games.repositories.ScreenshotContentStore
|
||||
import de.grimsi.gameyfin.games.repositories.ScreenshotRepository
|
||||
import de.grimsi.gameyfin.pluginapi.gamemetadata.GameMetadata
|
||||
import de.grimsi.gameyfin.pluginapi.gamemetadata.GameMetadataProvider
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
@ -9,12 +18,18 @@ import kotlinx.coroutines.runBlocking
|
||||
import org.pf4j.PluginManager
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.stereotype.Service
|
||||
import java.net.URL
|
||||
import java.net.URLConnection
|
||||
import java.nio.file.Path
|
||||
|
||||
@Service
|
||||
class GameService(
|
||||
private val pluginManager: PluginManager,
|
||||
private val pluginManagementService: PluginManagementService,
|
||||
private val gameRepository: GameRepository,
|
||||
private val pluginManager: PluginManager
|
||||
private val companyRepository: CompanyRepository,
|
||||
private val screenshotRepository: ScreenshotRepository,
|
||||
private val screenshotContentStore: ScreenshotContentStore
|
||||
) {
|
||||
private val log = KotlinLogging.logger {}
|
||||
|
||||
@ -47,15 +62,11 @@ class GameService(
|
||||
val (plugin, metadata) = metadataResults.entries.firstOrNull { it.value != null }
|
||||
?: throw NoMatchException("Could not match game at $path")
|
||||
|
||||
val game = Game(
|
||||
title = metadata!!.title,
|
||||
summary = metadata.description,
|
||||
release = metadata.release,
|
||||
publishers = metadata.publishedBy,
|
||||
developers = metadata.developedBy,
|
||||
path = path.toString(),
|
||||
source = plugin.javaClass.name
|
||||
)
|
||||
if (metadata == null) {
|
||||
throw NoMatchException("Plugin ${plugin.javaClass} returned invalid metadata for game at $path")
|
||||
}
|
||||
|
||||
val game = toEntity(metadata, path, plugin)
|
||||
|
||||
return createOrUpdate(game)
|
||||
}
|
||||
@ -74,13 +85,48 @@ class GameService(
|
||||
}
|
||||
|
||||
private fun toDto(game: Game): GameDto {
|
||||
if (game.id == null) {
|
||||
throw IllegalArgumentException("Game ID is null")
|
||||
}
|
||||
val gameId = game.id ?: throw IllegalArgumentException("Game ID is null")
|
||||
|
||||
return GameDto(
|
||||
id = game.id!!,
|
||||
id = gameId,
|
||||
title = game.title
|
||||
)
|
||||
}
|
||||
|
||||
private fun toEntity(metadata: GameMetadata, path: Path, source: GameMetadataProvider): Game {
|
||||
return Game(
|
||||
title = metadata.title,
|
||||
summary = metadata.description,
|
||||
release = metadata.release,
|
||||
publishers = metadata.publishedBy.map { toEntity(it, CompanyType.PUBLISHER) }.toSet(),
|
||||
developers = metadata.developedBy.map { toEntity(it, CompanyType.DEVELOPER) }.toSet(),
|
||||
genres = metadata.genres,
|
||||
themes = metadata.themes,
|
||||
keywords = metadata.keywords,
|
||||
features = metadata.features,
|
||||
perspectives = metadata.perspectives,
|
||||
screenshots = metadata.screenshotUrls.map { downloadAndPersist(it) }.toSet(),
|
||||
videoUrls = metadata.videoUrls,
|
||||
path = path.toString(),
|
||||
source = pluginManagementService.getPluginManagementEntry(source.javaClass)
|
||||
)
|
||||
}
|
||||
|
||||
private fun toEntity(companyName: String, companyType: CompanyType): Company {
|
||||
companyRepository.findByNameAndType(companyName, companyType)?.let { return it }
|
||||
val company = Company(name = companyName, type = companyType)
|
||||
return companyRepository.save(company)
|
||||
}
|
||||
|
||||
private fun downloadAndPersist(screenshotUrl: URL): Screenshot {
|
||||
screenshotRepository.findByOriginalUrl(screenshotUrl)?.let { return it }
|
||||
|
||||
val screenshot = Screenshot(originalUrl = screenshotUrl)
|
||||
screenshotUrl.openStream().use { input ->
|
||||
val mimeType = URLConnection.guessContentTypeFromStream(input)
|
||||
screenshot.mimeType = mimeType
|
||||
screenshotContentStore.setContent(screenshot, input)
|
||||
}
|
||||
return screenshotRepository.save(screenshot)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package de.grimsi.gameyfin.games.entities
|
||||
|
||||
import jakarta.persistence.*
|
||||
|
||||
@Entity
|
||||
@Table(uniqueConstraints = [UniqueConstraint(columnNames = ["name", "type"])])
|
||||
class Company(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
var id: Long? = null,
|
||||
val name: String,
|
||||
val type: CompanyType
|
||||
)
|
||||
|
||||
enum class CompanyType {
|
||||
DEVELOPER,
|
||||
PUBLISHER
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package de.grimsi.gameyfin.games.entities
|
||||
|
||||
import de.grimsi.gameyfin.core.plugins.management.PluginManagementEntry
|
||||
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 jakarta.persistence.*
|
||||
import java.net.URL
|
||||
import java.time.Instant
|
||||
|
||||
@Entity
|
||||
class Game(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
var id: Long? = null,
|
||||
|
||||
val title: String,
|
||||
|
||||
@Lob
|
||||
@Column(columnDefinition = "CLOB")
|
||||
val comment: String? = null,
|
||||
|
||||
@Lob
|
||||
@Column(columnDefinition = "CLOB")
|
||||
val summary: String,
|
||||
|
||||
val release: Instant,
|
||||
|
||||
@OneToMany(cascade = [CascadeType.MERGE])
|
||||
val publishers: Set<Company>,
|
||||
|
||||
@OneToMany(cascade = [CascadeType.MERGE])
|
||||
val developers: Set<Company>,
|
||||
|
||||
@ElementCollection
|
||||
val genres: Set<Genre>,
|
||||
|
||||
@ElementCollection
|
||||
val themes: Set<Theme>,
|
||||
|
||||
@ElementCollection
|
||||
val keywords: Set<String>,
|
||||
|
||||
@ElementCollection
|
||||
val features: Set<GameFeature>,
|
||||
|
||||
@ElementCollection
|
||||
val perspectives: Set<PlayerPerspective>,
|
||||
|
||||
@OneToMany(cascade = [CascadeType.MERGE])
|
||||
val screenshots: Set<Screenshot>,
|
||||
|
||||
@ElementCollection
|
||||
val videoUrls: Set<URL>,
|
||||
|
||||
@Column(unique = true)
|
||||
val path: String,
|
||||
|
||||
@ManyToOne
|
||||
val source: PluginManagementEntry
|
||||
)
|
||||
@ -0,0 +1,32 @@
|
||||
package de.grimsi.gameyfin.games.entities
|
||||
|
||||
import jakarta.annotation.Nullable
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.GeneratedValue
|
||||
import jakarta.persistence.GenerationType
|
||||
import jakarta.persistence.Id
|
||||
import org.springframework.content.commons.annotations.ContentId
|
||||
import org.springframework.content.commons.annotations.ContentLength
|
||||
import org.springframework.content.commons.annotations.MimeType
|
||||
import java.net.URL
|
||||
|
||||
@Entity
|
||||
class Screenshot(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
var id: Long? = null,
|
||||
|
||||
val originalUrl: URL,
|
||||
|
||||
@ContentId
|
||||
@Nullable
|
||||
var contentId: String? = null,
|
||||
|
||||
@ContentLength
|
||||
@Nullable
|
||||
var contentLength: Long? = null,
|
||||
|
||||
@MimeType
|
||||
@Nullable
|
||||
var mimeType: String? = null
|
||||
)
|
||||
@ -0,0 +1,4 @@
|
||||
package de.grimsi.gameyfin.games.entities
|
||||
|
||||
class Video {
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package de.grimsi.gameyfin.games.repositories
|
||||
|
||||
import de.grimsi.gameyfin.games.entities.Company
|
||||
import de.grimsi.gameyfin.games.entities.CompanyType
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
|
||||
interface CompanyRepository : JpaRepository<Company, Long> {
|
||||
fun findByNameAndType(name: String, type: CompanyType): Company?
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package de.grimsi.gameyfin.games
|
||||
package de.grimsi.gameyfin.games.repositories
|
||||
|
||||
import de.grimsi.gameyfin.games.entities.Game
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
|
||||
interface GameRepository : JpaRepository<Game, Long> {
|
||||
@ -0,0 +1,8 @@
|
||||
package de.grimsi.gameyfin.games.repositories
|
||||
|
||||
import de.grimsi.gameyfin.games.entities.Screenshot
|
||||
import org.springframework.content.commons.store.ContentStore
|
||||
import org.springframework.stereotype.Repository
|
||||
|
||||
@Repository
|
||||
interface ScreenshotContentStore : ContentStore<Screenshot, String>
|
||||
@ -0,0 +1,9 @@
|
||||
package de.grimsi.gameyfin.games.repositories
|
||||
|
||||
import de.grimsi.gameyfin.games.entities.Screenshot
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
import java.net.URL
|
||||
|
||||
interface ScreenshotRepository : JpaRepository<Screenshot, Long> {
|
||||
fun findByOriginalUrl(originalUrl: URL): Screenshot?
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
package de.grimsi.gameyfin.libraries
|
||||
|
||||
import de.grimsi.gameyfin.games.Game
|
||||
import de.grimsi.gameyfin.games.entities.Game
|
||||
import jakarta.persistence.*
|
||||
|
||||
@Entity
|
||||
|
||||
@ -2,7 +2,7 @@ package de.grimsi.gameyfin.libraries
|
||||
|
||||
import com.vaadin.hilla.Endpoint
|
||||
import de.grimsi.gameyfin.core.Role
|
||||
import de.grimsi.gameyfin.games.Game
|
||||
import de.grimsi.gameyfin.games.entities.Game
|
||||
import jakarta.annotation.security.RolesAllowed
|
||||
|
||||
@Endpoint
|
||||
|
||||
@ -2,8 +2,8 @@ package de.grimsi.gameyfin.libraries
|
||||
|
||||
import de.grimsi.gameyfin.config.ConfigProperties
|
||||
import de.grimsi.gameyfin.config.ConfigService
|
||||
import de.grimsi.gameyfin.games.Game
|
||||
import de.grimsi.gameyfin.games.GameService
|
||||
import de.grimsi.gameyfin.games.entities.Game
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.stereotype.Service
|
||||
import java.nio.file.Path
|
||||
|
||||
@ -9,14 +9,15 @@ class GameMetadata(
|
||||
val release: Instant,
|
||||
val userRating: Int?,
|
||||
val criticRating: Int?,
|
||||
val developedBy: List<String>,
|
||||
val publishedBy: List<String>,
|
||||
val genres: List<Genre>,
|
||||
val themes: List<Theme>,
|
||||
val screenshotUrls: List<URL>,
|
||||
val videoUrls: List<URL>,
|
||||
val features: List<GameFeature>,
|
||||
val perspectives: List<PlayerPerspective>
|
||||
val developedBy: Set<String>,
|
||||
val publishedBy: Set<String>,
|
||||
val genres: Set<Genre>,
|
||||
val themes: Set<Theme>,
|
||||
val keywords: Set<String>,
|
||||
val screenshotUrls: Set<URL>,
|
||||
val videoUrls: Set<URL>,
|
||||
val features: Set<GameFeature>,
|
||||
val perspectives: Set<PlayerPerspective>
|
||||
)
|
||||
|
||||
enum class Genre {
|
||||
@ -95,10 +96,12 @@ enum class GameFeature {
|
||||
ONLINE_PVE,
|
||||
LOCAL_PVP,
|
||||
LOCAL_PVE,
|
||||
CROSSPLAY
|
||||
CROSSPLAY,
|
||||
SPLITSCREEN
|
||||
}
|
||||
|
||||
enum class PlayerPerspective {
|
||||
UNKNOWN,
|
||||
FIRST_PERSON,
|
||||
THIRD_PERSON,
|
||||
BIRD_VIEW_ISOMETRIC,
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user