import { useState, useEffect } from 'react' import { Disc, Cpu, Globe, Tv, CheckCircle, ArrowRight } from 'lucide-react' import { api } from '../lib/api' import { useDarkMode } from '../context/ThemeContext' import { MEDIA_SERVER_OPTIONEN } from '../lib/mediaServer' // Erster Start: Rippy universell einrichten (Commander-Ziel: All-in-one, // weitergebbar — keine Handarbeit in .env-Dateien nötig). interface WorkerInfo { name: string encoders: string[] last_seen?: string } const ENCODER_LABELS: Record = { 'cpu-x264': 'CPU · H.264 (x264)', 'cpu-x265': 'CPU · H.265 (x265)', 'vaapi': 'Hardware · VAAPI (AMD/Intel)', 'nvenc': 'Hardware · NVENC (NVIDIA)', } export default function FirstRunWizard({ onDone }: { onDone: () => void }) { const [tmdbKey, setTmdbKey] = useState('') const [omdbKey, setOmdbKey] = useState('') const [mediaServer, setMediaServer] = useState('jellyfin') const [transcodeEnabled, setTranscodeEnabled] = useState(true) const [preset, setPreset] = useState('H.265 MKV 1080p30') const [workers, setWorkers] = useState([]) const [saving, setSaving] = useState(false) const [error, setError] = useState(null) const { theme } = useDarkMode() useEffect(() => { api.get('/capabilities') .then(r => setWorkers(r.data.workers || [])) .catch(() => setWorkers([])) }, []) const abschliessen = async () => { setSaving(true) setError(null) try { const bestehende = (await api.get('/settings')).data || {} await api.post('/settings', { ...bestehende, ...(tmdbKey ? { tmdbApiKey: tmdbKey } : {}), ...(omdbKey ? { omdbApiKey: omdbKey } : {}), mediaServer, transcodeEnabled, transcodePreset: preset, }) await api.post('/setup/complete') onDone() } catch { setError('Speichern fehlgeschlagen — läuft die API?') } finally { setSaving(false) } } const feldKlasse = `w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent ${theme === 'dark' ? 'bg-slate-800 border-slate-600 text-slate-200' : 'bg-white border-slate-300 text-slate-900'}` return (

Willkommen bei Rippy

Einmalige Einrichtung — dauert keine zwei Minuten. Alles ist später unter Einstellungen änderbar.

{/* Metadaten-APIs */}

Metadaten-Erkennung

setTmdbKey(e.target.value)} className={feldKlasse} placeholder="Kostenlos auf themoviedb.org" />
setOmdbKey(e.target.value)} className={feldKlasse} placeholder="Kostenlos auf omdbapi.com" />

Ohne Keys rippt Rippy trotzdem — Discs heißen dann nur wie ihr Volume-Label.

{/* Media-Server: worauf soll Rippy die Ablage vorbereiten? */}

Dein Media-Server

Rippy benennt fertige Rips als „Titel (Jahr)" und legt für Jellyfin/Emby/Kodi zusätzlich movie.nfo + poster.jpg dazu — dein Server erkennt alles ohne Nacharbeit.

{MEDIA_SERVER_OPTIONEN.map(o => ( ))}

{MEDIA_SERVER_OPTIONEN.find(o => o.wert === mediaServer)?.hinweis}

{/* Verarbeitung + erkannte Hardware */}

Verarbeitung

Erkannte Encoder in deinem System:

{workers.length === 0 ? (

Noch kein Worker gemeldet — startet gerade?

) : ( workers.map(w => (
{w.name}: {w.encoders.map(e => ( {ENCODER_LABELS[e] || e} ))}
)) )}

Tipp: GPU-Maschinen im Netz können als optionale Transcode-Worker angebunden werden (siehe README).

{transcodeEnabled && ( )}
{error &&

{error}

}

Läuft komplett lokal — keine Cloud, keine Telemetrie.

) }