# -*- mode: python ; coding: utf-8 -*- """Cross-platform PyInstaller onedir spec for the video-enabled workstation. PyInstaller's official PySide6 QtWebEngine hooks are activated by the explicit hidden imports below. Those hooks retain QtWebEngineProcess, Chromium .pak/ ICU resources, locales, Qt plugins, and the macOS framework/helper layout. The explicit QtMultimedia imports likewise activate PyInstaller's official Qt dependency scan, which collects the QtMultimedia/QtMultimediaWidgets extension modules, Qt6Multimedia shared libraries/frameworks, multimedia plugins, and their platform media backends. """ import os import sys from pathlib import Path PROJECT_ROOT = Path(SPEC).resolve().parent.parent SOURCE_ROOT = PROJECT_ROOT / "src" ENTRY_POINT = SOURCE_ROOT / "doctor_workstation" / "__main__.py" VIDEO_DIST = PROJECT_ROOT / "video_companion" / "dist" RESOURCES = PROJECT_ROOT / "resources" ENTITLEMENTS = PROJECT_ROOT / "packaging" / "macos" / "entitlements.plist" VERSION_FILE = PROJECT_ROOT / "packaging" / "windows" / "version_info.txt" MEDIA_SMOKE_HOOK = PROJECT_ROOT / "packaging" / "runtime_media_smoke.py" if not ENTRY_POINT.is_file(): raise SystemExit(f"Application entry point is missing: {ENTRY_POINT}") if not (VIDEO_DIST / "index.html").is_file(): raise SystemExit("Build video_companion before running PyInstaller") if not MEDIA_SMOKE_HOOK.is_file(): raise SystemExit(f"Frozen multimedia smoke hook is missing: {MEDIA_SMOKE_HOOK}") # Some Windows developer tools add an unrelated OpenSSL installation to PATH. # PyInstaller's dependency scanner would then pair Python's ``_ssl.pyd`` with # those incompatible DLLs. Put the running interpreter's DLL directory first # and collect the exact same files explicitly so the build is reproducible. python_runtime_binaries = [] if sys.platform == "win32": python_dll_dir = Path(sys.base_prefix) / "DLLs" for dll_name in ("libssl-3-x64.dll", "libcrypto-3-x64.dll"): dll_path = python_dll_dir / dll_name if not dll_path.is_file(): raise SystemExit(f"Python runtime dependency is missing: {dll_path}") python_runtime_binaries.append((str(dll_path), ".")) os.environ["PATH"] = os.pathsep.join((str(python_dll_dir), os.environ.get("PATH", ""))) qt_webengine_hiddenimports = [ # Importing these modules lets PyInstaller's official Qt hooks collect the # helper executable/app, resources, locales, frameworks, and plugins. "PySide6.QtWebChannel", "PySide6.QtWebEngineCore", "PySide6.QtWebEngineWidgets", "PySide6.QtNetwork", "PySide6.QtPrintSupport", ] qt_multimedia_hiddenimports = [ # These are intentionally explicit instead of relying on imports hidden by # the application's optional media fallback. PyInstaller's official # hooks collect Qt6Multimedia*.dll/.dylib/framework, plugins/multimedia, # and the platform FFmpeg/native backend dependencies. "PySide6.QtMultimedia", "PySide6.QtMultimediaWidgets", ] analysis = Analysis( [str(ENTRY_POINT)], pathex=[str(SOURCE_ROOT)], binaries=python_runtime_binaries, datas=[ (str(VIDEO_DIST), "video_companion_dist"), (str(RESOURCES), "resources"), ], hiddenimports=qt_webengine_hiddenimports + qt_multimedia_hiddenimports, hookspath=[], hooksconfig={}, runtime_hooks=[str(MEDIA_SMOKE_HOOK)], excludes=[], noarchive=False, optimize=0, ) pyz = PYZ(analysis.pure) is_macos = sys.platform == "darwin" exe = EXE( pyz, analysis.scripts, [], exclude_binaries=True, name="DoctorWorkstation", debug=False, bootloader_ignore_signals=False, strip=False, upx=False, console=False, disable_windowed_traceback=False, argv_emulation=False, target_arch=None, codesign_identity=os.environ.get("MACOS_CODESIGN_IDENTITY") if is_macos else None, entitlements_file=str(ENTITLEMENTS) if is_macos else None, version=str(VERSION_FILE) if sys.platform == "win32" else None, ) collection = COLLECT( exe, analysis.binaries, analysis.datas, strip=False, upx=False, name="DoctorWorkstation", ) if is_macos: app = BUNDLE( collection, name="DoctorWorkstation.app", icon=None, bundle_identifier="com.zyt.doctor-workstation", info_plist={ "CFBundleDisplayName": "臻阳堂医生工作站", "NSCameraUsageDescription": "用于视频面诊时采集医生画面。", "NSMicrophoneUsageDescription": "用于视频面诊时采集医生语音。", "NSHighResolutionCapable": True, }, )