IGDB-Integration für Game Library + Electron Update-Button im Version-Modal

- Neues IGDB-Service-Modul (igdb.ts): Token-Management, Rate-Limiting, Game-Lookup per Steam-AppID/Name, Batch-Enrichment mit In-Memory-Cache
- Server: 2 neue Routes (/igdb/enrich/:steamId, /igdb/game/:appid), Auto-Enrichment bei Steam-Login und Refresh
- Frontend: IGDB-Cover, Genre-Tags, Plattform-Badges, farbcodiertes Rating, IGDB-Anreichern-Button
- Version-Modal: Update-Button für Electron-App (checkForUpdates/installUpdate), Desktop-App-Version anzeigen
- CSS: Styles für IGDB-Elemente und Update-UI

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Daniel 2026-03-08 01:48:15 +01:00
parent aec1142bff
commit b404c20eca
6 changed files with 785 additions and 25 deletions

View file

@ -26,6 +26,8 @@ export function registerTab(pluginName: string, component: React.FC<{ data: any
tabComponents[pluginName] = component;
}
type UpdateStatus = 'idle' | 'checking' | 'available' | 'downloading' | 'ready' | 'upToDate' | 'error';
export default function App() {
const [connected, setConnected] = useState(false);
const [plugins, setPlugins] = useState<PluginInfo[]>([]);
@ -37,6 +39,12 @@ export default function App() {
};
const [showVersionModal, setShowVersionModal] = useState(false);
const [pluginData, setPluginData] = useState<Record<string, any>>({});
// Electron auto-update state
const isElectron = !!(window as any).electronAPI?.isElectron;
const electronVersion = isElectron ? (window as any).electronAPI.version : null;
const [updateStatus, setUpdateStatus] = useState<UpdateStatus>('idle');
const [updateError, setUpdateError] = useState<string>('');
const eventSourceRef = useRef<EventSource | null>(null);
// Request notification permission
@ -46,6 +54,19 @@ export default function App() {
}
}, []);
// Electron auto-update listeners
useEffect(() => {
if (!isElectron) return;
const api = (window as any).electronAPI;
api.onUpdateAvailable(() => setUpdateStatus('downloading'));
api.onUpdateReady(() => setUpdateStatus('ready'));
api.onUpdateNotAvailable(() => setUpdateStatus('upToDate'));
api.onUpdateError((msg: string) => {
setUpdateStatus('error');
setUpdateError(msg || 'Unbekannter Fehler');
});
}, [isElectron]);
// Fetch plugin list
useEffect(() => {
fetch('/api/plugins')
@ -184,9 +205,15 @@ export default function App() {
</div>
<div className="hub-version-modal-body">
<div className="hub-version-modal-row">
<span className="hub-version-modal-label">Version</span>
<span className="hub-version-modal-label">Hub-Version</span>
<span className="hub-version-modal-value">v{version}</span>
</div>
{isElectron && (
<div className="hub-version-modal-row">
<span className="hub-version-modal-label">Desktop-App</span>
<span className="hub-version-modal-value">v{electronVersion}</span>
</div>
)}
<div className="hub-version-modal-row">
<span className="hub-version-modal-label">Server</span>
<span className="hub-version-modal-value">
@ -194,6 +221,65 @@ export default function App() {
{connected ? 'Verbunden' : 'Getrennt'}
</span>
</div>
{isElectron && (
<div className="hub-version-modal-update">
{updateStatus === 'idle' && (
<button
className="hub-version-modal-update-btn"
onClick={() => {
setUpdateStatus('checking');
setUpdateError('');
(window as any).electronAPI.checkForUpdates();
}}
>
{'\u{1F504}'} Nach Updates suchen
</button>
)}
{updateStatus === 'checking' && (
<div className="hub-version-modal-update-status">
<span className="hub-update-spinner" />
Suche nach Updates
</div>
)}
{updateStatus === 'downloading' && (
<div className="hub-version-modal-update-status">
<span className="hub-update-spinner" />
Update wird heruntergeladen
</div>
)}
{updateStatus === 'ready' && (
<button
className="hub-version-modal-update-btn ready"
onClick={() => (window as any).electronAPI.installUpdate()}
>
{'\u2705'} Jetzt installieren & neu starten
</button>
)}
{updateStatus === 'upToDate' && (
<div className="hub-version-modal-update-status success">
{'\u2705'} App ist aktuell
<button
className="hub-version-modal-update-retry"
onClick={() => setUpdateStatus('idle')}
>
Erneut prüfen
</button>
</div>
)}
{updateStatus === 'error' && (
<div className="hub-version-modal-update-status error">
{'\u274C'} {updateError}
<button
className="hub-version-modal-update-retry"
onClick={() => setUpdateStatus('idle')}
>
Erneut versuchen
</button>
</div>
)}
</div>
)}
</div>
</div>
</div>