SimpleAppUpdater is a zero-dependency Python script that automates checking for, downloading, extracting, and launching the latest version of a portable application from GitHub (or Gitea/Forgejo-based sites like Codeberg) releases.
- Zero external dependencies — uses only Python stdlib (
urllib,zipfile,tarfile,json,re, etc.) - General-purpose — works with any portable app hosted on GitHub-style release APIs
- Auto-extraction — supports
.zip,.tar,.tar.gz,.tgz,.tar.bz2,.tar.xzarchives - Platform-aware configs — separate download URLs, file names, and executable paths per OS
- Cross-platform testing — override the detected platform via
--supdater-platformto test Windows configs on Linux and vice versa - Configurable — JSON config file named after the script; multiple defaults built in
.exe/.AppImagedetection — after extraction, automatically finds the first executable and saves its relative path for subsequent runs- Compilable — works as both a
.pyscript and a compiled binary (PyInstaller etc.)
- Python 3.x (stdlib only — no
pip installneeded)
Get the latest release at codeberg.org/marvin1099/SimpleAppUpdater/releases
or from the backup at github.com/marvin1099/SimpleAppUpdater/releases.
| File | Description |
|---|---|
app-updater.py |
Python script (runs with any Python 3.x) |
app-updater-lin-x64 |
Linux x86_64 standalone binary |
app-updater-win-x64.exe |
Windows x64 standalone binary |
On a Linux box, run the build script:
./build.sh -a # build both Linux and Windows binaries (default)
./build.sh -l # Linux only
./build.sh -w # Windows onlyBuilding for Linux needs Python and pyinstaller installed and in path. If you want to build for Windows on Linux you just need wine installed.
The first -w build auto-creates a Wine prefix, downloads the latest Python for Windows, installs PyInstaller, and compiles the Windows binary, all automatically.
On Windows, you have to build manually:
- Install Python 3.x from python.org
- Install PyInstaller:
pip install pyinstaller - Run:
pyinstaller --onefile app-updater.py --name "app-updater-win-x64"
app-updater.py [--supdater-* options] [app arguments...]
When run, the script:
- Loads its configuration from
<scriptname>.json(or custom path via--supdater-config). - If the file is missing, a default config is generated and the script exits so you can review/edit it.
- Checks the API for the latest release or pre-release.
- Downloads the new version if available (supports archive auto-extraction).
- Launches the application, passing any non-
--supdater-*arguments through.
The updater ships with several built-in configs. Use --supdater-configs to list them and --supdater-name=NAME to select one:
| Name | Platforms | Notes |
|---|---|---|
| FreeTube | Linux (.AppImage), Windows (.exe) |
|
| SatisfactoryModManager | Linux (binary) | |
| OpenRCT2 | Linux (.AppImage), Windows (.zip → portable) |
Extracts zip, saves zip_exec path |
If no --supdater-name is given, the script matches the script filename against default names (e.g., openrct2_updater.py auto-selects the OpenRCT2 config).
Arguments starting with --supdater- are consumed by the updater itself. All others are forwarded to the launched application.
| Flag | Description |
|---|---|
--supdater-help |
Show help and exit |
--supdater-version |
Show script version and exit |
--supdater-verbose |
Print platform, config, API details |
--supdater-name=NAME |
Select a default config by name (exact or substring match) |
--supdater-configs |
List all built-in default configs |
--supdater-config=PATH |
Use a custom config file path (appends .json if missing) |
--supdater-generate |
Generate the config file and exit |
--supdater-noexec |
Download/update but don't launch the app |
--supdater-platform=OS |
Override platform detection (Windows, Linux, Darwin) |
--supdater-stop |
Everything after this flag is forwarded to the app, even if it starts with --supdater- |
# Generate a config for SatisfactoryModManager if missing app_updater.json otherwise update and launch
app_updater.py --supdater-name=SatisfactoryModManager
# Generate a config for FreeTube
app_updater.py --supdater-name=FreeTube --supdater-generate
# Launch with app-specific arguments like server mode
app_updater.py --supdater-name=OpenRCT2 --headless --port=19065
# Use the OpenRCT2 config and test Windows extraction on Linux
app_updater.py --supdater-name=OpenRCT2 --supdater-platform=Windows --supdater-noexecA JSON config file is auto-generated on first run. By default it's named after the script (e.g., app_updater.json). Use --supdater-config=PATH for a custom location.
{
"name": "OpenRCT2",
"repo_api": "https://api.github.com/repos/OpenRCT2/OpenRCT2-binaries/releases",
"file_pattern": "OpenRCT2-v([0-9a-zA-Z._-]+)-windows-portable-x64\\.zip",
"app_file": "OpenRCT2.zip",
"zip_exec": "OpenRCT2/openrct2.exe",
"latest_version": "v0.5.3-2-g0b0f1336b4",
"get_releases": true,
"get_prereleases": true,
"archive_exts": [".zip", ".tar", ".tar.gz", ".tgz", ".tar.bz2", ".tar.xz"]
}| Key | Description |
|---|---|
name |
Friendly name for the app (used as the extraction directory name) |
repo_api |
GitHub (or compatible) releases API URL |
file_pattern |
Regex to match the downloadable asset name |
app_file |
Filename to save the downloaded asset |
zip_exec |
Relative path to the executable inside the extracted archive (auto-detected on first extract) |
archive_exts |
List of archive extensions that trigger auto-extraction |
latest_version |
Tracks the last downloaded version (compares against API tag_name) |
get_releases |
Include stable releases in update checks |
get_prereleases |
Include pre-releases in update checks |
missing_file |
Internal flag; triggers a re-download if the app file goes missing |
If both get_releases and get_prereleases are false, get_releases is forced to true so there is always something to download.
Some config options accept a dict keyed by platform name (Linux, Windows) instead of a plain value:
{
"file_pattern": {
"Linux": "freetube-([0-9.]+)-amd64\\.AppImage",
"Windows": "freetube-([0-9.]+)-win-x64-portable\\.exe"
},
"app_file": {
"Linux": "FreeTube.AppImage",
"Windows": "FreeTube.exe"
}
}When generating the config, the value matching your current platform (or --supdater-platform override) is selected. Unknown platforms fall back to the Linux key.
Rename the script for each app and it will use a corresponding config file:
vlc_updater.py→vlc_updater.jsonfreetube_updater.py→freetube_updater.json
Use --supdater-name=NAME to select the right built-in default for each renamed copy.
When app_file ends with one of the extensions listed in archive_exts, the downloaded file is treated as an archive and extracted automatically:
- Single top-level folder (and no root-level files): the folder is renamed to match
name(strips the archive's outer directory). - Multiple top-level entries (files + folders at root): everything is extracted directly into the
namefolder. - After extraction, the first executable is detected (
.exe/.bat/.cmdon Windows;.AppImage/.sh/.run/.binor extensionless files on Linux) and saved aszip_exec. - On subsequent runs, the cached
zip_execpath is checked first; if the file still exists, scanning is skipped.