feat: PyInstaller packaging with user data separation#1019
feat: PyInstaller packaging with user data separation#1019WEIFENG2333 wants to merge 10 commits intomasterfrom
Conversation
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| for m in missing: | ||
| print(f" - {m}") | ||
| else: | ||
| print("All expected resources found in bundle.") |
There was a problem hiding this comment.
Verify function silently passes with missing critical resources
Medium Severity
The verify() function only prints a WARNING when critical bundled resources (like logo.png, fonts, translations) are missing from the build output, but does not exit with a non-zero code. Since verify() is called at the end of every build.py run (including CI), a build with missing resources will pass CI, get uploaded as an artifact, and crash at runtime when those resources are accessed.
|
|
||
| # Windows binary download URLs | ||
| FFMPEG_URL = "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-gpl.zip" | ||
| SEVENZIP_URL = "https://7-zip.org/a/7zr.exe" |
There was a problem hiding this comment.
Wrong 7-Zip variant downloaded and renamed misleadingly
Low Severity
SEVENZIP_URL points to 7zr.exe, a reduced standalone 7-Zip variant that only supports .7z archives. This binary is saved as 7z.exe, which normally refers to the full 7-Zip command-line tool supporting dozens of archive formats. While the current codebase only extracts .7z files, the renamed binary silently lacks support for other formats that 7z.exe is expected to handle.
Additional Locations (1)
| data = tomllib.load(f) | ||
| deps = data['project']['dependencies'] | ||
| subprocess.check_call([sys.executable, '-m', 'pip', 'install'] + deps) | ||
| " |
There was a problem hiding this comment.
CI ignores platform-specific PyQt5-Qt5 version pin on Windows
Medium Severity
The CI installs dependencies via pip by reading pyproject.toml's [project] dependencies, but the project's [tool.uv] override-dependencies deliberately pins PyQt5-Qt5==5.15.2 on Windows. Since pip doesn't understand uv overrides, the Windows CI build installs the latest PyQt5-Qt5 (currently 5.15.16) instead of the explicitly required 5.15.2. This means the Windows artifact bundles a different Qt binary version than what developers test with, potentially causing runtime issues.
- Add VideoCaptioner.spec with entry point videocaptioner/ui/main.py - Add scripts/build.py with ffmpeg/7z download and writable resource copy - Add .github/workflows/build.yml for Windows + macOS CI builds - Update config.py with sys.frozen detection for PyInstaller paths - Update ui/main.py with frozen-mode Qt plugin path resolution Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
48f86b0 to
19452ca
Compare
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
The 7-zip.org server sometimes resets connections on CI runners. Downloads now retry up to 3 times with backoff, and failures are warnings instead of fatal errors. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
- ass_renderer.py: Generate default_bg.png in CACHE_PATH instead of RESOURCE_PATH, which is read-only in PyInstaller frozen mode - build.py: Auto-generate videocaptioner/_version.py before building so the packaged app has the correct version number Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Without fetch-depth: 0, git describe only sees the commit hash instead of the nearest tag, resulting in version like "d9d6206" instead of "1.5.0". Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
The previous entry point (ui/main.py) only launched GUI. Using __main__.py routes through cli/main.py which supports both CLI subcommands and auto-launches GUI when no args are given. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
The full GPL build includes every codec (x265, svtav1, dav1d, etc.) but the project only needs libx264, libvpx, and libass. The gyan.dev essentials build has all of these at roughly half the size. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Move user data (settings, logs, cache, models, subtitle styles) to the system standard data directory so upgrading the program is just replacing the program folder. Program directory (replaceable): - exe + _internal/, resource/bin/, work-dir/ User data directory (persistent across upgrades): - Windows: %LOCALAPPDATA%/VideoCaptioner/ - macOS: ~/Library/Application Support/VideoCaptioner/ - Linux: ~/.local/share/VideoCaptioner/ - Contains: settings.json, logs/, cache/, models/, subtitle_style/ Also update build.py to stop copying subtitle_style to dist/ since it's now managed by config.py first-run initialization. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
Both frozen (PyInstaller) and pip install modes now use platformdirs for user data, so settings/cache/models/logs are always in the system standard directory. Only dev mode uses project-local AppData/. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
The upstream refactored subtitle styles from .txt to .json format (ass-default.json, rounded-default.json, etc.) and switched the default font to NotoSansSC-Regular.ttf. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |


Summary
Add PyInstaller packaging support adapted to the new
videocaptioner/project structure, with proper user data separation for clean upgrades.Build System
VideoCaptioner.spec— PyInstaller config, entry point__main__.py(supports both CLI and GUI)scripts/build.py— One-command build with auto version detection, ffmpeg/7z download (Windows), and bundle verification.github/workflows/build.yml— CI for Windows + macOS with smoke tests and artifact uploadsUser Data Separation
User data now lives in the system standard directory instead of the program folder, so upgrading is just replacing the program directory:
%LOCALAPPDATA%/VideoCaptioner/~/Library/Application Support/VideoCaptioner/resource/bin/work-dir/Frozen Mode Fixes
config.py— Three-mode path detection (frozen / dev / pip), unifiedplatformdirsfor frozen + pipui/main.py— Qt plugin path for_internal/PyQt5/Qt5/pluginsass_renderer.py— Write generated images toCACHE_PATHinstead of read-onlyRESOURCE_PATHbuild.py— Auto-generate_version.pyfrom git tags, retry logic for binary downloadsChanged Files (6 files, +671 lines)
.github/workflows/build.yml— New CI workflowVideoCaptioner.spec— New PyInstaller specscripts/build.py— New build scriptvideocaptioner/config.py— Rewritten with data separationvideocaptioner/core/subtitle/ass_renderer.py— Fix read-only path writevideocaptioner/ui/main.py— Frozen mode Qt plugin pathTest plan
🤖 Generated with Claude Code