35cfcbcb07
Ampel / ampel (push) Successful in 27s
Commander-Rueckmeldung: Umlaute fehlen. Ausloeser war sichtbar der Installer -
"Diese Maschine uebernimmt die Video-Kompression fuer Rippy" stand woertlich im
Screenshot.
## Die .ps1-Falle war loesbar, nicht unumgehbar
Bisher galt: ausgelieferte .ps1 MUESSEN ASCII sein, weil PowerShell 5.1 sie
ohne BOM als ANSI liest. Das ist nur die halbe Wahrheit - gemessen mit echtem
powershell.exe 5.1:
ohne BOM: $s = "Größe: äöü" + Unerwartetes Token -> Skript kaputt
mit BOM: Groesse: aeoeue + laeuft, Length 16 korrekt
Alle drei Skripte sind jetzt UTF-8 MIT BOM und tragen echte Umlaute; unter 5.1
gegengeprueft (BOM vorhanden, Parser fehlerfrei, Text korrekt gelesen). Der
Kopfkommentar sagt das jetzt richtig statt "ASCII-only".
## Umstellung: Text ja, Bezeichner nein
Umlaute gehoeren in Kommentare und Anzeigetexte, nicht in Funktionsnamen oder
Datenschluessel. Deshalb je Sprache das passende Werkzeug:
- Python: ueber den TOKENIZER - angefasst wurden ausschliesslich COMMENT- und
STRING-Tokens. 156 Stellen. Code ist damit garantiert unberuehrt.
- TypeScript: nur // und /* */ Kommentare sowie JSX-Text (kann per Definition
kein Bezeichner sein). 24 Stellen. `const waehlen`, `let laeuft`, `plaetze`,
`GeraetInfo` sind nachweislich unversehrt.
- install.sh: Anzeigetext, aber die Shell-Funktionen (gruen/rot/gelb/titel) und
der Schalter --nur-pruefen bleiben ASCII - das sind Schnittstellen.
- Markdown: 0 Aenderungen, die Doku hatte schon Umlaute.
ZWEI FEHLER MEINES KONVERTERS, beide von Werkzeugen gefangen:
1. In f-Strings steht in {...} CODE, kein Text. Aus f"{groesse}" wurde
f"{größe}", waehrend die Variable groesse hiess - Ruff meldete F821
"Undefined name". Der Konverter lagert Einsetzungen jetzt aus.
2. Ein Dict-Schluessel wurde umbenannt: die Wortliste enthaelt das PRAEFIX
"uebersprung", der Tabu-Schutz prueft aber ganze Woerter. bericht[...] ist
wieder ASCII - Umlaute in Datenschluesseln brechen JSON-Runden und DB-Felder.
## Installer im Rippy-Look
Statt hellgrau jetzt dieselben Toene wie das Web-UI (aus lib/design.ts
uebernommen): slate-900 Flaeche, dunkle Eingabefelder, Amber-Hauptknopf wie
"Los geht's" im Wizard. Oben ein Kopfbereich mit dem Farbverlauf
amber -> indigo -> purple und dem Disc-Symbol - in WinForms per Paint-Ereignis
gezeichnet, weil es dort keine Verlaeufe von der Stange gibt.
Geprueft, nicht gehofft: Das Fenster wurde headless in ein PNG gerendert
(DrawToBitmap) und angesehen - Verlauf, Symbol, Umlaute und Farben sitzen.
RippyWorkerSetup.exe neu gebaut (57344 -> 60416 Bytes); Umlaute und das
requireAdministrator-Manifest sind in der .exe verifiziert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
212 lines
9.9 KiB
PowerShell
212 lines
9.9 KiB
PowerShell
# Rippy: Nativer Windows-Transcode-Worker - Installation OHNE Docker.
|
|
#
|
|
# Was das Skript tut (alles nach -InstallDir, Standard "C:\Program Files\Rippy Worker"):
|
|
# 1. Prüft Python (3.10+), legt ein venv an, installiert die Abhängigkeiten
|
|
# 2. Lädt den Worker-Code direkt von deiner Rippy-Instanz (/api/worker-setup/paket)
|
|
# 3. Lädt 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 hängt 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 (früher war hier
|
|
# eine feste 1.9.2 hardcodiert, was verwirrte). Fällt auf eine bekannte
|
|
# Version zurück, 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 ausführen)"
|
|
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 + Abhängigkeiten
|
|
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 für den Windows-Worker: Tray-Symbol (Status, Start/Stopp, Beenden)
|
|
& .\venv\Scripts\pip.exe install --quiet pystray pillow
|
|
Write-Host "Python-Abhängigkeiten installiert."
|
|
|
|
# 4. HandBrakeCLI besorgen (falls nötig)
|
|
$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: rückstandsfrei entfernbar
|
|
$uninstall = @"
|
|
# Rippy-Worker DEINSTALLIEREN: stoppt Prozesse, entfernt Autostart,
|
|
# meldet den Worker in Rippy ab und löscht 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-Verknüpfung entfernen - BEIDE möglichen Orte, weil die
|
|
# Installation je nach Zielverzeichnis persönlich 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 älteren 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 löschen (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)
|
|
#
|
|
# Über den Autostart-ORDNER, nicht über schtasks: Eine Aufgabe im
|
|
# Wurzelordner der Aufgabenplanung anzulegen verlangt Administratorrechte, und
|
|
# der Installer läuft 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 für die Maschine, also Autostart für
|
|
# alle Benutzer. Sonst persönlich. Siehe install-gui.ps1 für die
|
|
# ausführliche Begründung (Rechtelage bei fremdem Admin-Konto).
|
|
$programme = [Environment]::GetFolderPath("ProgramFiles")
|
|
$maschinenweit = $ziel.StartsWith($programme, "OrdinalIgnoreCase")
|
|
$autostartDir = if ($maschinenweit) {
|
|
[Environment]::GetFolderPath("CommonStartup")
|
|
} else {
|
|
[Environment]::GetFolderPath("Startup")
|
|
}
|
|
$wsh = New-Object -ComObject WScript.Shell
|
|
$lnk = $wsh.CreateShortcut((Join-Path $autostartDir "RippyWorker.lnk"))
|
|
$lnk.TargetPath = (Join-Path $ziel "start-tray.bat")
|
|
$lnk.WorkingDirectory = $ziel
|
|
$lnk.Description = "Rippy Encoding-Worker"
|
|
$lnk.Save()
|
|
Write-Host "Autostart eingerichtet (Verknüpfung 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 verknüpfen." -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'."
|