Harden updater and add icon-based installer release pipeline
Some checks are pending
Build and Release / build (push) Waiting to run

This commit is contained in:
Sucukdeluxe 2026-02-26 23:36:30 +01:00
parent 73ea2b9550
commit 680a5887d0
10 changed files with 111 additions and 28 deletions

View File

@ -25,18 +25,24 @@ jobs:
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install -r requirements.txt pip install -r requirements.txt
pip install pyinstaller pip install pyinstaller pillow
- name: Prepare release metadata
shell: pwsh
run: |
$version = "${{ github.ref_name }}".TrimStart('v')
python scripts/set_version.py $version
python scripts/prepare_icon.py
- name: Build exe - name: Build exe
run: | run: |
pyinstaller --noconfirm --onefile --windowed --name "Real-Debrid-Downloader" real_debrid_downloader_gui.py pyinstaller --noconfirm --windowed --onedir --name "Real-Debrid-Downloader" --icon "assets/app_icon.ico" real_debrid_downloader_gui.py
- name: Pack release zip - name: Pack release zip
shell: pwsh shell: pwsh
run: | run: |
New-Item -ItemType Directory -Path release -Force | Out-Null New-Item -ItemType Directory -Path release -Force | Out-Null
Copy-Item "dist/Real-Debrid-Downloader.exe" "release/Real-Debrid-Downloader.exe" Compress-Archive -Path "dist/Real-Debrid-Downloader/*" -DestinationPath "Real-Debrid-Downloader-win64.zip" -Force
Compress-Archive -Path "release/*" -DestinationPath "Real-Debrid-Downloader-win64.zip" -Force
- name: Install Inno Setup - name: Install Inno Setup
shell: pwsh shell: pwsh
@ -47,7 +53,7 @@ jobs:
shell: pwsh shell: pwsh
run: | run: |
$version = "${{ github.ref_name }}".TrimStart('v') $version = "${{ github.ref_name }}".TrimStart('v')
& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" "/DMyAppVersion=$version" "/DMySourceExe=..\\dist\\Real-Debrid-Downloader.exe" "/DMyOutputDir=..\\release" "installer\\RealDebridDownloader.iss" & "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" "/DMyAppVersion=$version" "/DMySourceDir=..\\dist\\Real-Debrid-Downloader" "/DMyOutputDir=..\\release" "/DMyIconFile=..\\assets\\app_icon.ico" "installer\\RealDebridDownloader.iss"
- name: Publish GitHub Release - name: Publish GitHub Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2

1
.gitignore vendored
View File

@ -8,6 +8,7 @@ venv/
build/ build/
dist/ dist/
release/
*.spec *.spec
rd_downloader_config.json rd_downloader_config.json

View File

@ -76,12 +76,18 @@ Danach liegt die EXE in `dist/`.
- Bei Tag-Push wie `v1.0.1` wird automatisch eine Windows-EXE gebaut - Bei Tag-Push wie `v1.0.1` wird automatisch eine Windows-EXE gebaut
- Release-Asset fuer Auto-Update: `Real-Debrid-Downloader-win64.zip` - Release-Asset fuer Auto-Update: `Real-Debrid-Downloader-win64.zip`
- Zusaetzlich wird ein Installer gebaut: `Real-Debrid-Downloader-Setup-<version>.exe` - Zusaetzlich wird ein Installer gebaut: `Real-Debrid-Downloader-Setup-<version>.exe`
- Installer legt automatisch eine Desktop-Verknuepfung an
## Auto-Installer ## Auto-Installer
- Im GitHub Release findest du direkt die Setup-Datei (`...Setup-<version>.exe`) - Im GitHub Release findest du direkt die Setup-Datei (`...Setup-<version>.exe`)
- Setup installiert die App unter `Programme/Real-Debrid Downloader` - Setup installiert die App unter `Programme/Real-Debrid Downloader`
- Optional erstellt Setup eine Desktop-Verknuepfung - Setup erstellt automatisch eine Desktop-Verknuepfung mit App-Icon
## App-Icon
- Das Projekt nutzt `assets/app_icon.png` (aus deinem `Downloads/abc.png`)
- Beim Build wird automatisch `assets/app_icon.ico` erzeugt
Beispiel: Beispiel:

BIN
assets/app_icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

BIN
assets/app_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 KiB

View File

@ -1,6 +1,16 @@
param(
[string]$Version = ""
)
python -m pip install --upgrade pip python -m pip install --upgrade pip
pip install -r requirements.txt pip install -r requirements.txt
pip install pyinstaller pip install pyinstaller pillow
pyinstaller --noconfirm --onefile --windowed --name "Real-Debrid-Downloader" real_debrid_downloader_gui.py
Write-Host "Build fertig: dist/Real-Debrid-Downloader.exe" if ($Version -ne "") {
python scripts/set_version.py $Version
}
python scripts/prepare_icon.py
pyinstaller --noconfirm --windowed --onedir --name "Real-Debrid-Downloader" --icon "assets/app_icon.ico" real_debrid_downloader_gui.py
Write-Host "Build fertig: dist/Real-Debrid-Downloader/Real-Debrid-Downloader.exe"

View File

