Jikan/MAL-Quelle + Job-Titel + Abbrechen-Knopf + Dark-Hover + Ordner-Verwaltung
Ampel / ampel (push) Failing after 38s

Commander-Befunde (Screenshots 23.07. abends):
- Jikan (MyAnimeList, kostenlos OHNE Key) als Anime-Quelle vor OMDb —
  waehlt per Titel-Aehnlichkeit (SequenceMatcher, Schwelle 0.55) statt
  blind Treffer 1; damit trifft "Evangelion 2.22" den exakten Film
- Job-Titel: POST /jobs uebernimmt den erkannten Disc-Titel aus dem
  DISC_CACHE — Schluss mit "Unbekannt" in der Queue
- Kooperativer Job-Abbruch: POST /jobs/{id}/cancel setzt canceling,
  der Worker prueft das Flag bei jedem Fortschritts-Update und killt
  den Encoder-Prozess sauber (RipAbbruch); UI-Knopf "Abbrechen" fuer
  laufende, Status-Badge "Wird abgebrochen"
- Dark-Mode: Job-Zeilen-Hover war hart hell (hover:bg-slate-50)
- Speicherziele: lokaler Ordner-Browser mit "Ordner anlegen"
  (GET /browse + POST /browse/mkdir, nur unter /app/media)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-07-23 21:22:57 +02:00
parent 85f352b14f
commit 07be54e62a
8 changed files with 307 additions and 21 deletions
+14 -2
View File
@@ -8,7 +8,7 @@ import LiveLogSection from '../components/LiveLogSection'
interface Job {
id: string
type: 'cd' | 'dvd' | 'bluray'
status: 'pending' | 'processing' | 'transcoding' | 'completed' | 'failed'
status: 'pending' | 'processing' | 'transcoding' | 'canceling' | 'completed' | 'failed'
device: string
startTime: string
endTime?: string
@@ -32,6 +32,7 @@ function StatusBadge({ status }: { status: string }) {
pending: 'bg-amber-900/30 text-amber-400 ring-amber-700/20',
processing: 'bg-blue-900/30 text-blue-400 ring-blue-700/20',
transcoding: 'bg-purple-900/30 text-purple-400 ring-purple-700/20',
canceling: 'bg-orange-900/30 text-orange-400 ring-orange-700/20',
completed: 'bg-emerald-900/30 text-emerald-400 ring-emerald-700/20',
failed: 'bg-rose-900/30 text-rose-400 ring-rose-700/20',
}
@@ -39,6 +40,7 @@ function StatusBadge({ status }: { status: string }) {
pending: 'bg-amber-100 text-amber-700 ring-amber-600/20',
processing: 'bg-blue-100 text-blue-700 ring-blue-600/20',
transcoding: 'bg-purple-100 text-purple-700 ring-purple-600/20',
canceling: 'bg-orange-100 text-orange-700 ring-orange-600/20',
completed: 'bg-emerald-100 text-emerald-700 ring-emerald-600/20',
failed: 'bg-rose-100 text-rose-700 ring-rose-600/20',
}
@@ -47,6 +49,7 @@ function StatusBadge({ status }: { status: string }) {
pending: 'Wartend',
processing: 'Rippen',
transcoding: 'Komprimieren',
canceling: 'Wird abgebrochen…',
completed: 'Fertig',
failed: 'Fehler',
}
@@ -273,7 +276,7 @@ export default function Dashboard() {
</tr>
) : (
jobs.slice(0, 10).map(job => (
<tr key={job.id} className="hover:bg-slate-50 transition-colors duration-300">
<tr key={job.id} className={`transition-colors duration-300 ${theme === 'dark' ? 'hover:bg-slate-700/40' : 'hover:bg-slate-50'}`}>
<td className="px-6 py-4 whitespace-nowrap">
<TypeBadge type={job.type} />
</td>
@@ -304,6 +307,15 @@ export default function Dashboard() {
Neu komprimieren
</button>
)}
{(job.status === 'pending' || job.status === 'processing' || job.status === 'transcoding') && (
<button
onClick={() => api.post(`/jobs/${job.id}/cancel`).catch(() => {})}
title="Job abbrechen (Rohdaten bleiben erhalten)"
className={`text-xs font-medium px-3 py-1.5 rounded-lg transition-colors ${theme === 'dark' ? 'bg-slate-700 text-rose-300 hover:bg-slate-600' : 'bg-slate-100 text-rose-700 hover:bg-slate-200'}`}
>
Abbrechen
</button>
)}
</td>
</tr>
))