# 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) $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 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 if ($chkAuto.Checked) { schtasks /create /f /tn "RippyWorker" /tr "`"$InstallDir\start-tray.bat`"" /sc onlogon | Out-Null Log "Autostart eingerichtet (Start bei Anmeldung)." } 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()