8f208ed0da
Ampel / ampel (push) Successful in 28s
Beim Commander live aufgetreten: Der Installer meldete
"FEHLER: FEHLER: Zugriff verweigert" samt dem Tipp, die IP koenne falsch sein -
und das, NACHDEM Worker-Code, Abhaengigkeiten und HandBrake schon fertig waren.
Die IP war also nie das Problem.
URSACHE: schtasks /create mit /tn "RippyWorker" legt die Aufgabe im
WURZELORDNER der Aufgabenplanung an, und das verlangt Administratorrechte. Der
Installer laeuft normal ohne. schtasks schrieb "FEHLER: Zugriff verweigert."
nach stderr, und weil im Skript $ErrorActionPreference = "Stop" steht, machte
PowerShell daraus einen TERMINIERENDEN Fehler - der catch-Block riss damit die
komplette Installation ab, obwohl nur der Autostart fehlte. Das doppelte
"FEHLER: FEHLER:" war der Hinweis: der aeussere Handler setzt sein Praefix vor
eine Meldung, die selbst schon mit "FEHLER:" begann, also aus schtasks kam.
FIX, zwei Teile:
1. Autostart ueber den Autostart-ORDNER statt schtasks. Eine Verknuepfung in
[Environment]::GetFolderPath("Startup") braucht NIE Adminrechte - und der
Nutzer kann sie dort selbst sehen und loeschen. Auf diesem Windows-PC
gegengeprueft: Verknuepfung angelegt (1047 Bytes) mit Admin=False.
2. Ein Fehlschlag beim Autostart ist jetzt eine WARNUNG in eigenem try/catch,
kein Abbruch. Der Worker ist zu dem Zeitpunkt fertig und startbar, und der
Text sagt das auch - plus den Handweg (shell:startup).
In BEIDEN Installern (install-gui.ps1 und install.ps1, dort mit -Autostart) -
der CLI-Weg hatte denselben Fehler. uninstall.ps1 raeumt jetzt die
Verknuepfung weg UND versucht weiter schtasks /delete, damit aeltere
Installationen sauber verschwinden.
RippyWorkerSetup.exe neu gebaut (50688 -> 52736 Bytes): die GUI ist in der .exe
eingebettet, ohne Rebuild wirkt der Fix beim Nutzer nicht.
Nebenbei: build-exe.ps1 hatte zwei Gedankenstriche. Ausgelieferte .ps1 muessen
reines ASCII sein (PowerShell 5.1 liest sie als ANSI) - jetzt sind alle drei
Skripte ASCII-rein und parsen fehlerfrei.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
269 lines
13 KiB
PowerShell
269 lines
13 KiB
PowerShell
# Rippy Windows-Worker - GRAFISCHER Installer (WinForms, keine externe Runtime).
|
|
# Wird ueber rippy-worker-setup.bat gestartet (Doppelklick). Braucht nur
|
|
# Python 3.10+ auf der Maschine - kein Docker, kein git.
|
|
#
|
|
# ASCII-only (PowerShell 5.1 liest .ps1 als ANSI - Sonderzeichen zerschiessen
|
|
# das Skript).
|
|
|
|
param(
|
|
[string]$RippyHost = "",
|
|
[string]$WorkerName = $env:COMPUTERNAME.ToLower()
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
Add-Type -AssemblyName System.Windows.Forms
|
|
Add-Type -AssemblyName System.Drawing
|
|
|
|
$InstallDir = Join-Path $env:USERPROFILE "rippy-worker"
|
|
|
|
# --- Fenster ---------------------------------------------------------------
|
|
$form = New-Object System.Windows.Forms.Form
|
|
$form.Text = "Rippy Encoding-Worker - Installation"
|
|
$form.Size = New-Object System.Drawing.Size(560, 520)
|
|
$form.StartPosition = "CenterScreen"
|
|
$form.FormBorderStyle = "FixedDialog"
|
|
$form.MaximizeBox = $false
|
|
$form.BackColor = [System.Drawing.Color]::FromArgb(248, 250, 252)
|
|
$form.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
|
|
|
# Fenster-Icon: Rippy-Disc zur Laufzeit zeichnen (Indigo-Kreis + weisses Loch)
|
|
# - kein externes .ico noetig. Erscheint in Titelleiste und Taskleiste.
|
|
try {
|
|
$ibmp = New-Object System.Drawing.Bitmap 32, 32
|
|
$ig = [System.Drawing.Graphics]::FromImage($ibmp)
|
|
$ig.SmoothingMode = "AntiAlias"
|
|
$ig.FillEllipse((New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(79, 70, 229))), 1, 1, 30, 30)
|
|
$ig.FillEllipse([System.Drawing.Brushes]::White, 12, 12, 8, 8)
|
|
$form.Icon = [System.Drawing.Icon]::FromHandle($ibmp.GetHicon())
|
|
} catch {}
|
|
|
|
$titel = New-Object System.Windows.Forms.Label
|
|
$titel.Text = "Rippy Encoding-Worker einrichten"
|
|
$titel.Font = New-Object System.Drawing.Font("Segoe UI", 14, [System.Drawing.FontStyle]::Bold)
|
|
$titel.ForeColor = [System.Drawing.Color]::FromArgb(79, 70, 229)
|
|
$titel.Location = New-Object System.Drawing.Point(24, 20)
|
|
$titel.Size = New-Object System.Drawing.Size(500, 30)
|
|
$form.Controls.Add($titel)
|
|
|
|
$info = New-Object System.Windows.Forms.Label
|
|
$info.Text = "Diese Maschine uebernimmt die Video-Kompression fuer Rippy. Gerippt wird weiter auf der Rippy-Hauptmaschine."
|
|
$info.Location = New-Object System.Drawing.Point(24, 52)
|
|
$info.Size = New-Object System.Drawing.Size(500, 34)
|
|
$info.ForeColor = [System.Drawing.Color]::FromArgb(100, 116, 139)
|
|
$form.Controls.Add($info)
|
|
|
|
# Rippy-Adresse
|
|
$lblHost = New-Object System.Windows.Forms.Label
|
|
$lblHost.Text = "LAN-IP der Rippy-Maschine (Docker-Host) - NICHT dieser PC:"
|
|
$lblHost.Location = New-Object System.Drawing.Point(24, 96)
|
|
$lblHost.Size = New-Object System.Drawing.Size(500, 18)
|
|
$form.Controls.Add($lblHost)
|
|
|
|
$txtHost = New-Object System.Windows.Forms.TextBox
|
|
$txtHost.Location = New-Object System.Drawing.Point(24, 116)
|
|
$txtHost.Size = New-Object System.Drawing.Size(300, 26)
|
|
$txtHost.Text = $RippyHost
|
|
$txtHost.Font = New-Object System.Drawing.Font("Consolas", 10)
|
|
$form.Controls.Add($txtHost)
|
|
|
|
# Worker-Name
|
|
$lblName = New-Object System.Windows.Forms.Label
|
|
$lblName.Text = "Name dieses Workers (frei waehlbar):"
|
|
$lblName.Location = New-Object System.Drawing.Point(24, 152)
|
|
$lblName.Size = New-Object System.Drawing.Size(500, 18)
|
|
$form.Controls.Add($lblName)
|
|
|
|
$txtName = New-Object System.Windows.Forms.TextBox
|
|
$txtName.Location = New-Object System.Drawing.Point(24, 172)
|
|
$txtName.Size = New-Object System.Drawing.Size(300, 26)
|
|
$txtName.Text = $WorkerName
|
|
$form.Controls.Add($txtName)
|
|
|
|
# Autostart
|
|
$chkAuto = New-Object System.Windows.Forms.CheckBox
|
|
$chkAuto.Text = "Beim Anmelden automatisch starten (Tray-Symbol)"
|
|
$chkAuto.Location = New-Object System.Drawing.Point(24, 206)
|
|
$chkAuto.Size = New-Object System.Drawing.Size(400, 22)
|
|
$chkAuto.Checked = $true
|
|
$form.Controls.Add($chkAuto)
|
|
|
|
# Log-Bereich
|
|
$log = New-Object System.Windows.Forms.TextBox
|
|
$log.Location = New-Object System.Drawing.Point(24, 240)
|
|
$log.Size = New-Object System.Drawing.Size(500, 170)
|
|
$log.Multiline = $true
|
|
$log.ReadOnly = $true
|
|
$log.ScrollBars = "Vertical"
|
|
$log.BackColor = [System.Drawing.Color]::FromArgb(15, 23, 42)
|
|
$log.ForeColor = [System.Drawing.Color]::FromArgb(226, 232, 240)
|
|
$log.Font = New-Object System.Drawing.Font("Consolas", 8.5)
|
|
$form.Controls.Add($log)
|
|
|
|
# Knoepfe
|
|
$btnInstall = New-Object System.Windows.Forms.Button
|
|
$btnInstall.Text = "Installieren"
|
|
$btnInstall.Location = New-Object System.Drawing.Point(24, 424)
|
|
$btnInstall.Size = New-Object System.Drawing.Size(150, 40)
|
|
$btnInstall.BackColor = [System.Drawing.Color]::FromArgb(79, 70, 229)
|
|
$btnInstall.ForeColor = [System.Drawing.Color]::White
|
|
$btnInstall.FlatStyle = "Flat"
|
|
$btnInstall.Font = New-Object System.Drawing.Font("Segoe UI", 10, [System.Drawing.FontStyle]::Bold)
|
|
$form.Controls.Add($btnInstall)
|
|
|
|
$btnStart = New-Object System.Windows.Forms.Button
|
|
$btnStart.Text = "Worker starten"
|
|
$btnStart.Location = New-Object System.Drawing.Point(190, 424)
|
|
$btnStart.Size = New-Object System.Drawing.Size(150, 40)
|
|
$btnStart.BackColor = [System.Drawing.Color]::FromArgb(16, 185, 129)
|
|
$btnStart.ForeColor = [System.Drawing.Color]::White
|
|
$btnStart.FlatStyle = "Flat"
|
|
$btnStart.Font = New-Object System.Drawing.Font("Segoe UI", 10, [System.Drawing.FontStyle]::Bold)
|
|
$btnStart.Visible = $false
|
|
$form.Controls.Add($btnStart)
|
|
|
|
function Log($text) {
|
|
$log.AppendText($text + "`r`n")
|
|
[System.Windows.Forms.Application]::DoEvents()
|
|
}
|
|
|
|
# --- Installations-Logik ---------------------------------------------------
|
|
function Do-Install {
|
|
$rHost = $txtHost.Text.Trim()
|
|
$wName = $txtName.Text.Trim()
|
|
if (-not $rHost) { [System.Windows.Forms.MessageBox]::Show("Bitte die LAN-IP der Rippy-Maschine eintragen.", "Fehlt"); return }
|
|
if (-not $wName) { $wName = $env:COMPUTERNAME.ToLower() }
|
|
|
|
$btnInstall.Enabled = $false
|
|
$log.Clear()
|
|
|
|
try {
|
|
# 1. Python finden
|
|
$python = $null
|
|
foreach ($k in @("py -3", "python")) {
|
|
try {
|
|
$v = Invoke-Expression "$k --version" 2>&1
|
|
if ("$v" -match "Python 3\.(\d+)" -and [int]$Matches[1] -ge 10) { $python = $k; break }
|
|
} catch {}
|
|
}
|
|
if (-not $python) {
|
|
Log "FEHLER: Python 3.10+ nicht gefunden."
|
|
Log "Installieren mit: winget install Python.Python.3.12"
|
|
Log "Danach diesen Installer erneut starten."
|
|
$btnInstall.Enabled = $true
|
|
return
|
|
}
|
|
Log "Python gefunden: $python"
|
|
|
|
# 2. Ordner + Worker-Code
|
|
New-Item -ItemType Directory -Force $InstallDir | Out-Null
|
|
Set-Location $InstallDir
|
|
$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") }
|
|
} catch {}
|
|
|
|
Log "Lade Worker-Code von $rHost ..."
|
|
Invoke-WebRequest "http://$rHost/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")) { Log "Lege Python-Umgebung an ..."; Invoke-Expression "$python -m venv venv" }
|
|
Log "Installiere Python-Abhaengigkeiten (kann 1-2 min dauern) ..."
|
|
& .\venv\Scripts\python.exe -m pip install --quiet --upgrade pip
|
|
& .\venv\Scripts\pip.exe install --quiet -r requirements.txt
|
|
& .\venv\Scripts\pip.exe install --quiet pystray pillow
|
|
Log "Abhaengigkeiten installiert."
|
|
|
|
# 4. HandBrakeCLI
|
|
if (-not (Test-Path ".\HandBrakeCLI.exe") -and -not (Get-Command HandBrakeCLI.exe -ErrorAction SilentlyContinue)) {
|
|
Log "Lade HandBrakeCLI $HandBrakeVersion (offizielles Release) ..."
|
|
$url = "https://github.com/HandBrake/HandBrake/releases/download/$HandBrakeVersion/HandBrakeCLI-$HandBrakeVersion-win-x86_64.zip"
|
|
Invoke-WebRequest $url -OutFile hb.zip -UseBasicParsing
|
|
Expand-Archive hb.zip -DestinationPath . -Force
|
|
Remove-Item hb.zip
|
|
}
|
|
Log "HandBrake bereit."
|
|
|
|
# 5. Start-Skripte + Deinstaller erzeugen
|
|
$trayBat = "@echo off`r`ncd /d `"%~dp0`"`r`nset REDIS_URL=redis://${rHost}:6379/0`r`nset DATABASE_URL=postgresql://rippy:rippy@${rHost}:5432/rippy`r`nset API_URL=http://${rHost}:8000`r`nset WORKER_NAME=$wName`r`nset RIPPY_TRAY_HOST=$rHost`r`nset PATH=%~dp0;%PATH%`r`nstart `"`" venv\Scripts\pythonw.exe tray.py"
|
|
Set-Content -Path "start-tray.bat" -Value $trayBat -Encoding ASCII
|
|
|
|
$workBat = "@echo off`r`ncd /d `"%~dp0`"`r`nset REDIS_URL=redis://${rHost}:6379/0`r`nset DATABASE_URL=postgresql://rippy:rippy@${rHost}:5432/rippy`r`nset API_URL=http://${rHost}:8000`r`nset WORKER_NAME=$wName`r`nset PATH=%~dp0;%PATH%`r`nvenv\Scripts\celery.exe -A celery_app worker --loglevel=info -Q transcode --pool=solo -n ${wName}@%%h"
|
|
Set-Content -Path "start-worker.bat" -Value $workBat -Encoding ASCII
|
|
|
|
$uninstall = @"
|
|
param([switch]`$Force)
|
|
if (-not `$Force) { if ([System.Windows.Forms.MessageBox]::Show("Rippy-Worker '$wName' deinstallieren?","Rippy",4) -ne "Yes") { exit } }
|
|
Add-Type -AssemblyName System.Windows.Forms
|
|
Get-CimInstance Win32_Process | Where-Object { `$_.ExecutablePath -like "`$PSScriptRoot*" } | ForEach-Object { Stop-Process -Id `$_.ProcessId -Force -ErrorAction SilentlyContinue }
|
|
Start-Sleep 2
|
|
# Autostart-Verknuepfung entfernen (neuer Weg) ...
|
|
try { Remove-Item -Force (Join-Path ([Environment]::GetFolderPath("Startup")) "RippyWorker.lnk") -ErrorAction Stop } catch {}
|
|
# ... und die geplante Aufgabe aus aelteren Installationen, falls vorhanden.
|
|
schtasks /delete /tn "RippyWorker" /f 2>`$null | Out-Null
|
|
try { Invoke-RestMethod -Method Delete "http://$rHost/api/workers/$wName" -TimeoutSec 5 | Out-Null } catch {}
|
|
Set-Location (Split-Path `$PSScriptRoot -Parent)
|
|
Remove-Item -Recurse -Force `$PSScriptRoot
|
|
[System.Windows.Forms.MessageBox]::Show("Rippy-Worker deinstalliert.","Rippy")
|
|
"@
|
|
Set-Content -Path "uninstall.ps1" -Value $uninstall -Encoding ASCII
|
|
|
|
# 6. Autostart ueber den Autostart-ORDNER, nicht ueber schtasks.
|
|
#
|
|
# Befund 25.07.2026 (auf dem Commander-PC aufgetreten): schtasks /create
|
|
# mit /tn "RippyWorker" legt die Aufgabe im WURZELORDNER der
|
|
# Aufgabenplanung an, und das verlangt Administratorrechte. Der
|
|
# Installer laeuft normal ohne. schtasks schrieb deshalb
|
|
# "FEHLER: Zugriff verweigert." nach stderr, und weil oben
|
|
# $ErrorActionPreference = "Stop" steht, wurde daraus ein Abbruch der
|
|
# GESAMTEN Installation - obwohl alles ausser dem Autostart fertig war.
|
|
# Der Nutzer sah nur "FEHLER: FEHLER: Zugriff verweigert" samt dem
|
|
# irrefuehrenden Tipp, die IP koenne falsch sein.
|
|
#
|
|
# Der Autostart-Ordner braucht NIE Adminrechte, und der Nutzer kann die
|
|
# Verknuepfung dort selbst sehen und loeschen. Zwei Fliegen.
|
|
if ($chkAuto.Checked) {
|
|
try {
|
|
$autostartOrdner = [Environment]::GetFolderPath("Startup")
|
|
$verknuepfung = Join-Path $autostartOrdner "RippyWorker.lnk"
|
|
$wsh = New-Object -ComObject WScript.Shell
|
|
$lnk = $wsh.CreateShortcut($verknuepfung)
|
|
$lnk.TargetPath = (Join-Path $InstallDir "start-tray.bat")
|
|
$lnk.WorkingDirectory = $InstallDir
|
|
$lnk.Description = "Rippy Encoding-Worker"
|
|
$lnk.Save()
|
|
Log "Autostart eingerichtet (startet bei der Anmeldung)."
|
|
} catch {
|
|
# Nur eine Warnung: der Worker selbst ist fertig und startbar.
|
|
Log "HINWEIS: Autostart konnte nicht eingerichtet werden ($($_.Exception.Message))."
|
|
Log " Der Worker ist trotzdem fertig installiert und laeuft."
|
|
Log " Von Hand: start-tray.bat in den Autostart-Ordner verknuepfen"
|
|
Log " (Windows-Taste + R, dann shell:startup eingeben)."
|
|
}
|
|
}
|
|
|
|
Log ""
|
|
Log "FERTIG! Ordner: $InstallDir"
|
|
Log "Klick 'Worker starten' - er erscheint dann in Rippy unter Einstellungen -> Worker."
|
|
$btnStart.Visible = $true
|
|
$btnInstall.Text = "Neu installieren"
|
|
$btnInstall.Enabled = $true
|
|
} catch {
|
|
Log ""
|
|
Log "FEHLER: $_"
|
|
Log "Tipp: Ist die IP korrekt und die Rippy-Maschine im Heimnetz erreichbar?"
|
|
$btnInstall.Enabled = $true
|
|
}
|
|
}
|
|
|
|
$btnInstall.Add_Click({ Do-Install })
|
|
$btnStart.Add_Click({
|
|
Start-Process -FilePath (Join-Path $InstallDir "start-tray.bat") -WindowStyle Hidden
|
|
[System.Windows.Forms.MessageBox]::Show("Worker gestartet - Symbol erscheint unten rechts neben der Uhr.", "Rippy")
|
|
$form.Close()
|
|
})
|
|
|
|
[void]$form.ShowDialog()
|