Merge pull request #1 from fojadrachi/Preview
Release / build-windows (push) Waiting to run
Release / build-linux (push) Waiting to run
Release / publish-release (push) Blocked by required conditions

Preview
This commit is contained in:
2026-09-19 20:13:33 +02:00
committed by GitHub
4 changed files with 66 additions and 9 deletions
+40 -6
View File
@@ -98,27 +98,61 @@ begin
Result := ExpandConstant('{param:RELAUNCH|0}') = '1';
end;
procedure StopRunningPlaytube();
function PowerShellPath(): String;
begin
Result := ExpandConstant('{sys}\WindowsPowerShell\v1.0\powershell.exe');
end;
procedure WaitForOldInstance();
var
OldPid, ResultCode: Integer;
begin
{ Playtubes Updater startet Setup aus der laufenden App heraus und uebergibt deren
Prozess-ID (/WAITPID=...). Setup wartet, bis sich diese Instanz selbst beendet hat,
statt sie hart abzuschiessen (max. 20 s). Ohne Angabe (Setup per Doppelklick) passiert
hier nichts. }
OldPid := StrToIntDef(ExpandConstant('{param:WAITPID|0}'), 0);
if OldPid > 0 then
Exec(PowerShellPath(),
'-NoProfile -NonInteractive -WindowStyle Hidden -Command "Wait-Process -Id ' + IntToStr(OldPid) + ' -Timeout 20 -ErrorAction SilentlyContinue"',
'', SW_HIDE, ewWaitUntilTerminated, ResultCode);
end;
procedure StopLeftoverProcesses();
var
ResultCode: Integer;
begin
{ /T beendet auch die Kindprozesse (QtWebEngine); der Hilfsprozess wird zusaetzlich
einzeln beendet, falls er als Waise ueberlebt hat. }
Exec(ExpandConstant('{sys}\taskkill.exe'), '/F /T /IM {#AppExeName}', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
{ WICHTIG: bewusst OHNE "/T" (Prozessbaum mitbeenden). Der Updater startet Setup aus
Playtube.exe heraus - Setup ist also ein Kindprozess. Solange Playtube noch beendet
wird, wuerde "/T" den Installer selbst mit abschiessen, bevor er etwas installiert hat
(so ging frueher ein Update still verloren: kein Kopieren, kein Neustart). }
Exec(ExpandConstant('{sys}\taskkill.exe'), '/F /IM {#AppExeName}', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
Exec(ExpandConstant('{sys}\taskkill.exe'), '/F /IM {#AppHelperName}', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
{ QtWebEngine-Kindprozesse, die nach dem Ende von Playtube noch aus dem
Installationsordner laufen, wuerden Dateien sperren - gezielt nach Pfad beenden
(nicht per Namen: QtWebEngineProcess.exe heisst auch bei anderen Qt-Programmen). }
if DirExists(ExpandConstant('{app}')) then
Exec(PowerShellPath(),
'-NoProfile -NonInteractive -WindowStyle Hidden -Command "$d = ''' + ExpandConstant('{app}') + '\''; ' +
'Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -and $_.ExecutablePath.StartsWith($d, [StringComparison]::OrdinalIgnoreCase) } | ' +
'ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }"',
'', SW_HIDE, ewWaitUntilTerminated, ResultCode);
{ Dateisperren freigeben lassen, bevor kopiert wird. }
Sleep(800);
end;
function PrepareToInstall(var NeedsRestart: Boolean): String;
begin
StopRunningPlaytube();
WaitForOldInstance();
StopLeftoverProcesses();
Result := '';
end;
function InitializeUninstall(): Boolean;
begin
StopRunningPlaytube();
StopLeftoverProcesses();
Result := True;
end;
+1 -1
View File
@@ -1,4 +1,4 @@
"""Playtube - ein eigenstaendiger YouTube- & YouTube-Music-Player mit Discord Rich Presence."""
__app_name__ = "Playtube"
__version__ = "2.3.2"
__version__ = "2.4.0"
+14
View File
@@ -2,6 +2,7 @@ from __future__ import annotations
import os
import sys
import threading
from pathlib import Path
from typing import Any
@@ -28,6 +29,15 @@ from .updater import UpdateChecker, UpdateInstaller
ASSETS_DIR = Path(__file__).resolve().parent.parent / "assets"
def _force_exit_after(seconds: float) -> None:
"""Beendet den Prozess nach `seconds` hart (os._exit), falls das normale Beenden bis
dahin noch nicht durch ist. Der Timer laeuft als Daemon-Thread und stoert das
normale, schnelle Beenden nicht."""
timer = threading.Timer(seconds, os._exit, args=(0,))
timer.daemon = True
timer.start()
class MainWindow(QMainWindow):
def __init__(self, config: dict[str, Any]):
super().__init__()
@@ -359,6 +369,10 @@ class MainWindow(QMainWindow):
"Installation abgeschlossen. Playtube wird neu gestartet …"
)
self._tray.setToolTip(f"{APP_NAME} – wird neu gestartet …")
# Haengt sich Qt/QtWebEngine beim Beenden auf, wuerde der Update-Helfer (bzw.
# Setup, siehe /WAITPID) ewig auf das Ende dieses Prozesses warten - und die
# alte Version bliebe einfach weiterlaufen. Nach 8 s hart beenden.
_force_exit_after(8.0)
self._quit()
else:
QMessageBox.information(
+11 -2
View File
@@ -466,7 +466,12 @@ rm -rf "{staging}"
packaging/playtube.iss) und startet Playtube dank /RELAUNCH=1 danach neu. Die
laufende App beendet sich direkt nach diesem Aufruf (siehe MainWindow), muss
hier also nicht auf Setup warten. Setup wird abgekoppelt gestartet, damit es das
Beenden dieses Prozesses ueberlebt."""
Beenden dieses Prozesses ueberlebt.
/WAITPID=<eigene PID>: Setup wartet, bis sich diese App wirklich beendet hat,
bevor es Dateien tauscht. /LOG (ohne Pfad): Setup schreibt ein Protokoll nach
%TEMP% ("Setup Log ....txt") - so laesst sich ein fehlgeschlagenes Update
nachtraeglich nachvollziehen, obwohl die Installation selbst still laeuft."""
subprocess.Popen(
[
str(setup_path),
@@ -475,6 +480,8 @@ rm -rf "{staging}"
"/NORESTART",
"/NOCANCEL",
"/RELAUNCH=1",
f"/WAITPID={os.getpid()}",
"/LOG",
],
creationflags=subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP,
close_fds=True,
@@ -497,7 +504,9 @@ $form.Refresh()
# Ueber Start-Process (statt direktem Aufruf) gestartet und per Polling statt -Wait
# abgewartet, damit die Fensternachrichtenschleife per DoEvents() weiterlaeuft -
# sonst wuerde Windows das Fenster waehrend robocopy als "Keine Rueckmeldung" anzeigen.
$roboArgs = @("{source_dir}", "{install_dir}", "/MIR", "/NFL", "/NDL", "/NJH", "/NJS", "/NC", "/NS", "/NP")
# /R:3 /W:2 begrenzt die Wiederholungen bei gesperrten Dateien (Standard: praktisch endlos,
# das Update haengt dann sichtbar "fuer immer" im Fortschrittsfenster).
$roboArgs = @("{source_dir}", "{install_dir}", "/MIR", "/R:3", "/W:2", "/NFL", "/NDL", "/NJH", "/NJS", "/NC", "/NS", "/NP")
$roboProc = Start-Process -FilePath "robocopy" -ArgumentList $roboArgs -WindowStyle Hidden -PassThru
while (-not $roboProc.HasExited) {{
Start-Sleep -Milliseconds 200