@ -5,14 +5,18 @@
#define MyAppVersion "1.0.0" #define MyAppVersion "1.0.0"
#endif #endif
#ifndef MySourceExe #ifndef MySourceDir
#define MySourceExe "dist\\Real-Debrid-Downloader.exe" #define MySourceDir "..\\dist\\Real-Debrid-Downloader"
#endif #endif
#ifndef MyOutputDir #ifndef MyOutputDir
#define MyOutputDir "release" #define MyOutputDir "release"
#endif #endif
#ifndef MyIconFile
#define MyIconFile "..\\assets\\app_icon.ico"
#endif
[Setup] [Setup]
AppId={{C0E95B39-389E-4D2C-8E1E-12A44E8AE8E0} AppId={{C0E95B39-389E-4D2C-8E1E-12A44E8AE8E0}
AppName={#MyAppName} AppName={#MyAppName}
@ -25,23 +29,22 @@ OutputBaseFilename=Real-Debrid-Downloader-Setup-{#MyAppVersion}
Compression=lzma Compression=lzma
SolidCompression=yes SolidCompression=yes
WizardStyle=modern WizardStyle=modern
PrivilegesRequired=lowest PrivilegesRequired=admin
ArchitecturesInstallIn64BitMode=x64compatible ArchitecturesInstallIn64BitMode=x64compatible
UninstallDisplayIcon={app}\{#MyAppExeName} UninstallDisplayIcon={app}\{#MyAppExeName}
SetupIconFile={#MyIconFile}
[Languages] [Languages]
Name: "german"; MessagesFile: "compiler:Languages\German.isl" Name: "german"; MessagesFile: "compiler:Languages\German.isl"
Name: "english"; MessagesFile: "compiler:Default.isl" Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "Desktop-Verknuepfung erstellen"; GroupDescription: "Zusaetzliche Aufgaben:"; Flags: unchecked
[Files] [Files]
Source: "{#MySourceExe}"; DestDir: "{app}"; Flags: ignoreversion Source: "{#MySourceDir}\\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "{#MyIconFile}"; DestDir: "{app}"; DestName: "app_icon.ico"; Flags: ignoreversion
[Icons] [Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\app_icon.ico"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\app_icon.ico"
[Run] [Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{#MyAppName} starten"; Flags: nowait postinstall skipifsilent Filename: "{app}\{#MyAppExeName}"; Description: "{#MyAppName} starten"; Flags: nowait postinstall skipifsilent

View File

@ -29,7 +29,7 @@ API_BASE_URL = "https://api.real-debrid.com/rest/1.0"
CONFIG_FILE = Path(__file__).with_name("rd_downloader_config.json") CONFIG_FILE = Path(__file__).with_name("rd_downloader_config.json")
CHUNK_SIZE = 1024 * 512 CHUNK_SIZE = 1024 * 512
APP_NAME = "Real-Debrid Downloader GUI" APP_NAME = "Real-Debrid Downloader GUI"
APP_VERSION = "1.0.0" APP_VERSION = "1.0.5"
DEFAULT_UPDATE_REPO = "Sucukdeluxe/real-debrid-downloader" DEFAULT_UPDATE_REPO = "Sucukdeluxe/real-debrid-downloader"
DEFAULT_RELEASE_ASSET = "Real-Debrid-Downloader-win64.zip" DEFAULT_RELEASE_ASSET = "Real-Debrid-Downloader-win64.zip"
REQUEST_RETRIES = 3 REQUEST_RETRIES = 3
@ -223,19 +223,12 @@ def fetch_latest_release(session: requests.Session, repo: str, preferred_asset:
chosen = None chosen = None
for asset in assets: for asset in assets:
if asset.get("name") == preferred_asset: if str(asset.get("name", "")).strip() == preferred_asset:
chosen = asset chosen = asset
break break
if chosen is None: if chosen is None:
for asset in assets: raise RuntimeError(f"Release-Asset '{preferred_asset}' nicht gefunden")
name = str(asset.get("name", "")).lower()
if name.endswith(".zip"):
chosen = asset
break
if chosen is None:
chosen = assets[0]
return ReleaseInfo( return ReleaseInfo(
version=normalize_version(str(payload.get("tag_name", "0.0.0"))), version=normalize_version(str(payload.get("tag_name", "0.0.0"))),

29
scripts/prepare_icon.py Normal file
View File

@ -0,0 +1,29 @@
from pathlib import Path
def main() -> int:
project_root = Path(__file__).resolve().parents[1]
png_path = project_root / "assets" / "app_icon.png"
ico_path = project_root / "assets" / "app_icon.ico"
if not png_path.exists():
print(f"Icon PNG not found: {png_path}")
return 1
try:
from PIL import Image
except ImportError:
print("Pillow missing. Install with: pip install pillow")
return 1
with Image.open(png_path) as image:
image = image.convert("RGBA")
sizes = [(16, 16), (24, 24), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)]
image.save(ico_path, format="ICO", sizes=sizes)
print(f"Wrote icon: {ico_path}")
return 0
if __name__ == "__main__":
raise SystemExit(main())

35
scripts/set_version.py Normal file
View File

@ -0,0 +1,35 @@
import re
import sys
from pathlib import Path
def main() -> int:
if len(sys.argv) < 2:
print("Usage: python scripts/set_version.py <version>")
return 1
version = sys.argv[1].strip().lstrip("v")
if not re.fullmatch(r"\d+(?:\.\d+){1,3}", version):
print(f"Invalid version: {version}")
return 1
target = Path(__file__).resolve().parents[1] / "real_debrid_downloader_gui.py"
content = target.read_text(encoding="utf-8")
updated, count = re.subn(
r'^APP_VERSION\s*=\s*"[^"]+"\s*$',
f'APP_VERSION = "{version}"',
content,
count=1,
flags=re.MULTILINE,
)
if count != 1:
print("APP_VERSION marker not found")
return 1
target.write_text(updated, encoding="utf-8")
print(f"Set APP_VERSION to {version}")
return 0
if __name__ == "__main__":
raise SystemExit(main())