Document how to build, package and release the player so the knowledge is not rediscovered on each machine or session. New file: .github/instructions/kiwy-build-and-development.instructions.md Contents: - Entry points: src/main.py on Linux/Pi, windows/run_win.py on Windows (which patches platform differences before running main.py). - Verified toolchain: Python 3.12.9 x64 in windows\venv, Kivy 2.3.1, PyInstaller 6.21.0. Python 3.13+/3.14 is unsupported for the Windows build because Kivy 2.3.1 has no wheels for them. - Build commands (pyinstaller build.spec, build_win.bat) and the real output path, including the note that cefpython3 is not installed in this venv, so the embedded-CEF engine is inactive and web links use the subprocess adapter. - build.spec expectations: runtime hook for DPI awareness, console=True, excludes, and the rule that lazily/dynamically imported modules must be listed in hiddenimports or the packaged exe fails with ModuleNotFoundError. - Code signing constraint: production hosts enforce Smart App Control, where an unsigned (or self-signed) exe is blocked at kernel level, so a public CA cert is required. - Verification: py_compile gate, the need to close the running player before a rebuild (output lock / "Access is denied"), the .exe reserved-device-name pitfall that makes Test-Path report a false positive without -LiteralPath, and the stale duplicate one-file exe at windows\dist\KiwySignagePlayer.exe that must not be deployed. - Release checklist and commit hygiene (do not track dist/build output or the player_auth.json credential files).
6.3 KiB
description, name
| description | name |
|---|---|
| Use when building, compiling, packaging or releasing the Kiwy Signage Player: PyInstaller build, .exe generation, build.spec, hiddenimports, code signing, Smart App Control, Windows development, Raspberry Pi deployment, or adding new modules under src/. Covers the exact build commands, environment constraints, bundling rules and verification steps. | Kiwy Build & Development |
Kiwy Signage Player — Build & Development
Cross-platform Kivy digital signage player.
- Raspberry Pi / Linux —
src/main.pyis the entry point (rootinstall.sh,start.sh). - Windows —
windows/run_win.pyis the entry point; it sets Windows env vars, importsmain.py, then monkey-patches platform differences. Packaged to.exewith PyInstaller.
Ground Rules
- Keep
src/main.pycross-platform. Windows-specific behaviour belongs inwindows/run_win.py(see_patch_main()), Pi-specific behaviour inmain.pyguarded by capability checks. Do not add Windows-only imports tomain.py. - Rebuild is mandatory. The
.exebundlessrc/, so Python edits are invisible until you rebuild. There is no hot reload in the packaged app. dist/is a runtime folder, not just build output. It holdsconfig/,media/,playlists/,logs/,.kiosk-profile/and.player_heartbeat. Never wipedist/blindly; a--cleanrebuild preserves it, but a manual delete destroys player state.
Environment
| Item | Value |
|---|---|
| Interpreter | Python 3.12.9 (64-bit) — project venv at windows\venv |
| Kivy | 2.3.1 |
| PyInstaller | 6.21.0 |
| Linux target | Python 3.13 (repo/python-wheels/, repo/system-packages/) |
- Python 3.13+/3.14 is NOT supported for the Windows build — Kivy 2.3.1 has no wheels for them.
cefpython3is not installed in the project venv. The embedded-CEF web-link engine is therefore unavailable and web links fall back to the Chrome/Edge subprocess adapter. Installingcefpython3(uncomment it inwindows/requirements_win.txt) restores the CEF engine.
Build
From windows\:
venv\Scripts\python.exe -m PyInstaller build.spec --clean --noconfirm
Or the full one-click path (creates venv, installs deps, builds, then signs):
build_win.bat
Output (folder mode, via COLLECT):
windows\dist\KiwySignagePlayer\KiwySignagePlayer.exe <- the real build output
Deployment hazard: windows\dist\KiwySignagePlayer.exe (one level up) is a stale
leftover from an older single-file build of the same name. It is not refreshed by the
current spec, so deploying it ships old code. Always take the executable from the
KiwySignagePlayer\ subfolder, and delete the stray copy if it reappears.
build.spec facts
- Entry point
run_win.py;pathex=[BUILD_DIR, SRC_DIR]sosrc/modules resolve. runtime_hooks=[pyi_runtime_hook.py]— sets per-monitor DPI awareness before SDL/Kivy initialise. Keep DPI work here; it must run before any window is created.datas += Tree(src)bundles all ofsrc/.console=Trueso startup errors and the Kivy log remain visible — do not flip this toFalsewithout a reason.hiddenimportsmust list modules that PyInstaller's static analysis cannot see: lazily imported ones (cef_browseris imported inside a function) or dynamic imports (getattr,importlib). Top-level imports such asweblink_sessionare found automatically viapathex, but listing them is harmless insurance. When you add a module undersrc/that is imported lazily or by string, add it tohiddenimportsor the packaged exe will fail at runtime withModuleNotFoundError.excluded_importsdrops Linux-only packages (evdev,gi, GStreamer) and the non-matchingcefpython3.pydvariants.
Code Signing (production constraint)
Production PCs run with Smart App Control enforced (VerifiedAndReputablePolicyState=1,
UMCI enforced) with no "Run anyway" bypass — an unsigned exe is blocked at kernel level.
- A self-signed certificate does NOT satisfy Smart App Control. A cert from a reputable
public CA is required.
create_self_signed_cert.ps1is dev-only. - Provide a cert as
KIWY_SIGN_PFX(+ optionalKIWY_SIGN_PFX_PASSWORD) or dropkiwy_signing.pfxinwindows\;build_win.batthen signs viasign_exe.ps1(signtool with RFC3161 timestamp when available). - See
documentation/CODE_SIGNING_SMART_APP_CONTROL.md.
Verify Before Committing
Fast syntax gate (no build, seconds):
python -m py_compile src/main.py src/weblink_session.py windows/run_win.py
Close the running player before rebuilding. A running
dist\KiwySignagePlayer\KiwySignagePlayer.exe locks the output and the build fails with
"Access is denied". Chrome/Edge kiosk processes left over from web-link playback can also
hold locks; if the build fails, check for stray msedge.exe / chrome.exe before retrying.
Because .exe is a reserved Windows device name as well as a real file, use
Test-Path -LiteralPath when probing for the executable, otherwise the path silently
resolves to the console device.
Development run — use this on a SAC-locked host, since the unsigned exe cannot launch:
cd windows
venv\Scripts\activate
python run_win.py
Diagnose playback transitions via the trace log (logs\playback_trace.log), written by
src/playback_trace.py.
Release Checklist
- Bump
PLAYER_VERSIONinsrc/main.pyandfilevers/prodvers/FileVersion/ProductVersioninwindows\version_info.txt; keep them in sync. - Rebuild (
build_win.bat). - Confirm the exe is signed (
Get-AuthenticodeSignature); unsigned builds are blocked on production hosts. - Smoke-test a mixed playlist: image → video → weblink → image, verifying durations, audio
(
audio: off/muted), and a clean exit/restart.
Commit Hygiene
- Never commit
windows\build\orwindows\dist\(git-ignored). Tracked build output such aswindows\archive_list.txtandwindows\build_last.txtis the exception, not the rule. - Do not commit
player_auth.jsonorsrc/player_auth.json— they contain live credentials (auth_code,player_id,server_url). These are currently tracked; treat any future change to them as a deliberate, reviewed decision. - Do not commit
config\app_config.jsonvalues that are host-specific without checking whether they belong in the repo default.