Harden updater and add icon-based installer release pipeline
Some checks are pending
Build and Release / build (push) Waiting to run
Some checks are pending
Build and Release / build (push) Waiting to run
This commit is contained in:
parent
73ea2b9550
commit
680a5887d0
16
.github/workflows/release.yml
vendored
16
.github/workflows/release.yml
vendored
@ -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
1
.gitignore
vendored
@ -8,6 +8,7 @@ venv/
|
|||||||
|
|
||||||
build/
|
build/
|
||||||
dist/
|
dist/
|
||||||
|
release/
|
||||||
*.spec
|
*.spec
|
||||||
|
|
||||||
rd_downloader_config.json
|
rd_downloader_config.json
|
||||||
|
|||||||
@ -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
BIN
assets/app_icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 141 KiB |
BIN
assets/app_icon.png
Normal file
BIN
assets/app_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 358 KiB |
@ -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"
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
29
scripts/prepare_icon.py
Normal 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
35
scripts/set_version.py
Normal 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())
|
||||||
Loading…
Reference in New Issue
Block a user