Drei Praxis-Bugs: tote NAS-Mounts reparierbar, HandBrake-Versionen konsistent, Encoder-Wahl beim Rip
Ampel / ampel (push) Successful in 28s
Ampel / ampel (push) Successful in 28s
1) Speicher-Mounts robust (Befund: toter CIFS-Mount nach NAS-Ausfall/Rebuild —
mounted:false, verschwand aus 'Verfuegbare Ziele', Neu-Anlegen -> 409, man
sass fest):
- mounts.py: ist_erreichbar() (listdir, soft-Mount bricht schnell ab),
ist_gemountet() faengt OSError toter Mounts, aushaengen() mit
umount -l Fallback, reparieren() (lazy abhaengen + frisch mounten).
- /storage-mounts liefert 'reachable'; POST bei existierendem Namen:
aktiv -> 409, tot -> automatische Reparatur mit neuen Angaben;
neuer POST /storage-mounts/{name}/repair (gespeicherte Zugangsdaten).
- /storage-targets crasht nicht mehr an totem Mount (os.path.ismount
OSError abgefangen).
- UI: eigene 'Netzwerk-Mounts'-Liste mit Status (aktiv/nicht erreichbar/
getrennt) + Reparieren- und Entfernen-Knopf — tote Mounts sind sichtbar
und wiederherstellbar statt zu verschwinden.
2) HandBrake-Versionen konsistent (Befund: Docker 1.6.1, Windows-Skript
fest 1.9.2, Update-Check meldet 1.11.2 — verwirrend):
- Windows-Installer zieht jetzt DYNAMISCH die neueste Version (GitHub
latest, Fallback 1.11.2) — passt zum Update-Check.
- Update-UI erklaert klar: Docker = stabiles Debian-Paket (bewusst aelter,
kein Fehler), Windows = neueste. MakeMKV-Update zeigt den Befehl.
3) Encoder-/Worker-Auswahl beim Rip (Feature):
- Celery worker_direct=True: jeder Worker konsumiert zusaetzlich seine
Direkt-Queue. API-Helper transcode_queue(node) routet gezielt an den
gewaehlten Worker, faellt aber sicher auf die geteilte transcode-Queue
zurueck, wenn er offline ist (kein Haengenbleiben).
- /capabilities liefert den Celery-Node je Worker; POST /jobs nimmt
transcode_node (-> Job-meta); rip_disc + retry-transcode routen danach.
- Rip-Dialog: Encoder-/Worker-Dropdown, sichtbar ab 2 Online-Workern.
- ping_worker-Task zum Verifizieren des gezielten Routings.
- Nebenfund gefixt: DeviceDiscovery leitete die Titel-Auswahl (titles)
gar nicht an die API weiter — jetzt titles + transcode_node.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
fe1387b1ec
commit
4ba02047db
@@ -1,5 +1,5 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { HardDrive, Plus, Trash2, CheckCircle, AlertCircle, RefreshCw, Folder, File, ArrowUp, FolderPlus } from 'lucide-react'
|
||||
import { HardDrive, Plus, Trash2, CheckCircle, AlertCircle, AlertTriangle, RefreshCw, Wrench, Folder, File, ArrowUp, FolderPlus } from 'lucide-react'
|
||||
import { api } from '../lib/api'
|
||||
import { useToast } from '../context/ToastContext'
|
||||
import { Card, CardHeader, CardTitle, CardContent } from './ui/Card'
|
||||
@@ -11,6 +11,7 @@ interface Mount {
|
||||
type: string
|
||||
source: string
|
||||
mounted: boolean
|
||||
reachable?: boolean
|
||||
has_credentials: boolean
|
||||
}
|
||||
|
||||
@@ -149,6 +150,20 @@ export default function StorageMounts() {
|
||||
}
|
||||
}
|
||||
|
||||
const reparieren = async (mountName: string) => {
|
||||
setBusy(true)
|
||||
try {
|
||||
const r = await api.post(`/storage-mounts/${mountName}/repair`)
|
||||
toast(r.data.writable ? 'success' : 'error',
|
||||
r.data.writable ? `„${mountName}" neu verbunden` : `„${mountName}" verbunden, aber nur lesbar`)
|
||||
laden()
|
||||
} catch (e: any) {
|
||||
toast('error', e?.response?.data?.detail || 'Reparatur fehlgeschlagen — NAS erreichbar?')
|
||||
} finally {
|
||||
setBusy(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Vorhandene Ziele */}
|
||||
@@ -190,6 +205,56 @@ export default function StorageMounts() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Netzwerk-Mounts mit Status — zeigt AUCH tote/getrennte Mounts, damit
|
||||
man sie reparieren oder entfernen kann (Bug 24.07.: ein toter NAS-Mount
|
||||
verschwand aus „Verfügbare Ziele" und ließ sich nicht neu anlegen). */}
|
||||
{mounts.length > 0 && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<HardDrive size={20} className="text-amber-500" />
|
||||
<span>Netzwerk-Mounts</span>
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-2.5">
|
||||
{mounts.map(m => {
|
||||
const aktiv = m.mounted && m.reachable !== false
|
||||
const tot = m.mounted && m.reachable === false
|
||||
return (
|
||||
<div key={m.name} className="flex items-center justify-between gap-3 p-3.5 rounded-xl border border-slate-200/80 dark:border-slate-800 bg-slate-50 dark:bg-slate-950/80">
|
||||
<div className="flex items-center gap-3 min-w-0">
|
||||
{aktiv
|
||||
? <CheckCircle size={18} className="text-emerald-500 flex-shrink-0" />
|
||||
: tot
|
||||
? <AlertTriangle size={18} className="text-amber-500 flex-shrink-0" />
|
||||
: <AlertCircle size={18} className="text-slate-400 flex-shrink-0" />}
|
||||
<div className="min-w-0">
|
||||
<span className="text-sm font-medium text-slate-900 dark:text-slate-200">{m.name}</span>
|
||||
<span className="text-xs ml-2 font-mono text-slate-500 dark:text-slate-400">{m.source}</span>
|
||||
<p className={`text-xs ${aktiv ? 'text-emerald-600 dark:text-emerald-400' : tot ? 'text-amber-600 dark:text-amber-400' : 'text-slate-500 dark:text-slate-400'}`}>
|
||||
{aktiv ? 'aktiv & erreichbar' : tot ? 'verbunden, aber NICHT erreichbar (NAS aus/weg?)' : 'getrennt'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5 flex-shrink-0">
|
||||
{!aktiv && (
|
||||
<Button variant="secondary" size="sm" onClick={() => reparieren(m.name)} disabled={busy} title="Neu verbinden (gespeicherte Zugangsdaten)">
|
||||
<Wrench size={14} /> Reparieren
|
||||
</Button>
|
||||
)}
|
||||
<button onClick={() => entfernen(m.name)} disabled={busy} className="p-1.5 rounded-lg text-rose-500 hover:bg-rose-500/10 transition-colors" title="Entfernen">
|
||||
<Trash2 size={16} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* Ordner-Verwaltung */}
|
||||
<Card>
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user