Load download options dynamically from backend

Minor layout and performance improvements
This commit is contained in:
grimsi
2025-05-19 17:59:22 +02:00
parent eab23d48e1
commit afd99d79df
10 changed files with 79 additions and 33 deletions
+9 -1
View File
@@ -20,6 +20,7 @@ import InvitationRegistrationView from "Frontend/views/InvitationRegistrationVie
import PluginManagement from "Frontend/components/administration/PluginManagement";
import {SystemManagement} from "Frontend/components/administration/SystemManagement";
import GameView from "Frontend/views/GameView";
import LibraryManagementView from "Frontend/views/LibraryManagementView";
export const routes = protectRoutes([
{
@@ -49,7 +50,14 @@ export const routes = protectRoutes([
path: 'administration',
element: <AdministrationView/>,
children: [
{path: 'libraries', element: <LibraryManagement/>},
{
path: 'libraries',
element: <LibraryManagement/>,
children: [{
path: 'library/:libraryId',
element: <LibraryManagementView/>
}]
},
{path: 'users', element: <UserManagement/>},
{path: 'sso', element: <SsoManagement/>},
{path: 'messages', element: <MessageManagement/>},
+17 -18
View File
@@ -1,6 +1,6 @@
import {useEffect, useState} from "react";
import GameDto from "Frontend/generated/de/grimsi/gameyfin/games/dto/GameDto";
import {GameEndpoint} from "Frontend/generated/endpoints";
import {DownloadProviderEndpoint, GameEndpoint} from "Frontend/generated/endpoints";
import {useParams} from "react-router";
import {GameCover} from "Frontend/components/general/covers/GameCover";
import ComboButton, {ComboButtonOption} from "Frontend/components/general/input/ComboButton";
@@ -13,24 +13,23 @@ export default function GameView() {
const {gameId} = useParams();
const [game, setGame] = useState<GameDto>();
const [downloadOptions, setDownloadOptions] = useState<Record<string, ComboButtonOption>>({});
const downloadOptions: Record<string, ComboButtonOption> = {
browser: {
label: "Direct Download",
description: "Download the game in this browser",
action: () => {
DownloadEndpoint.downloadGame(parseInt(gameId!), "de.grimsi.gameyfin.plugins.directdownload.DirectDownloadPlugin$DirectDownloadProvider")
}
},
torrent: {
label: "Torrent Download",
description: "Download the game as a torrent",
action: () => {
alert("Torrent download not yet implemented")
},
isDisabled: true
}
}
useEffect(() => {
DownloadProviderEndpoint.getProviders().then((providers) => {
const options: Record<string, ComboButtonOption> = providers.reduce((acc, provider) => {
acc[provider.key] = {
label: provider.name,
description: provider.shortDescription ?? provider.description,
action: () => {
if (gameId) DownloadEndpoint.downloadGame(parseInt(gameId!), provider.key);
},
};
return acc;
}, {} as Record<string, ComboButtonOption>);
setDownloadOptions(options);
});
}, []);
useEffect(() => {
if (gameId) {
@@ -0,0 +1,7 @@
import {useParams} from "react-router";
export default function LibraryManagementView() {
const {libraryId} = useParams();
return (<></>);
}
@@ -15,10 +15,6 @@ class DownloadEndpoint(
private val downloadService: DownloadService,
private val gameService: GameService
) {
fun getProviders(): List<String> {
return downloadService.getProviders()
}
@GetMapping("/{gameId}")
fun downloadGame(
@PathVariable gameId: Long,
@@ -0,0 +1,11 @@
package de.grimsi.gameyfin.core.download
import com.fasterxml.jackson.annotation.JsonInclude
@JsonInclude(JsonInclude.Include.NON_NULL)
data class DownloadProviderDto(
val key: String,
val name: String,
val description: String,
val shortDescription: String? = null
)
@@ -0,0 +1,14 @@
package de.grimsi.gameyfin.core.download
import com.vaadin.hilla.Endpoint
import jakarta.annotation.security.PermitAll
@Endpoint
@PermitAll
class DownloadProviderEndpoint(
private val downloadService: DownloadService
) {
fun getProviders(): List<DownloadProviderDto> {
return downloadService.getProviders()
}
}
@@ -1,5 +1,6 @@
package de.grimsi.gameyfin.core.download
import de.grimsi.gameyfin.core.plugins.management.GameyfinPluginDescriptor
import de.grimsi.gameyfin.core.plugins.management.GameyfinPluginManager
import de.grimsi.gameyfin.pluginapi.download.Download
import de.grimsi.gameyfin.pluginapi.download.DownloadProvider
@@ -13,8 +14,18 @@ class DownloadService(
private val downloadPlugins: List<DownloadProvider>
get() = pluginManager.getExtensions(DownloadProvider::class.java)
fun getProviders(): List<String> {
return downloadPlugins.map { it.javaClass.name }
fun getProviders(): List<DownloadProviderDto> {
return downloadPlugins.map {
val plugin = pluginManager.whichPlugin(it.javaClass.enclosingClass)
val descriptor = plugin.descriptor as GameyfinPluginDescriptor
DownloadProviderDto(
key = it.javaClass.name,
name = descriptor.pluginName,
description = descriptor.pluginDescription,
shortDescription = descriptor.pluginShortDescription,
)
}
}
fun getDownload(path: String, provider: String): Download {
@@ -59,11 +59,6 @@ class PluginService(
.map { toDto(it) }
}
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)
@@ -137,6 +132,11 @@ class PluginService(
return pluginManager.validatePluginConfig(pluginId, configToValidate)
}
private fun getPluginManagementEntry(pluginId: String): PluginManagementEntry {
return pluginManagementRepository.findByIdOrNull(pluginId)
?: throw IllegalArgumentException("Plugin with ID $pluginId not found")
}
private fun toDto(pluginWrapper: PluginWrapper): PluginDto {
val pluginManagementEntry = getPluginManagementEntry(pluginWrapper.pluginId)
@@ -183,7 +183,7 @@ class GameService(
// Sort results by plugin priority
val sortedResults = results.entries.sortedByDescending {
pluginService.getPluginManagementEntry(it.key.javaClass).priority
providerToManagementEntry[it.key]?.priority
}
sortedResults.forEach { (provider, metadata) ->
@@ -1,10 +1,10 @@
Plugin-Version: 1.0.0-alpha2
Plugin-Version: 1.0.0-alpha3
Plugin-Class: de.grimsi.gameyfin.plugins.directdownload.DirectDownloadPlugin
Plugin-Id: de.grimsi.gameyfin.directdownload
Plugin-Name: Direct Download
Plugin-Description: Downloads games directly in the browser.<br>
If the game is contained in a folder, it will pack the folder into a zip file on the fly.
Plugin-Short-Description: Download games directly in the browser
Plugin-Short-Description: Download directly in the browser
Plugin-Author: grimsi
Plugin-License: MIT
Plugin-Url: https://github.com/gameyfin