- Removed native overlay

parent d697940f
...@@ -33,10 +33,11 @@ Successfully replaced the PyQt5 video player implementation with a comprehensive ...@@ -33,10 +33,11 @@ Successfully replaced the PyQt5 video player implementation with a comprehensive
- **Responsive Design**: Automatic scaling for different resolutions - **Responsive Design**: Automatic scaling for different resolutions
- **GSAP-ready Structure**: Animation framework integration support - **GSAP-ready Structure**: Animation framework integration support
### 3. Legacy Compatibility (mbetterclient/qt_player/overlay_engine.py) ### 3. Legacy Removal (overlay_engine.py)
**UPDATED** PyQt5 → PyQt6 imports and constants for compatibility: **REMOVED** the legacy native overlay engine entirely:
- Updated Qt enums to PyQt6 format (Qt.AlignLeft → Qt.AlignmentFlag.AlignLeft) - The native Qt overlay implementation was replaced by the superior QWebEngineView system
- Maintained backward compatibility for any remaining legacy code - All overlay functionality now uses HTML/CSS/JavaScript templates exclusively
- Removed OverlayEngine and OverlayRenderer classes as they are no longer needed
### 4. Message Bus Integration ### 4. Message Bus Integration
**ENHANCED** message handling for complete thread communication: **ENHANCED** message handling for complete thread communication:
...@@ -135,7 +136,10 @@ message_bus.publish(overlay_message) ...@@ -135,7 +136,10 @@ message_bus.publish(overlay_message)
### Modified Files: ### Modified Files:
- `mbetterclient/qt_player/player.py` - **COMPLETELY REPLACED** with PyQt6 implementation - `mbetterclient/qt_player/player.py` - **COMPLETELY REPLACED** with PyQt6 implementation
- `mbetterclient/qt_player/overlay_engine.py` - Updated PyQt5 → PyQt6 imports - `mbetterclient/qt_player/__init__.py` - Removed legacy overlay engine imports
### Removed Files:
- `mbetterclient/qt_player/overlay_engine.py` - Legacy native overlay implementation removed
### Unchanged Files: ### Unchanged Files:
- `mbetterclient/core/application.py` - Works seamlessly with new implementation - `mbetterclient/core/application.py` - Works seamlessly with new implementation
......
...@@ -173,11 +173,6 @@ Examples: ...@@ -173,11 +173,6 @@ Examples:
help='Disable web dashboard (PyQt interface only)' help='Disable web dashboard (PyQt interface only)'
) )
parser.add_argument(
'--native-overlay',
action='store_true',
help='Use native Qt overlay instead of QWebEngineView (prevents freezing on some systems)'
)
# Screen cast options # Screen cast options
parser.add_argument( parser.add_argument(
...@@ -275,7 +270,6 @@ def main(): ...@@ -275,7 +270,6 @@ def main():
settings.debug_overlay = args.debug_overlay settings.debug_overlay = args.debug_overlay
settings.enable_qt = not args.no_qt settings.enable_qt = not args.no_qt
settings.enable_web = not args.no_web settings.enable_web = not args.no_web
settings.qt.use_native_overlay = args.native_overlay
# Timer settings # Timer settings
if args.start_timer is not None: if args.start_timer is not None:
......
...@@ -922,27 +922,27 @@ class APIClient(ThreadedComponent): ...@@ -922,27 +922,27 @@ class APIClient(ThreadedComponent):
self.message_bus.publish(ready_message) self.message_bus.publish(ready_message)
# Main execution loop # Main execution loop
while self.running: while self.running and not self.shutdown_event.is_set():
try: try:
# Update heartbeat at the start of each loop # Update heartbeat at the start of each loop
self.heartbeat() self.heartbeat()
# Process messages # Process messages
message = self.message_bus.get_message(self.name, timeout=1.0) message = self.message_bus.get_message(self.name, timeout=1.0)
if message: if message:
self._process_message(message) self._process_message(message)
# Update heartbeat before potentially long operations # Update heartbeat before potentially long operations
self.heartbeat() self.heartbeat()
# Execute scheduled API requests # Execute scheduled API requests
self._execute_scheduled_requests() self._execute_scheduled_requests()
# Update heartbeat after operations # Update heartbeat after operations
self.heartbeat() self.heartbeat()
time.sleep(1.0) time.sleep(1.0)
except Exception as e: except Exception as e:
logger.error(f"APIClient run loop error: {e}") logger.error(f"APIClient run loop error: {e}")
# Update heartbeat even in error cases # Update heartbeat even in error cases
......
...@@ -228,7 +228,6 @@ class QtConfig: ...@@ -228,7 +228,6 @@ class QtConfig:
overlay_enabled: bool = True overlay_enabled: bool = True
default_template: str = "news_template" default_template: str = "news_template"
overlay_opacity: float = 0.9 overlay_opacity: float = 0.9
use_native_overlay: bool = False # Use native Qt widgets instead of QWebEngineView
# Performance settings # Performance settings
hardware_acceleration: bool = True hardware_acceleration: bool = True
......
...@@ -133,8 +133,6 @@ class MbetterClientApplication: ...@@ -133,8 +133,6 @@ class MbetterClientApplication:
stored_settings.enable_web = self.settings.enable_web stored_settings.enable_web = self.settings.enable_web
stored_settings.enable_screen_cast = self.settings.enable_screen_cast # Preserve screen cast setting stored_settings.enable_screen_cast = self.settings.enable_screen_cast # Preserve screen cast setting
# Preserve command line Qt overlay setting
stored_settings.qt.use_native_overlay = self.settings.qt.use_native_overlay
# Preserve command line debug settings # Preserve command line debug settings
stored_settings.debug_overlay = self.settings.debug_overlay stored_settings.debug_overlay = self.settings.debug_overlay
......
...@@ -63,7 +63,7 @@ class MatchTimerComponent(ThreadedComponent): ...@@ -63,7 +63,7 @@ class MatchTimerComponent(ThreadedComponent):
"""Main timer loop""" """Main timer loop"""
logger.info("MatchTimer component started") logger.info("MatchTimer component started")
while self.running: while self.running and not self.shutdown_event.is_set():
try: try:
# Process any pending messages first # Process any pending messages first
message = self.message_bus.get_message(self.name, timeout=0.1) message = self.message_bus.get_message(self.name, timeout=0.1)
......
...@@ -183,21 +183,21 @@ class ScreenCastComponent(ThreadedComponent): ...@@ -183,21 +183,21 @@ class ScreenCastComponent(ThreadedComponent):
self._connect_chromecast() self._connect_chromecast()
# Main loop - monitor and restart capture if needed # Main loop - monitor and restart capture if needed
while self.running: while self.running and not self.shutdown_event.is_set():
try: try:
# Process messages # Process messages
message = self.message_bus.get_message(self.name, timeout=1.0) message = self.message_bus.get_message(self.name, timeout=1.0)
if message: if message:
self._process_message(message) self._process_message(message)
# Check capture health # Check capture health
self._check_capture_health() self._check_capture_health()
# Update heartbeat # Update heartbeat
self.heartbeat() self.heartbeat()
time.sleep(1.0) time.sleep(1.0)
except Exception as e: except Exception as e:
logger.error(f"ScreenCast run loop error: {e}") logger.error(f"ScreenCast run loop error: {e}")
time.sleep(1.0) time.sleep(1.0)
......
...@@ -233,10 +233,11 @@ class ThreadManager: ...@@ -233,10 +233,11 @@ class ThreadManager:
def stop_all(self, timeout: float = 10.0) -> bool: def stop_all(self, timeout: float = 10.0) -> bool:
"""Stop all components""" """Stop all components"""
logger.info("Stopping all components...") logger.info("Stopping all components...")
success = True success = True
stop_timeout = timeout / max(len(self.components), 1) # Distribute timeout # Use at least 8 seconds per component, but distribute total timeout
stop_timeout = max(timeout / max(len(self.components), 1), 8.0)
with self._lock: with self._lock:
for name, component in self.components.items(): for name, component in self.components.items():
try: try:
...@@ -248,12 +249,12 @@ class ThreadManager: ...@@ -248,12 +249,12 @@ class ThreadManager:
except Exception as e: except Exception as e:
logger.error(f"Exception stopping component {name}: {e}") logger.error(f"Exception stopping component {name}: {e}")
success = False success = False
if success: if success:
logger.info("All components stopped successfully") logger.info("All components stopped successfully")
else: else:
logger.warning("Some components failed to stop cleanly") logger.warning("Some components failed to stop cleanly")
return success return success
def restart_component(self, name: str, timeout: float = 5.0) -> bool: def restart_component(self, name: str, timeout: float = 5.0) -> bool:
......
...@@ -3,13 +3,10 @@ PyQt video player with overlay templates for MbetterClient ...@@ -3,13 +3,10 @@ PyQt video player with overlay templates for MbetterClient
""" """
from .player import QtVideoPlayer from .player import QtVideoPlayer
from .overlay_engine import OverlayEngine, OverlayRenderer
from .templates import TemplateManager, NewsTemplate from .templates import TemplateManager, NewsTemplate
__all__ = [ __all__ = [
'QtVideoPlayer', 'QtVideoPlayer',
'OverlayEngine',
'OverlayRenderer',
'TemplateManager', 'TemplateManager',
'NewsTemplate' 'NewsTemplate'
] ]
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
...@@ -169,18 +169,18 @@ class TemplateWatcher(ThreadedComponent): ...@@ -169,18 +169,18 @@ class TemplateWatcher(ThreadedComponent):
self._scan_existing_templates() self._scan_existing_templates()
# Message processing loop # Message processing loop
while self.running: while self.running and not self.shutdown_event.is_set():
try: try:
# Process messages # Process messages
message = self.message_bus.get_message(self.name, timeout=1.0) message = self.message_bus.get_message(self.name, timeout=1.0)
if message: if message:
self._process_message(message) self._process_message(message)
# Update heartbeat # Update heartbeat
self.heartbeat() self.heartbeat()
time.sleep(0.1) time.sleep(0.1)
except Exception as e: except Exception as e:
logger.error(f"TemplateWatcher run loop error: {e}") logger.error(f"TemplateWatcher run loop error: {e}")
time.sleep(1.0) time.sleep(1.0)
...@@ -199,14 +199,23 @@ class TemplateWatcher(ThreadedComponent): ...@@ -199,14 +199,23 @@ class TemplateWatcher(ThreadedComponent):
"""Shutdown template watcher""" """Shutdown template watcher"""
try: try:
logger.info("Shutting down TemplateWatcher...") logger.info("Shutting down TemplateWatcher...")
if self.observer: if self.observer:
# Unschedule all handlers
for handler in self.event_handlers:
try:
self.observer.unschedule(handler)
except Exception:
pass
self.event_handlers.clear()
self.observer.stop() self.observer.stop()
self.observer.join() try:
self.observer.join(timeout=2.0)
except Exception:
pass
self.observer = None self.observer = None
self.event_handler = None
except Exception as e: except Exception as e:
logger.error(f"TemplateWatcher shutdown error: {e}") logger.error(f"TemplateWatcher shutdown error: {e}")
......
...@@ -432,25 +432,25 @@ class WebDashboard(ThreadedComponent): ...@@ -432,25 +432,25 @@ class WebDashboard(ThreadedComponent):
server_thread.start() server_thread.start()
# Message processing loop # Message processing loop
while self.running: while self.running and not self.shutdown_event.is_set():
try: try:
# Process messages # Process messages
message = self.message_bus.get_message(self.name, timeout=1.0) message = self.message_bus.get_message(self.name, timeout=1.0)
if message: if message:
self._process_message(message) self._process_message(message)
# Update heartbeat # Update heartbeat
self.heartbeat() self.heartbeat()
time.sleep(0.1) time.sleep(0.1)
except Exception as e: except Exception as e:
logger.error(f"WebDashboard run loop error: {e}") logger.error(f"WebDashboard run loop error: {e}")
time.sleep(1.0) time.sleep(1.0)
# Wait for server thread # Wait for server thread to finish (with timeout since it's daemon)
if server_thread.is_alive(): if server_thread and server_thread.is_alive():
server_thread.join(timeout=5.0) server_thread.join(timeout=2.0)
except Exception as e: except Exception as e:
logger.error(f"WebDashboard run failed: {e}") logger.error(f"WebDashboard run failed: {e}")
...@@ -527,7 +527,8 @@ class WebDashboard(ThreadedComponent): ...@@ -527,7 +527,8 @@ class WebDashboard(ThreadedComponent):
if self.server: if self.server:
logger.info("Shutting down HTTP server...") logger.info("Shutting down HTTP server...")
self.server.shutdown() self.server.shutdown()
logger.info("HTTP server shutdown initiated") self.server.server_close()
logger.info("HTTP server shutdown completed")
# Note: SocketIO connections will be closed when the server shuts down # Note: SocketIO connections will be closed when the server shuts down
# No explicit SocketIO shutdown needed as it's handled by the WSGI server # No explicit SocketIO shutdown needed as it's handled by the WSGI server
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment