65edf8369e
Ampel / ampel (push) Successful in 28s
Commander-Wunsch: nicht ins Benutzerprofil, sondern wie jedes andere Programm
nach C:\Program Files - und selbst waehlbar, mit diesem Standard.
## Was neu ist
- Feld "Installieren nach" mit Knopf "Aendern ..." (Ordner-Dialog). Standard
ist [Environment]::GetFolderPath("ProgramFiles") + "Rippy Worker" - der
ECHTE Pfad; deutsche Windows-Versionen zeigen im Explorer "Programme", der
Pfad heisst trotzdem "Program Files".
- Der Ordner-Dialog liefert den ELTERN-Ordner, "Rippy Worker" haengt der
Installer selbst an. Sonst koennte die Deinstallation einen fremden Ordner
mitloeschen - sie macht Remove-Item -Recurse auf das Zielverzeichnis.
- install.ps1 bekommt -InstallDir mit demselben Standard.
## Drei Folgen, die mitbehandelt werden mussten
1. RECHTE. In C:\Program Files darf nur ein Administrator schreiben. Die .exe
traegt jetzt ein requireAdministrator-Manifest (-requireAdmin in
build-exe.ps1), fragt also beim Doppelklick EINMAL per UAC - danach stimmen
die Rechte fuer alles Weitere. Verifiziert: "requireAdministrator" steckt im
Manifest, "asInvoker" nicht mehr. Zusaetzlich prueft der Installer VOR dem
Entpacken, ob er dort schreiben darf, und nennt bei Nein die zwei Wege
(als Administrator starten ODER Ziel ins eigene Profil legen) - statt
irgendwo tief "Zugriff verweigert" zu produzieren.
2. DAS LOG. tray.py schrieb worker.log NEBEN das Programm. Unter Program Files
darf ein normaler Benutzer das nicht - der Worker waere beim Starten
gescheitert, und zwar still. Das Log liegt jetzt in
%LOCALAPPDATA%\Rippy Worker\worker.log, also da, wo veraenderliche Daten
hingehoeren. Rueckfall auf das Programmverzeichnis bleibt fuer
Installationen ins eigene Profil.
3. DER AUTOSTART. Bei einer Installation unter Programme ist es eine
Installation FUER DIE MASCHINE - der Autostart geht deshalb in den
Autostart-Ordner aller Benutzer (CommonStartup). Das loest zugleich ein
Rechte-Problem: erhoeht man ueber ein FREMDES Administratorkonto, waere
GetFolderPath("Startup") der Ordner dieses Admins, also der falsche. Bei
einem Ziel im eigenen Profil bleibt es persoenlich. uninstall.ps1 raeumt
beide Orte ab.
## Geprueft
- Leerzeichen im Pfad: die erzeugte .bat mit cd /d "%~dp0", PATH-Erweiterung
und relativem Aufruf laeuft aus "C:\...\Rippy Test Ordner" korrekt durch.
- Alle drei .ps1 ASCII-rein und fehlerfrei geparst.
- RippyWorkerSetup.exe neu gebaut (52736 -> 57344 Bytes, Version 1.0.1.0).
UI: Der Copy-Paste-Befehl fuer den CLI-Weg sagt jetzt, dass PowerShell als
Administrator laufen muss, und nennt -InstallDir als Ausweg ohne Adminrechte.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
212 lines
9.7 KiB
PowerShell
212 lines
9.7 KiB
PowerShell
# Rippy: Nativer Windows-Transcode-Worker - Installation OHNE Docker.
|
|
#
|
|
# Was das Skript tut (alles nach -InstallDir, Standard "C:\Program Files\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,
|
|
# Zielverzeichnis. Standard ist "Programme", wie bei jedem anderen Programm
|
|
# (Commander-Wunsch 25.07.2026). Dorthin schreiben braucht Adminrechte -
|
|
# PowerShell also "Als Administrator" starten, oder hier einen Ordner im
|
|
# eigenen Profil angeben.
|
|
[string]$InstallDir = (Join-Path ([Environment]::GetFolderPath("ProgramFiles")) "Rippy Worker")
|
|
)
|
|
|
|
$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. Zielordner + Worker-Code von der Rippy-Instanz laden
|
|
$ziel = $InstallDir
|
|
try {
|
|
New-Item -ItemType Directory -Force $ziel -ErrorAction Stop | Out-Null
|
|
$probe = Join-Path $ziel ".schreibtest"
|
|
Set-Content -Path $probe -Value "x" -ErrorAction Stop
|
|
Remove-Item -Force $probe -ErrorAction SilentlyContinue
|
|
} catch {
|
|
Write-Host ""
|
|
Write-Host "FEHLER: In '$ziel' darf nicht geschrieben werden." -ForegroundColor Red
|
|
Write-Host "Das ist normal bei Ordnern unter 'Programme'. Zwei Wege:" -ForegroundColor Red
|
|
Write-Host " 1. PowerShell als Administrator starten und erneut aufrufen, ODER" -ForegroundColor Red
|
|
Write-Host " 2. ein eigenes Ziel angeben, z. B.:" -ForegroundColor Red
|
|
Write-Host " -InstallDir `"`$env:LOCALAPPDATA\Rippy Worker`"" -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
Write-Host "Ziel: $ziel"
|
|
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
|
|
# Autostart-Verknuepfung entfernen - BEIDE moeglichen Orte, weil die
|
|
# Installation je nach Zielverzeichnis persoenlich oder maschinenweit war.
|
|
foreach (`$ordner in @("Startup", "CommonStartup")) {
|
|
try { Remove-Item -Force (Join-Path ([Environment]::GetFolderPath(`$ordner)) "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://$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)
|
|
#
|
|
# Ueber den Autostart-ORDNER, nicht ueber schtasks: Eine Aufgabe im
|
|
# Wurzelordner der Aufgabenplanung anzulegen verlangt Administratorrechte, und
|
|
# der Installer laeuft normal ohne. Auf dem Commander-PC scheiterte das am
|
|
# 25.07.2026 mit "FEHLER: Zugriff verweigert." - und weil oben
|
|
# $ErrorActionPreference = "Stop" steht, riss es die ganze Installation mit,
|
|
# obwohl nur der Autostart fehlte. Der Autostart-Ordner braucht nie Adminrechte.
|
|
if ($Autostart) {
|
|
try {
|
|
# Unter "Programme" = Installation fuer die Maschine, also Autostart fuer
|
|
# alle Benutzer. Sonst persoenlich. Siehe install-gui.ps1 fuer die
|
|
# ausfuehrliche Begruendung (Rechtelage bei fremdem Admin-Konto).
|
|
$programme = [Environment]::GetFolderPath("ProgramFiles")
|
|
$fuerAlle = $ziel.StartsWith($programme, "OrdinalIgnoreCase")
|
|
$autostartOrdner = if ($fuerAlle) {
|
|
[Environment]::GetFolderPath("CommonStartup")
|
|
} else {
|
|
[Environment]::GetFolderPath("Startup")
|
|
}
|
|
$wsh = New-Object -ComObject WScript.Shell
|
|
$lnk = $wsh.CreateShortcut((Join-Path $autostartOrdner "RippyWorker.lnk"))
|
|
$lnk.TargetPath = (Join-Path $ziel "start-tray.bat")
|
|
$lnk.WorkingDirectory = $ziel
|
|
$lnk.Description = "Rippy Encoding-Worker"
|
|
$lnk.Save()
|
|
Write-Host "Autostart eingerichtet (Verknuepfung im Autostart-Ordner)."
|
|
} catch {
|
|
Write-Host "HINWEIS: Autostart konnte nicht eingerichtet werden ($($_.Exception.Message))." -ForegroundColor Yellow
|
|
Write-Host " Der Worker ist trotzdem fertig installiert." -ForegroundColor Yellow
|
|
Write-Host " Von Hand: start-tray.bat in shell:startup verknuepfen." -ForegroundColor Yellow
|
|
}
|
|
}
|
|
|
|
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'."
|