4ba02047db
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>
159 lines
6.7 KiB
PowerShell
159 lines
6.7 KiB
PowerShell
# Rippy: Nativer Windows-Transcode-Worker — Installation OHNE Docker.
|
|
#
|
|
# Was das Skript tut (alles in einen Unterordner "rippy-worker"):
|
|
# 1. Prueft Python (3.10+), legt ein venv an, installiert die Abhaengigkeiten
|
|
# 2. Laedt den Worker-Code direkt von deiner Rippy-Instanz (/api/worker-setup/paket)
|
|
# 3. Laedt HandBrakeCLI (gepinnte Version, offizielles GitHub-Release),
|
|
# falls nicht schon im PATH oder im Ordner vorhanden
|
|
# 4. Erzeugt start-worker.bat — Doppelklick startet den Worker
|
|
#
|
|
# Der Worker bedient NUR die Kompressions-Queue (transcode) — gerippt wird
|
|
# weiterhin auf der Rippy-Hauptmaschine (dort haengt das Laufwerk).
|
|
#
|
|
# Aufruf (PowerShell):
|
|
# .\install.ps1 -RippyHost 192.168.178.162 [-WorkerName mein-pc] [-Autostart]
|
|
#
|
|
# -Autostart registriert eine Aufgabe "RippyWorker" (Start bei Anmeldung).
|
|
|
|
param(
|
|
[Parameter(Mandatory = $true)] [string]$RippyHost,
|
|
[string]$WorkerName = $env:COMPUTERNAME.ToLower(),
|
|
[switch]$Autostart
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
# HandBrake-Version: die NEUESTE offizielle (GitHub-Release) — so passt der
|
|
# Windows-Worker zu dem, was der Update-Check im UI meldet (frueher war hier
|
|
# eine feste 1.9.2 hardcodiert, was verwirrte). Faellt auf eine bekannte
|
|
# Version zurueck, falls die GitHub-API gerade nicht erreichbar ist.
|
|
$HandBrakeVersion = "1.11.2"
|
|
try {
|
|
$rel = Invoke-RestMethod "https://api.github.com/repos/HandBrake/HandBrake/releases/latest" `
|
|
-TimeoutSec 15 -Headers @{ "User-Agent" = "rippy-installer" }
|
|
if ($rel.tag_name) { $HandBrakeVersion = ([string]$rel.tag_name).TrimStart("v") }
|
|
Write-Host "Neueste HandBrake-Version: $HandBrakeVersion"
|
|
} catch { Write-Host "GitHub-API nicht erreichbar — nutze HandBrake $HandBrakeVersion" }
|
|
$HandBrakeUrl = "https://github.com/HandBrake/HandBrake/releases/download/$HandBrakeVersion/HandBrakeCLI-$HandBrakeVersion-win-x86_64.zip"
|
|
|
|
Write-Host "== Rippy Windows-Worker Installation ==" -ForegroundColor Cyan
|
|
|
|
# 1. Python finden (py-Launcher oder python im PATH)
|
|
$python = $null
|
|
foreach ($kandidat in @("py -3", "python")) {
|
|
try {
|
|
$version = Invoke-Expression "$kandidat --version" 2>&1
|
|
if ("$version" -match "Python 3\.(\d+)") {
|
|
if ([int]$Matches[1] -ge 10) { $python = $kandidat; break }
|
|
}
|
|
} catch {}
|
|
}
|
|
if (-not $python) {
|
|
Write-Host "FEHLER: Python 3.10+ nicht gefunden." -ForegroundColor Red
|
|
Write-Host "Installieren mit: winget install Python.Python.3.12 (dann Skript erneut ausfuehren)"
|
|
exit 1
|
|
}
|
|
Write-Host "Python gefunden: $python"
|
|
|
|
# 2. Arbeitsordner + Worker-Code von der Rippy-Instanz laden
|
|
$ziel = Join-Path (Get-Location) "rippy-worker"
|
|
New-Item -ItemType Directory -Force $ziel | Out-Null
|
|
Set-Location $ziel
|
|
|
|
Write-Host "Lade Worker-Code von http://$RippyHost/api/worker-setup/paket ..."
|
|
Invoke-WebRequest "http://$RippyHost/api/worker-setup/paket" -OutFile worker.zip -UseBasicParsing
|
|
Expand-Archive worker.zip -DestinationPath . -Force
|
|
Remove-Item worker.zip
|
|
|
|
# 3. venv + Abhaengigkeiten
|
|
if (-not (Test-Path "venv")) {
|
|
Write-Host "Lege Python-Umgebung an ..."
|
|
Invoke-Expression "$python -m venv venv"
|
|
}
|
|
& .\venv\Scripts\python.exe -m pip install --quiet --upgrade pip
|
|
& .\venv\Scripts\pip.exe install --quiet -r requirements.txt
|
|
# Nur fuer den Windows-Worker: Tray-Symbol (Status, Start/Stopp, Beenden)
|
|
& .\venv\Scripts\pip.exe install --quiet pystray pillow
|
|
Write-Host "Python-Abhaengigkeiten installiert."
|
|
|
|
# 4. HandBrakeCLI besorgen (falls noetig)
|
|
$hb = Get-Command HandBrakeCLI.exe -ErrorAction SilentlyContinue
|
|
if (-not $hb -and -not (Test-Path ".\HandBrakeCLI.exe")) {
|
|
Write-Host "Lade HandBrakeCLI $HandBrakeVersion (offizielles GitHub-Release) ..."
|
|
Invoke-WebRequest $HandBrakeUrl -OutFile hb.zip -UseBasicParsing
|
|
Expand-Archive hb.zip -DestinationPath . -Force
|
|
Remove-Item hb.zip
|
|
}
|
|
if (-not (Test-Path ".\HandBrakeCLI.exe") -and -not $hb) {
|
|
Write-Host "FEHLER: HandBrakeCLI.exe fehlt." -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
Write-Host "HandBrakeCLI bereit."
|
|
|
|
# 5. Start-Skript erzeugen
|
|
$bat = @"
|
|
@echo off
|
|
rem Rippy Windows-Transcode-Worker — verbindet sich mit $RippyHost
|
|
cd /d "%~dp0"
|
|
set REDIS_URL=redis://${RippyHost}:6379/0
|
|
set DATABASE_URL=postgresql://rippy:rippy@${RippyHost}:5432/rippy
|
|
set API_URL=http://${RippyHost}:8000
|
|
set WORKER_NAME=$WorkerName
|
|
set PATH=%~dp0;%PATH%
|
|
venv\Scripts\celery.exe -A celery_app worker --loglevel=info -Q transcode --pool=solo -n ${WorkerName}@%%h
|
|
"@
|
|
Set-Content -Path "start-worker.bat" -Value $bat -Encoding ASCII
|
|
|
|
# 6. Tray-Start (empfohlen): Symbol neben der Uhr, kein Konsolenfenster
|
|
$trayBat = @"
|
|
@echo off
|
|
rem Rippy-Worker mit Tray-Symbol — verbindet sich mit $RippyHost
|
|
cd /d "%~dp0"
|
|
set REDIS_URL=redis://${RippyHost}:6379/0
|
|
set DATABASE_URL=postgresql://rippy:rippy@${RippyHost}:5432/rippy
|
|
set API_URL=http://${RippyHost}:8000
|
|
set WORKER_NAME=$WorkerName
|
|
set RIPPY_TRAY_HOST=$RippyHost
|
|
set PATH=%~dp0;%PATH%
|
|
start "" venv\Scripts\pythonw.exe tray.py
|
|
"@
|
|
Set-Content -Path "start-tray.bat" -Value $trayBat -Encoding ASCII
|
|
Write-Host "start-worker.bat + start-tray.bat erzeugt."
|
|
|
|
# 7. Deinstaller — MUSS-Kriterium: rueckstandsfrei entfernbar
|
|
$uninstall = @"
|
|
# Rippy-Worker DEINSTALLIEREN: stoppt Prozesse, entfernt Autostart,
|
|
# meldet den Worker in Rippy ab und loescht diesen Ordner komplett.
|
|
param([switch]`$Force)
|
|
if (-not `$Force) {
|
|
`$antwort = Read-Host "Rippy-Worker '$WorkerName' wirklich deinstallieren? (j/n)"
|
|
if (`$antwort -ne "j") { Write-Host "Abgebrochen."; exit }
|
|
}
|
|
Get-CimInstance Win32_Process | Where-Object {
|
|
`$_.ExecutablePath -like "`$PSScriptRoot*"
|
|
} | ForEach-Object { Stop-Process -Id `$_.ProcessId -Force -ErrorAction SilentlyContinue }
|
|
Start-Sleep 2
|
|
schtasks /delete /tn "RippyWorker" /f 2>`$null | Out-Null
|
|
try {
|
|
Invoke-RestMethod -Method Delete "http://$RippyHost/api/workers/$WorkerName" -TimeoutSec 5 | Out-Null
|
|
Write-Host "Worker-Eintrag in Rippy entfernt."
|
|
} catch { Write-Host "Hinweis: Eintrag in Rippy ggf. von Hand loeschen (Einstellungen -> Worker)." }
|
|
Set-Location (Split-Path `$PSScriptRoot -Parent)
|
|
Remove-Item -Recurse -Force `$PSScriptRoot
|
|
Write-Host "Rippy-Worker deinstalliert." -ForegroundColor Green
|
|
"@
|
|
Set-Content -Path "uninstall.ps1" -Value $uninstall -Encoding ASCII
|
|
Write-Host "uninstall.ps1 erzeugt."
|
|
|
|
# 8. Optional: Autostart bei Anmeldung (mit Tray)
|
|
if ($Autostart) {
|
|
schtasks /create /f /tn "RippyWorker" /tr "`"$ziel\start-tray.bat`"" /sc onlogon | Out-Null
|
|
Write-Host "Autostart-Aufgabe 'RippyWorker' registriert (Tray bei Anmeldung)."
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "FERTIG." -ForegroundColor Green
|
|
Write-Host " Starten (mit Tray-Symbol): $ziel\start-tray.bat"
|
|
Write-Host " Starten (Konsole/Debug): $ziel\start-worker.bat"
|
|
Write-Host " Deinstallieren: $ziel\uninstall.ps1"
|
|
Write-Host "Der Worker erscheint in Rippy unter Einstellungen -> Worker als '$WorkerName'."
|