6438beec05
Ampel / ampel (push) Successful in 31s
Zwei Meldungen, beide auf dieselbe Wurzel zurueckgefuehrt: Der Worker startet
Konsolenprogramme, und das hat unter Windows Nebenwirkungen.
1. "Es geht immer alle paar Sekunden ne CMD auf." Kein Geist, sondern der
HERZSCHLAG. Der Worker laeuft als pythonw.exe, also ohne eigene Konsole. Wer
ohne Konsole ein Konsolenprogramm startet, bekommt von Windows eine NEUE - und
die ist sichtbar. `capture_output=True` hilft nicht: es leitet die Datenstroeme
um, unterdrueckt aber kein Fenster. Und caps.py fragt jede Minute
`HandBrakeCLI --help`, `--preset-list` und `--version` ab, dazu makemkvcon aus
der Schluessel-Automatik: vier bis fuenf Fenster pro Minute, in Schueben.
Neues winlauf.py haelt CREATE_NO_WINDOW an EINER Stelle; alle elf Aufrufe in
caps.py, ripping.py und schluessel.py benutzen es. Auf Linux ist der Wert 0 und
creationflags=0 eine Nulloperation - im Worker-Container gegengeprueft, damit
derselbe Code auf beiden Seiten laeuft.
2. Die 7200 Sekunden sind CELERYS EIGENE UMRECHNUNG, nicht die Uhren. Erst fiel
auf, dass die Sekundenbruchteile nur 40 ms auseinanderliegen (.177269 vs
.134799) - derselbe Augenblick, zweimal verschieden gerechnet. Die Quelle sagt
warum (celery/utils/time.py):
def utcoffset(): # Sekunden WEST von UTC, in Stunden
return time.altzone // 3600 # CEST -> -2 ; UTC -> 0
def adjust_timestamp(ts, offset, here=utcoffset):
return ts - (offset - here()) * 3600
Absender VM (offset 0), Empfaenger Windows-PC (here() = -2):
ts - (0 - (-2)) * 3600 = ts - 7200. Celery verschiebt den empfangenen Stempel
also selbst und vergleicht ihn dann mit der eigenen Uhr. Die Annahme dahinter -
Ereignisse truegen Ortszeit - stimmt nicht, `Event()` stempelt Epoch.
Abhilfe gemessen, nicht geraten: Mit TZ=UTC meldet Windows utcoffset 0
(timezone=0, isdst=0 - auf dem Commander-PC geprueft), damit wird die
Umrechnung zur Nulloperation. Beide .bat-Dateien setzen es jetzt. Nebeneffekt
ist erwuenscht: Der Worker rechnet dann in derselben Zone wie die VM und wie
Rippys UI.
Fuer Rippy war die Meldung ohnehin folgenlos - /capabilities fragt per
Celery-Ping (Frage/Antwort, ohne Zeitstempel), nicht ueber die
Gossip-Ereignisse. Aber eine Warnung, die bei jedem Blick ins Log steht und
nichts bedeutet, kostet Vertrauen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
356 lines
18 KiB
PowerShell
356 lines
18 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. Fragt Rippy, über welche Netzwerk-Freigabe die Rohdaten erreichbar sind,
|
||
# und prüft, ob DIESER PC sie wirklich sieht (RIPPY_PATH_MAP)
|
||
# 5. 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 <LAN-IP-der-Rippy-Maschine> [-WorkerName mein-pc] [-Autostart]
|
||
# (die IP steht in Rippy unter Einstellungen -> Worker; NICHT die dieses PCs)
|
||
#
|
||
# -Autostart legt eine Verknüpfung im Autostart-Ordner an (Start bei Anmeldung).
|
||
|
||
param(
|
||
[Parameter(Mandatory = $true)] [string]$RippyHost,
|
||
[string]$WorkerName = $env:COMPUTERNAME.ToLower(),
|
||
[switch]$Autostart,
|
||
# Verknüpfung auf dem Desktop. Standard AN (Commander-Wunsch 26.07.2026) —
|
||
# mit -KeineDesktopVerknuepfung abschaltbar.
|
||
[switch]$KeineDesktopVerknuepfung,
|
||
# Übersetzung der Rippy-Container-Pfade auf Freigaben, die DIESER PC sieht.
|
||
# Leer lassen: dann holt der Installer den Wert von Rippy selbst
|
||
# (GET /worker-setup/pfad-map, abgeleitet aus dessen eigenen Mounts).
|
||
# Von Hand nur, wenn dieser PC die Freigabe anders erreicht, z. B.
|
||
# -PfadMap "/app/media/rippy=Z:\"
|
||
[string]$PfadMap = "",
|
||
# Wie viele Kompressions-Aufträge dieser PC gleichzeitig annimmt. 0 = nach
|
||
# Kernzahl entscheiden (ab 12 Kernen zwei, sonst einer): HandBrake nutzt
|
||
# schon alle Kerne, aber x265 skaliert nicht linear — auf einer breiten CPU
|
||
# bringt ein zweiter Encode mehr Durchsatz, auf einer schmalen bremst er nur.
|
||
[int]$Slots = 0,
|
||
# 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. Netzwerk-Freigabe klären (RIPPY_PATH_MAP) - der stille Blocker bis 26.07.2026
|
||
#
|
||
# Rippy schickt dem Worker Pfade wie /app/media/rippy/<job>. Das sind Pfade
|
||
# INNERHALB des Rippy-Containers; dieser PC sieht sie nur, wenn sie auf eine
|
||
# Netzwerk-Freigabe übersetzt werden. Ohne das nimmt der Worker die Aufgabe an
|
||
# und lehnt sie Millisekunden später ab ("Keine Roh-MKVs gefunden") - gemessen
|
||
# am Job 95afdc89. Geraten wird nichts: Rippy hat die Freigabe selbst
|
||
# eingehängt und kennt ihre Quelle.
|
||
if (-not $PfadMap) {
|
||
Write-Host "Frage Rippy, über welche Freigabe die Rohdaten erreichbar sind ..."
|
||
try {
|
||
$antwort = Invoke-RestMethod "http://$RippyHost/api/worker-setup/pfad-map" -TimeoutSec 15
|
||
if ($antwort.hinweis) { Write-Host $antwort.hinweis -ForegroundColor Yellow }
|
||
if ($antwort.mapping) { $PfadMap = [string]$antwort.mapping }
|
||
} catch {
|
||
Write-Host "HINWEIS: Abfrage fehlgeschlagen ($($_.Exception.Message))." -ForegroundColor Yellow
|
||
}
|
||
}
|
||
if ($PfadMap) {
|
||
Write-Host "Freigabe: $PfadMap"
|
||
foreach ($paar in ($PfadMap -split ";")) {
|
||
if ($paar -notmatch "=") { continue }
|
||
$zielPfad = ($paar -split "=", 2)[1]
|
||
if (Test-Path -LiteralPath $zielPfad -ErrorAction SilentlyContinue) {
|
||
Write-Host " OK: $zielPfad ist von hier erreichbar." -ForegroundColor Green
|
||
} else {
|
||
Write-Host " NICHT erreichbar: $zielPfad" -ForegroundColor Yellow
|
||
Write-Host " Meist fehlen nur die Zugangsdaten: die Freigabe einmal im" -ForegroundColor Yellow
|
||
Write-Host " Explorer öffnen und 'Anmeldedaten speichern' anhaken." -ForegroundColor Yellow
|
||
}
|
||
}
|
||
} else {
|
||
Write-Host "ACHTUNG: Ohne Freigabe kann dieser Worker NICHTS komprimieren." -ForegroundColor Yellow
|
||
Write-Host " Er wird trotzdem installiert; Jobs schlagen dann mit einer" -ForegroundColor Yellow
|
||
Write-Host " Klartext-Meldung fehl statt still zu hängen." -ForegroundColor Yellow
|
||
}
|
||
# Leeres RIPPY_PATH_MAP nicht setzen: pfad_lokal() liest es als "kein Mapping",
|
||
# und die Fehlermeldung im Worker unterscheidet genau diese beiden Fälle.
|
||
$mapZeile = if ($PfadMap) { "set RIPPY_PATH_MAP=$PfadMap`r`n" } else { "" }
|
||
|
||
# Gleichzeitige Aufträge. Auf Windows gibt es KEINEN prefork-Pool (kein fork) —
|
||
# `solo` bedient genau einen Auftrag, `threads` mehrere. Das passt hier, weil die
|
||
# eigentliche Arbeit ein Kind-Prozess ist (HandBrake) und der Thread nur wartet.
|
||
if ($Slots -le 0) {
|
||
$Slots = if ([Environment]::ProcessorCount -ge 12) { 2 } else { 1 }
|
||
}
|
||
$poolArg = if ($Slots -le 1) { "--pool=solo" } else { "--pool=threads --concurrency=$Slots" }
|
||
Write-Host "Gleichzeitige Aufträge: $Slots (von $([Environment]::ProcessorCount) Kernen)"
|
||
|
||
# 6. 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 RIPPY_SLOTS=$Slots
|
||
set TZ=UTC
|
||
${mapZeile}set PATH=%~dp0;%PATH%
|
||
venv\Scripts\celery.exe -A celery_app worker --loglevel=info -Q transcode $poolArg -n ${WorkerName}@%%h
|
||
"@
|
||
Set-Content -Path "start-worker.bat" -Value $bat -Encoding ASCII
|
||
|
||
# 7. 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 RIPPY_SLOTS=$Slots
|
||
set TZ=UTC
|
||
${mapZeile}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."
|
||
|
||
# 8. 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 }
|
||
}
|
||
|
||
# ⚠️ ADMINRECHTE. Der Standard-Zielordner liegt unter "C:\Program Files", und der
|
||
# gehört nicht dem Benutzer — jedes Remove-Item darin scheitert mit "Der Zugriff
|
||
# auf den Pfad wurde verweigert" (Commander-Befund 26.07.2026). Geprüft wird per
|
||
# Schreibversuch, nicht per Annahme: Wer ins eigene Profil installiert hat,
|
||
# bekommt keine UAC-Frage.
|
||
`$schreibbar = `$false
|
||
try {
|
||
`$probe = Join-Path `$PSScriptRoot ".deinstall-probe"
|
||
Set-Content -Path `$probe -Value "x" -ErrorAction Stop
|
||
Remove-Item -Force `$probe -ErrorAction SilentlyContinue
|
||
`$schreibbar = `$true
|
||
} catch { }
|
||
`$istAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
|
||
).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||
if (-not `$schreibbar -and -not `$istAdmin) {
|
||
Write-Host "Der Ordner liegt unter 'Programme' — starte mich mit Administratorrechten neu ..." -ForegroundColor Yellow
|
||
try {
|
||
Start-Process powershell.exe -Verb RunAs -ArgumentList @(
|
||
"-NoProfile", "-ExecutionPolicy", "Bypass",
|
||
"-File", ('"' + `$PSCommandPath + '"'), "-Force")
|
||
} catch {
|
||
Write-Host "FEHLER: Erhöhung abgelehnt. PowerShell mit Rechtsklick 'Als Administrator ausführen' starten und erneut aufrufen." -ForegroundColor Red
|
||
}
|
||
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 Desktop-Verknüpfung. „Rückstandsfrei entfernbar" ist ein
|
||
# MUSS-Kriterium; ein totes Symbol auf dem Desktop wäre genau so ein Rückstand.
|
||
foreach (`$ordner in @("Desktop", "CommonDesktopDirectory")) {
|
||
try { Remove-Item -Force (Join-Path ([Environment]::GetFolderPath(`$ordner)) "Rippy Worker.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)." }
|
||
# Ordner abräumen — NICHT von hier aus: Dieses Skript liegt darin, und die
|
||
# venv-DLLs sind noch geladen. `Remove-Item -Recurse -Force` auf den eigenen
|
||
# Ordner klappt auf Windows nicht zuverlässig (Befund 26.07.2026). Ein
|
||
# losgelöstes cmd wartet, bis PowerShell weg ist, und räumt dann auf.
|
||
Set-Location `$env:TEMP
|
||
Start-Process cmd.exe -ArgumentList '/c timeout /t 4 /nobreak >nul & rd /s /q "'"`$PSScriptRoot"'"' -WindowStyle Hidden
|
||
Write-Host "Rippy-Worker deinstalliert (Ordner verschwindet in wenigen Sekunden)." -ForegroundColor Green
|
||
"@
|
||
# UTF-8 MIT BOM statt ASCII: die Datei enthält Umlaute, und PowerShell 5.1 liest
|
||
# .ps1 ohne BOM als ANSI.
|
||
[System.IO.File]::WriteAllText(
|
||
(Join-Path $ziel "uninstall.ps1"), $uninstall,
|
||
(New-Object System.Text.UTF8Encoding $true))
|
||
Write-Host "uninstall.ps1 erzeugt."
|
||
|
||
# 9. 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"
|
||
# WindowStyle 7 = minimiert: start-tray.bat startet pythonw (kein
|
||
# Konsolenfenster), aber die .bat selbst blitzt sonst kurz auf.
|
||
$lnk.WindowStyle = 7
|
||
$ico = Join-Path $ziel "rippy.ico"
|
||
if (Test-Path $ico) { $lnk.IconLocation = $ico }
|
||
$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
|
||
}
|
||
}
|
||
|
||
# 10. Verknüpfung auf dem Desktop (Commander-Wunsch 26.07.2026). Vorher lagen die
|
||
# Startdateien nur im Programmordner — wer den Worker von Hand starten wollte,
|
||
# musste erst "C:\Program Files\Rippy Worker" suchen. Ein Fehlschlag hier ist nur
|
||
# eine Warnung; der Worker läuft davon unberührt.
|
||
if (-not $KeineDesktopVerknuepfung) {
|
||
try {
|
||
$programme = [Environment]::GetFolderPath("ProgramFiles")
|
||
$maschinenweit = $ziel.StartsWith($programme, "OrdinalIgnoreCase")
|
||
$desktopDir = if ($maschinenweit) {
|
||
[Environment]::GetFolderPath("CommonDesktopDirectory")
|
||
} else {
|
||
[Environment]::GetFolderPath("Desktop")
|
||
}
|
||
$wsh = New-Object -ComObject WScript.Shell
|
||
$lnk = $wsh.CreateShortcut((Join-Path $desktopDir "Rippy Worker.lnk"))
|
||
$lnk.TargetPath = (Join-Path $ziel "start-tray.bat")
|
||
$lnk.WorkingDirectory = $ziel
|
||
$lnk.Description = "Rippy Encoding-Worker starten (Symbol neben der Uhr)"
|
||
$lnk.WindowStyle = 7
|
||
$ico = Join-Path $ziel "rippy.ico"
|
||
if (Test-Path $ico) { $lnk.IconLocation = $ico }
|
||
$lnk.Save()
|
||
Write-Host "Verknüpfung 'Rippy Worker' auf dem Desktop angelegt."
|
||
} catch {
|
||
Write-Host "HINWEIS: Desktop-Verknüpfung ging nicht ($($_.Exception.Message))." -ForegroundColor Yellow
|
||
}
|
||
}
|
||
|
||
Write-Host ""
|
||
Write-Host "FERTIG." -ForegroundColor Green
|
||
Write-Host " Auf dem Desktop: Rippy Worker"
|
||
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'."
|