feat: initial project scaffold — server, client, Android APK
- FastAPI server with audio mixer (Windows + Voicemeeter), media tracking, notifications (progress + alerts), telemetry, and system tray .exe build - Test suite covering notifications, audio mixer, media, telemetry, and API - E-Ink web client (vanilla JS, DOM API, block meters, swipe gestures) - Android WebView APK for BOOX Go 7 Color Gen II (Android 13, Kotlin) - Design decision records in .pi/docs/design/ - PyInstaller build script for server .exe
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
"""Build script: compile PaperDash server to a standalone .exe with system tray.
|
||||
|
||||
Usage:
|
||||
python build_exe.py # Build in release mode
|
||||
python build_exe.py --debug # Build in debug mode (with console)
|
||||
|
||||
Output: server/dist/PaperDash.exe
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
DIST_DIR = os.path.join(SCRIPT_DIR, "dist")
|
||||
|
||||
|
||||
def build(debug: bool = False) -> None:
|
||||
"""Compile the server to an .exe using PyInstaller."""
|
||||
os.makedirs(DIST_DIR, exist_ok=True)
|
||||
|
||||
# PyInstaller spec content — wraps the server with system tray
|
||||
spec_content = f'''
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
"""PyInstaller spec for PaperDash with system tray."""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
block_cipher = None
|
||||
|
||||
a = Analysis(
|
||||
["tray_wrapper.py"],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[
|
||||
"fastapi",
|
||||
"uvicorn",
|
||||
"pydantic",
|
||||
"pystray",
|
||||
"PIL",
|
||||
"audio_mixer",
|
||||
"media",
|
||||
"notifications",
|
||||
"telemetry",
|
||||
"main",
|
||||
],
|
||||
hookspath=[],
|
||||
hooksconfig={{}},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False,
|
||||
)
|
||||
|
||||
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name="PaperDash",
|
||||
debug={"True": True, "False": False}[str(debug)],
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False if not debug else True,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon=None,
|
||||
)
|
||||
'''
|
||||
|
||||
spec_path = os.path.join(SCRIPT_DIR, "PaperDash.spec")
|
||||
with open(spec_path, "w") as f:
|
||||
f.write(spec_content)
|
||||
|
||||
try:
|
||||
cmd = [
|
||||
sys.executable,
|
||||
"-m",
|
||||
"PyInstaller",
|
||||
spec_path,
|
||||
"--clean",
|
||||
]
|
||||
if debug:
|
||||
cmd.append("--debug=all")
|
||||
|
||||
print(f"Building PaperDash.exe (debug={debug})...")
|
||||
print(f" Spec: {spec_path}")
|
||||
print(f" Output: {DIST_DIR}/PaperDash.exe")
|
||||
print()
|
||||
|
||||
subprocess.run(cmd, check=True)
|
||||
|
||||
exe_path = os.path.join(DIST_DIR, "PaperDash.exe")
|
||||
if os.path.exists(exe_path):
|
||||
size_mb = os.path.getsize(exe_path) / (1024 * 1024)
|
||||
print(f"\nBuild complete: {exe_path} ({size_mb:.1f} MB)")
|
||||
else:
|
||||
print("\nBuild completed but .exe not found in dist/")
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"\nBuild failed: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
finally:
|
||||
# Clean up spec file
|
||||
if os.path.exists(spec_path):
|
||||
os.remove(spec_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Build PaperDash .exe")
|
||||
parser.add_argument("--debug", action="store_true", help="Build with debug console")
|
||||
args = parser.parse_args()
|
||||
build(debug=args.debug)
|
||||
Reference in New Issue
Block a user