The exe shipped config/app_config.json AND src/player_auth.json inside the
bundle, and because a frozen app runs with cwd = _internal/, the player loaded
that snapshot as its live auth state. A stale snapshot therefore made a fresh
build boot "already authenticated" against an old server and play an outdated
playlist. It also meant every install inherited the build machine's server_ip,
screen_name and auth_code.
Both files are now excluded from the bundle (app_config.json is no longer added
to datas, player_auth.json is excluded from Tree(src)), and the runtime hook no
longer copies a config into place on first run.
New behaviour, all in src/main.py so it applies to the Pi build too:
- The player starts with blank credentials. A missing file, an empty or
unparseable file, missing keys, and leftover placeholder values
(localhost, 127.0.0.1, kivy-player, 1234567) all count as UNCONFIGURED.
config_is_configured() is the single source of truth for that decision.
- After the splash video a notice appears ("Player is not configured"), and
after 5 seconds the Settings screen opens automatically so the operator can
enter the server details.
- Saving valid values writes config/app_config.json next to the .exe and
starts playback immediately - no restart needed.
- On a machine that IS configured, the notice and Settings are skipped and the
cached playlist plays straight away.
- Settings refuses to close while the three required fields are blank, so it
cannot be dismissed into a permanently blank screen with no way back.
- The 30s playlist timer does not fight the setup flow while unconfigured.
on_intro_finished() is the single decision point after the splash; both intro
paths (video end and "no intro file") go through it so they cannot drift apart.
Also loads config over DEFAULT_CONFIG rather than replacing it, so a partial or
older config file keeps working defaults instead of losing keys.
Note for future changes: when adding a new REQUIRED config key, add it to
CONFIG_REQUIRED_KEYS or the first-run flow will not ask for it.
Verified on the packaged exe by removing the config to simulate a fresh install:
setup_required_shown -> setup_opening_settings exactly 5s later ->
setup_completed, with the config written next to the exe and playback resuming.
Restarting with that config produced no setup events at all.
Covered by windows/test_first_run_setup.py.
- Added empty playlist guard in play_current_media() to return
early instead of calling restart_playlist()
- Added empty playlist guard in restart_playlist() to return
early instead of calling play_current_media()
- Wrapped SettingsPopup content in ScrollView so fields
are not cut off on smaller screens
- Created src/edit_popup.py module for EditPopup and DrawingLayer classes
- Moved EditPopup UI definition to signage_player.kv (reduced main.py by 533 lines)
- Moved CardSwipePopup UI definition to signage_player.kv (reduced main.py by 41 lines)
- Improved code organization with better separation of concerns
- main.py reduced from 2,384 to 1,811 lines (24% reduction)
- All functionality preserved, no breaking changes
- Added checkbox in Settings screen to enable/disable edit feature
- Setting stored in app_config.json as 'edit_feature_enabled'
- Edit workflow now validates: player setting, media type, server permission, card auth
- Shows appropriate error message when edit is blocked at any validation step
- Defaults to enabled (true) if not set
- All conditions must be met for edit interface to open
- Added pencil edit button to player controls
- Created EditPopup with drawing layer for image annotation
- Drawing tools: color selection (red/blue/green/black), thickness control
- Features: undo last stroke, clear all strokes, save edited image
- Playback automatically pauses during editing
- Only images (.jpg, .jpeg, .png, .bmp) can be edited
- Edited images saved with '_edited' suffix in same directory
- Drawing layer with touch support for annotations
- Full toolbar with color, thickness, and action controls
- Added custom half-width on-screen keyboard widget (keyboard_widget.py)
- Keyboard appears at bottom center when input fields are active
- Integrated keyboard in exit popup and settings popup
- Fixed install.sh: added --break-system-packages flag for pip3
- Fixed install.sh: added fallback to online installation for version mismatches
- Removed old Kivy 2.1.0 tar.gz that was causing conflicts
- Keyboard includes close button for intuitive dismissal
- All input fields trigger keyboard on touch
- Keyboard automatically cleans up on popup dismiss
- Complete Kivy-based signage player application
- Fetches playlists from DigiServer via REST API
- Supports images (JPG, PNG, GIF, BMP) and videos (MP4, AVI, MKV, MOV, WEBM)
- Modern UI with touch controls and settings popup
- Separated UI (KV file) from business logic (Python)
- Fullscreen media display with proper scaling
- Server feedback system for player status reporting
- Auto-hide controls with mouse/touch activation
- Virtual environment setup with requirements.txt
- Installation and run scripts included
Features:
✅ Cross-platform Kivy framework
✅ Server integration with DigiServer
✅ Media playback with duration control
✅ Player feedback and status reporting
✅ Settings management with persistent config
✅ Error handling and recovery
✅ Clean architecture with KV file separation